summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2009-11-18 14:59:57 +0000
committerrdivacky <rdivacky@FreeBSD.org>2009-11-18 14:59:57 +0000
commit741c13ecc20fb35b836ad690aeecd402f002d654 (patch)
tree60a1694bec5a44d15456acc880cb2f91619f66aa /lib
parentb3a51061b1b9c4add078237850649f7c9efb13ab (diff)
downloadFreeBSD-src-741c13ecc20fb35b836ad690aeecd402f002d654.zip
FreeBSD-src-741c13ecc20fb35b836ad690aeecd402f002d654.tar.gz
Update clang to r89205.
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/ASTContext.cpp113
-rw-r--r--lib/AST/CMakeLists.txt1
-rw-r--r--lib/AST/CXXInheritance.cpp29
-rw-r--r--lib/AST/Decl.cpp6
-rw-r--r--lib/AST/DeclBase.cpp32
-rw-r--r--lib/AST/DeclCXX.cpp86
-rw-r--r--lib/AST/DeclObjC.cpp47
-rw-r--r--lib/AST/DeclPrinter.cpp54
-rw-r--r--lib/AST/DeclTemplate.cpp7
-rw-r--r--lib/AST/DeclarationName.cpp5
-rw-r--r--lib/AST/Expr.cpp19
-rw-r--r--lib/AST/ExprCXX.cpp8
-rw-r--r--lib/AST/ExprConstant.cpp29
-rw-r--r--lib/AST/NestedNameSpecifier.cpp2
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp3
-rw-r--r--lib/AST/StmtDumper.cpp7
-rw-r--r--lib/AST/StmtProfile.cpp4
-rw-r--r--lib/AST/TemplateBase.cpp14
-rw-r--r--lib/AST/Type.cpp710
-rw-r--r--lib/AST/TypePrinter.cpp728
-rw-r--r--lib/Analysis/AnalysisManager.cpp35
-rw-r--r--lib/Analysis/ArrayBoundChecker.cpp86
-rw-r--r--lib/Analysis/AttrNonNullChecker.cpp22
-rw-r--r--lib/Analysis/BadCallChecker.cpp25
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.cpp2
-rw-r--r--lib/Analysis/BasicStore.cpp19
-rw-r--r--lib/Analysis/CFRefCount.cpp585
-rw-r--r--lib/Analysis/CMakeLists.txt17
-rw-r--r--lib/Analysis/CallGraph.cpp2
-rw-r--r--lib/Analysis/CastToStructChecker.cpp77
-rw-r--r--lib/Analysis/CheckSecuritySyntaxOnly.cpp52
-rw-r--r--lib/Analysis/CheckSizeofPointer.cpp72
-rw-r--r--lib/Analysis/DereferenceChecker.cpp161
-rw-r--r--lib/Analysis/DivZeroChecker.cpp21
-rw-r--r--lib/Analysis/ExplodedGraph.cpp2
-rw-r--r--lib/Analysis/FixedAddressChecker.cpp70
-rw-r--r--lib/Analysis/GRCoreEngine.cpp49
-rw-r--r--lib/Analysis/GRExprEngine.cpp448
-rw-r--r--lib/Analysis/GRExprEngineExperimentalChecks.cpp38
-rw-r--r--lib/Analysis/GRExprEngineExperimentalChecks.h26
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.cpp115
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.h39
-rw-r--r--lib/Analysis/GRState.cpp6
-rw-r--r--lib/Analysis/LiveVariables.cpp12
-rw-r--r--lib/Analysis/MallocChecker.cpp218
-rw-r--r--lib/Analysis/ManagerRegistry.cpp (renamed from lib/Frontend/ManagerRegistry.cpp)2
-rw-r--r--lib/Analysis/MemRegion.cpp20
-rw-r--r--lib/Analysis/NSErrorChecker.cpp13
-rw-r--r--lib/Analysis/PointerArithChecker.cpp71
-rw-r--r--lib/Analysis/PointerSubChecker.cpp77
-rw-r--r--lib/Analysis/PthreadLockChecker.cpp141
-rw-r--r--lib/Analysis/RangeConstraintManager.cpp2
-rw-r--r--lib/Analysis/RegionStore.cpp25
-rw-r--r--lib/Analysis/ReturnPointerRangeChecker.cpp97
-rw-r--r--lib/Analysis/ReturnStackAddressChecker.cpp97
-rw-r--r--lib/Analysis/ReturnUndefChecker.cpp68
-rw-r--r--lib/Analysis/SVals.cpp10
-rw-r--r--lib/Analysis/SValuator.cpp3
-rw-r--r--lib/Analysis/Store.cpp22
-rw-r--r--lib/Analysis/UndefinedArgChecker.cpp29
-rw-r--r--lib/Analysis/UndefinedArraySubscriptChecker.cpp56
-rw-r--r--lib/Analysis/UndefinedAssignmentChecker.cpp5
-rw-r--r--lib/Analysis/VLASizeChecker.cpp153
-rw-r--r--lib/Basic/SourceManager.cpp4
-rw-r--r--lib/Basic/TargetInfo.cpp39
-rw-r--r--lib/Basic/Targets.cpp352
-rw-r--r--lib/Basic/Version.cpp4
-rw-r--r--lib/CodeGen/CGBlocks.cpp69
-rw-r--r--lib/CodeGen/CGBlocks.h3
-rw-r--r--lib/CodeGen/CGBuiltin.cpp21
-rw-r--r--lib/CodeGen/CGCXX.cpp631
-rw-r--r--lib/CodeGen/CGCXXClass.cpp3
-rw-r--r--lib/CodeGen/CGCXXExpr.cpp264
-rw-r--r--lib/CodeGen/CGCall.cpp13
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp265
-rw-r--r--lib/CodeGen/CGDebugInfo.h6
-rw-r--r--lib/CodeGen/CGDecl.cpp6
-rw-r--r--lib/CodeGen/CGExpr.cpp205
-rw-r--r--lib/CodeGen/CGExprAgg.cpp1
-rw-r--r--lib/CodeGen/CGExprConstant.cpp28
-rw-r--r--lib/CodeGen/CGExprScalar.cpp121
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp6
-rw-r--r--lib/CodeGen/CGObjCMac.cpp83
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp6
-rw-r--r--lib/CodeGen/CGRtti.cpp396
-rw-r--r--lib/CodeGen/CGStmt.cpp25
-rw-r--r--lib/CodeGen/CGVtable.cpp579
-rw-r--r--lib/CodeGen/CGVtable.h11
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp127
-rw-r--r--lib/CodeGen/CodeGenFunction.h57
-rw-r--r--lib/CodeGen/CodeGenModule.cpp74
-rw-r--r--lib/CodeGen/CodeGenModule.h75
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp2
-rw-r--r--lib/CodeGen/CodeGenTypes.h4
-rw-r--r--lib/CodeGen/GlobalDecl.h110
-rw-r--r--lib/CodeGen/Mangle.cpp70
-rw-r--r--lib/CodeGen/Mangle.h5
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp14
-rw-r--r--lib/CodeGen/TargetABIInfo.cpp39
-rw-r--r--lib/Driver/ToolChains.h13
-rw-r--r--lib/Driver/Tools.cpp132
-rw-r--r--lib/Driver/Types.cpp13
-rw-r--r--lib/Frontend/ASTUnit.cpp16
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp283
-rw-r--r--lib/Frontend/Backend.cpp91
-rw-r--r--lib/Frontend/CMakeLists.txt7
-rw-r--r--lib/Frontend/CompilerInstance.cpp403
-rw-r--r--lib/Frontend/CompilerInvocation.cpp548
-rw-r--r--lib/Frontend/DependencyFile.cpp44
-rw-r--r--lib/Frontend/DocumentXML.cpp4
-rw-r--r--lib/Frontend/FrontendAction.cpp225
-rw-r--r--lib/Frontend/FrontendActions.cpp281
-rw-r--r--lib/Frontend/FrontendOptions.cpp31
-rw-r--r--lib/Frontend/HTMLDiagnostics.cpp2
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp289
-rw-r--r--lib/Frontend/InitPreprocessor.cpp117
-rw-r--r--lib/Frontend/PCHReader.cpp186
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp9
-rw-r--r--lib/Frontend/PCHWriter.cpp22
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp4
-rw-r--r--lib/Frontend/PlistDiagnostics.cpp10
-rw-r--r--lib/Frontend/PrintParserCallbacks.cpp3
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp26
-rw-r--r--lib/Frontend/RewriteObjC.cpp2
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp11
-rw-r--r--lib/Frontend/VerifyDiagnosticsClient.cpp344
-rw-r--r--lib/Frontend/Warnings.cpp18
-rw-r--r--lib/Headers/stdint.h615
-rw-r--r--lib/Index/ResolveLocation.cpp14
-rw-r--r--lib/Lex/Lexer.cpp8
-rw-r--r--lib/Lex/PPCaching.cpp2
-rw-r--r--lib/Lex/PPExpressions.cpp2
-rw-r--r--lib/Lex/PTHLexer.cpp40
-rw-r--r--lib/Lex/Preprocessor.cpp24
-rw-r--r--lib/Parse/AttributeList.cpp1
-rw-r--r--lib/Parse/DeclSpec.cpp10
-rw-r--r--lib/Parse/MinimalAction.cpp7
-rw-r--r--lib/Parse/ParseDecl.cpp1
-rw-r--r--lib/Parse/ParseDeclCXX.cpp17
-rw-r--r--lib/Parse/ParseExprCXX.cpp67
-rw-r--r--lib/Parse/ParseObjc.cpp51
-rw-r--r--lib/Parse/ParseTemplate.cpp163
-rw-r--r--lib/Parse/Parser.cpp1
-rw-r--r--lib/Rewrite/DeltaTree.cpp28
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp491
-rw-r--r--lib/Sema/JumpDiagnostics.cpp2
-rw-r--r--lib/Sema/Lookup.h392
-rw-r--r--lib/Sema/ParseAST.cpp17
-rw-r--r--lib/Sema/Sema.cpp338
-rw-r--r--lib/Sema/Sema.h507
-rw-r--r--lib/Sema/SemaAttr.cpp7
-rw-r--r--lib/Sema/SemaCXXCast.cpp150
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp29
-rw-r--r--lib/Sema/SemaChecking.cpp23
-rw-r--r--lib/Sema/SemaCodeComplete.cpp554
-rw-r--r--lib/Sema/SemaDecl.cpp249
-rw-r--r--lib/Sema/SemaDeclAttr.cpp44
-rw-r--r--lib/Sema/SemaDeclCXX.cpp745
-rw-r--r--lib/Sema/SemaDeclObjC.cpp81
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp4
-rw-r--r--lib/Sema/SemaExpr.cpp374
-rw-r--r--lib/Sema/SemaExprCXX.cpp182
-rw-r--r--lib/Sema/SemaInit.cpp3
-rw-r--r--lib/Sema/SemaLookup.cpp433
-rw-r--r--lib/Sema/SemaOverload.cpp199
-rw-r--r--lib/Sema/SemaOverload.h8
-rw-r--r--lib/Sema/SemaStmt.cpp10
-rw-r--r--lib/Sema/SemaTemplate.cpp961
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp198
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp294
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp199
-rw-r--r--lib/Sema/SemaType.cpp5
-rw-r--r--lib/Sema/TreeTransform.h44
173 files changed, 13844 insertions, 5596 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 8562249..dc13e7f 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -35,7 +35,7 @@ enum FloatingRank {
};
ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
- TargetInfo &t,
+ const TargetInfo &t,
IdentifierTable &idents, SelectorTable &sels,
Builtin::Context &builtins,
bool FreeMem, unsigned size_reserve) :
@@ -256,9 +256,9 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
= new (*this) MemberSpecializationInfo(Tmpl, TSK);
}
-UnresolvedUsingDecl *
+NamedDecl *
ASTContext::getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD) {
- llvm::DenseMap<UsingDecl *, UnresolvedUsingDecl *>::iterator Pos
+ llvm::DenseMap<UsingDecl *, NamedDecl *>::const_iterator Pos
= InstantiatedFromUnresolvedUsingDecl.find(UUD);
if (Pos == InstantiatedFromUnresolvedUsingDecl.end())
return 0;
@@ -268,7 +268,10 @@ ASTContext::getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD) {
void
ASTContext::setInstantiatedFromUnresolvedUsingDecl(UsingDecl *UD,
- UnresolvedUsingDecl *UUD) {
+ NamedDecl *UUD) {
+ assert((isa<UnresolvedUsingValueDecl>(UUD) ||
+ isa<UnresolvedUsingTypenameDecl>(UUD)) &&
+ "original declaration is not an unresolved using decl");
assert(!InstantiatedFromUnresolvedUsingDecl[UD] &&
"Already noted what using decl what instantiated from");
InstantiatedFromUnresolvedUsingDecl[UD] = UUD;
@@ -1186,7 +1189,7 @@ QualType ASTContext::getNoReturnType(QualType T) {
}
}
- return getQualifiedType(ResultType, T.getQualifiers());
+ return getQualifiedType(ResultType, T.getLocalQualifiers());
}
/// getComplexType - Return the uniqued reference to the type for a complex
@@ -2350,6 +2353,12 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) {
return DTN->CanonicalTemplateName;
}
+bool ASTContext::hasSameTemplateName(TemplateName X, TemplateName Y) {
+ X = getCanonicalTemplateName(X);
+ Y = getCanonicalTemplateName(Y);
+ return X.getAsVoidPointer() == Y.getAsVoidPointer();
+}
+
TemplateArgument
ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) {
switch (Arg.getKind()) {
@@ -2357,12 +2366,14 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) {
return Arg;
case TemplateArgument::Expression:
- // FIXME: Build canonical expression?
return Arg;
case TemplateArgument::Declaration:
return TemplateArgument(Arg.getAsDecl()->getCanonicalDecl());
+ case TemplateArgument::Template:
+ return TemplateArgument(getCanonicalTemplateName(Arg.getAsTemplate()));
+
case TemplateArgument::Integral:
return TemplateArgument(*Arg.getAsIntegral(),
getCanonicalType(Arg.getIntegralType()));
@@ -2427,7 +2438,7 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) {
const ArrayType *ASTContext::getAsArrayType(QualType T) {
// Handle the non-qualified case efficiently.
- if (!T.hasQualifiers()) {
+ if (!T.hasLocalQualifiers()) {
// Handle the common positive case fast.
if (const ArrayType *AT = dyn_cast<ArrayType>(T))
return AT;
@@ -2732,12 +2743,22 @@ int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) {
return 1;
}
+static RecordDecl *
+CreateRecordDecl(ASTContext &Ctx, RecordDecl::TagKind TK, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id) {
+ if (Ctx.getLangOptions().CPlusPlus)
+ return CXXRecordDecl::Create(Ctx, TK, DC, L, Id);
+ else
+ return RecordDecl::Create(Ctx, TK, DC, L, Id);
+}
+
// getCFConstantStringType - Return the type used for constant CFStrings.
QualType ASTContext::getCFConstantStringType() {
if (!CFConstantStringTypeDecl) {
CFConstantStringTypeDecl =
- RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
- &Idents.get("NSConstantString"));
+ CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ &Idents.get("NSConstantString"));
+
QualType FieldTypes[4];
// const int *isa;
@@ -2774,8 +2795,8 @@ void ASTContext::setCFConstantStringType(QualType T) {
QualType ASTContext::getObjCFastEnumerationStateType() {
if (!ObjCFastEnumerationStateTypeDecl) {
ObjCFastEnumerationStateTypeDecl =
- RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
- &Idents.get("__objcFastEnumerationState"));
+ CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ &Idents.get("__objcFastEnumerationState"));
QualType FieldTypes[] = {
UnsignedLongTy,
@@ -2807,8 +2828,8 @@ QualType ASTContext::getBlockDescriptorType() {
RecordDecl *T;
// FIXME: Needs the FlagAppleBlock bit.
- T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
- &Idents.get("__block_descriptor"));
+ T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ &Idents.get("__block_descriptor"));
QualType FieldTypes[] = {
UnsignedLongTy,
@@ -2850,8 +2871,8 @@ QualType ASTContext::getBlockDescriptorExtendedType() {
RecordDecl *T;
// FIXME: Needs the FlagAppleBlock bit.
- T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
- &Idents.get("__block_descriptor_withcopydispose"));
+ T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ &Idents.get("__block_descriptor_withcopydispose"));
QualType FieldTypes[] = {
UnsignedLongTy,
@@ -2920,8 +2941,8 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) {
llvm::raw_svector_ostream(Name) << "__Block_byref_" <<
++UniqueBlockByRefTypeID << '_' << DeclName;
RecordDecl *T;
- T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
- &Idents.get(Name.str()));
+ T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ &Idents.get(Name.str()));
T->startDefinition();
QualType Int32Ty = IntTy;
assert(getIntWidth(IntTy) == 32 && "non-32bit int not supported");
@@ -2970,8 +2991,8 @@ QualType ASTContext::getBlockParmType(
llvm::raw_svector_ostream(Name) << "__block_literal_"
<< ++UniqueBlockParmTypeID;
RecordDecl *T;
- T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
- &Idents.get(Name.str()));
+ T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ &Idents.get(Name.str()));
QualType FieldTypes[] = {
getPointerType(VoidPtrTy),
IntTy,
@@ -3053,6 +3074,54 @@ int ASTContext::getObjCEncodingTypeSize(QualType type) {
return sz / getTypeSize(CharTy);
}
+/// getObjCEncodingForBlockDecl - Return the encoded type for this method
+/// declaration.
+void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
+ std::string& S) {
+ const BlockDecl *Decl = Expr->getBlockDecl();
+ QualType BlockTy =
+ Expr->getType()->getAs<BlockPointerType>()->getPointeeType();
+ // Encode result type.
+ getObjCEncodingForType(cast<FunctionType>(BlockTy)->getResultType(), S);
+ // Compute size of all parameters.
+ // Start with computing size of a pointer in number of bytes.
+ // FIXME: There might(should) be a better way of doing this computation!
+ SourceLocation Loc;
+ int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy);
+ int ParmOffset = PtrSize;
+ for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
+ E = Decl->param_end(); PI != E; ++PI) {
+ QualType PType = (*PI)->getType();
+ int sz = getObjCEncodingTypeSize(PType);
+ assert (sz > 0 && "BlockExpr - Incomplete param type");
+ ParmOffset += sz;
+ }
+ // Size of the argument frame
+ S += llvm::utostr(ParmOffset);
+ // Block pointer and offset.
+ S += "@?0";
+ ParmOffset = PtrSize;
+
+ // Argument types.
+ ParmOffset = PtrSize;
+ for (BlockDecl::param_const_iterator PI = Decl->param_begin(), E =
+ Decl->param_end(); PI != E; ++PI) {
+ ParmVarDecl *PVDecl = *PI;
+ QualType PType = PVDecl->getOriginalType();
+ if (const ArrayType *AT =
+ dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) {
+ // Use array's original type only if it has known number of
+ // elements.
+ if (!isa<ConstantArrayType>(AT))
+ PType = PVDecl->getType();
+ } else if (PType->isFunctionType())
+ PType = PVDecl->getType();
+ getObjCEncodingForType(PType, S);
+ S += llvm::utostr(ParmOffset);
+ ParmOffset += getObjCEncodingTypeSize(PType);
+ }
+}
+
/// getObjCEncodingForMethodDecl - Return the encoded type for this method
/// declaration.
void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
@@ -4186,8 +4255,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
return LHS;
// If the qualifiers are different, the types aren't compatible... mostly.
- Qualifiers LQuals = LHSCan.getQualifiers();
- Qualifiers RQuals = RHSCan.getQualifiers();
+ Qualifiers LQuals = LHSCan.getLocalQualifiers();
+ Qualifiers RQuals = RHSCan.getLocalQualifiers();
if (LQuals != RQuals) {
// If any of these qualifiers are different, we have a type
// mismatch.
@@ -4394,7 +4463,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
//===----------------------------------------------------------------------===//
unsigned ASTContext::getIntWidth(QualType T) {
- if (T == BoolTy)
+ if (T->isBooleanType())
return 1;
if (FixedWidthIntType *FWIT = dyn_cast<FixedWidthIntType>(T)) {
return FWIT->getWidth();
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index e541406..0f0b22d 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -30,6 +30,7 @@ add_clang_library(clangAST
TemplateName.cpp
Type.cpp
TypeLoc.cpp
+ TypePrinter.cpp
)
add_dependencies(clangAST ClangDiagnosticAST)
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index b59b45f..023bca4 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -76,31 +76,31 @@ void CXXBasePaths::swap(CXXBasePaths &Other) {
std::swap(DetectedVirtual, Other.DetectedVirtual);
}
-bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base) {
+bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base) const {
CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false,
/*DetectVirtual=*/false);
return isDerivedFrom(Base, Paths);
}
-bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) {
+bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) const {
if (getCanonicalDecl() == Base->getCanonicalDecl())
return false;
- Paths.setOrigin(this);
+ Paths.setOrigin(const_cast<CXXRecordDecl*>(this));
return lookupInBases(&FindBaseClass, Base->getCanonicalDecl(), Paths);
}
bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
void *UserData,
- CXXBasePaths &Paths) {
+ CXXBasePaths &Paths) const {
bool FoundPath = false;
ASTContext &Context = getASTContext();
- for (base_class_iterator BaseSpec = bases_begin(), BaseSpecEnd = bases_end();
- BaseSpec != BaseSpecEnd; ++BaseSpec) {
+ for (base_class_const_iterator BaseSpec = bases_begin(),
+ BaseSpecEnd = bases_end(); BaseSpec != BaseSpecEnd; ++BaseSpec) {
// Find the record of the base class subobjects for this type.
- QualType BaseType = Context.getCanonicalType(BaseSpec->getType());
- BaseType = BaseType.getUnqualifiedType();
+ QualType BaseType = Context.getCanonicalType(BaseSpec->getType())
+ .getUnqualifiedType();
// C++ [temp.dep]p3:
// In the definition of a class template or a member of a class template,
@@ -183,7 +183,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
return FoundPath;
}
-bool CXXRecordDecl::FindBaseClass(CXXBaseSpecifier *Specifier,
+bool CXXRecordDecl::FindBaseClass(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *BaseRecord) {
assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord &&
@@ -192,7 +192,7 @@ bool CXXRecordDecl::FindBaseClass(CXXBaseSpecifier *Specifier,
->getCanonicalDecl() == BaseRecord;
}
-bool CXXRecordDecl::FindTagMember(CXXBaseSpecifier *Specifier,
+bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *Name) {
RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
@@ -208,7 +208,7 @@ bool CXXRecordDecl::FindTagMember(CXXBaseSpecifier *Specifier,
return false;
}
-bool CXXRecordDecl::FindOrdinaryMember(CXXBaseSpecifier *Specifier,
+bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *Name) {
RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
@@ -225,9 +225,10 @@ bool CXXRecordDecl::FindOrdinaryMember(CXXBaseSpecifier *Specifier,
return false;
}
-bool CXXRecordDecl::FindNestedNameSpecifierMember(CXXBaseSpecifier *Specifier,
- CXXBasePath &Path,
- void *Name) {
+bool CXXRecordDecl::
+FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path,
+ void *Name) {
RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index a6996a4..bdc8047 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -289,6 +289,10 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
if (isa<ObjCInterfaceDecl>(this) && isa<ObjCCompatibleAliasDecl>(OldD))
return true;
+ if (isa<UsingShadowDecl>(this) && isa<UsingShadowDecl>(OldD))
+ return cast<UsingShadowDecl>(this)->getTargetDecl() ==
+ cast<UsingShadowDecl>(OldD)->getTargetDecl();
+
// For non-function declarations, if the declarations are of the
// same kind then this must be a redeclaration, or semantic analysis
// would not have given us the new declaration.
@@ -308,7 +312,7 @@ bool NamedDecl::hasLinkage() const {
NamedDecl *NamedDecl::getUnderlyingDecl() {
NamedDecl *ND = this;
while (true) {
- if (UsingDecl *UD = dyn_cast<UsingDecl>(ND))
+ if (UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(ND))
ND = UD->getTargetDecl();
else if (ObjCCompatibleAliasDecl *AD
= dyn_cast<ObjCCompatibleAliasDecl>(ND))
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 6cfdcdd..831f552 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -97,7 +97,7 @@ bool Decl::isTemplateParameterPack() const {
}
bool Decl::isFunctionOrFunctionTemplate() const {
- if (const UsingDecl *UD = dyn_cast<UsingDecl>(this))
+ if (const UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(this))
return UD->getTargetDecl()->isFunctionOrFunctionTemplate();
return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this);
@@ -189,10 +189,11 @@ ASTContext &Decl::getASTContext() const {
unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
switch (DeclKind) {
- default:
- if (DeclKind >= FunctionFirst && DeclKind <= FunctionLast)
- return IDNS_Ordinary;
- assert(0 && "Unknown decl kind!");
+ case Function:
+ case CXXMethod:
+ case CXXConstructor:
+ case CXXDestructor:
+ case CXXConversion:
case OverloadedFunction:
case Typedef:
case EnumConstant:
@@ -200,8 +201,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ImplicitParam:
case ParmVar:
case NonTypeTemplateParm:
- case Using:
- case UnresolvedUsing:
case ObjCMethod:
case ObjCContainer:
case ObjCCategory:
@@ -210,6 +209,16 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCCompatibleAlias:
return IDNS_Ordinary;
+ case UsingShadow:
+ return 0; // we'll actually overwrite this later
+
+ case UnresolvedUsingValue:
+ case UnresolvedUsingTypename:
+ return IDNS_Ordinary | IDNS_Using;
+
+ case Using:
+ return IDNS_Using;
+
case ObjCProtocol:
return IDNS_ObjCProtocol;
@@ -256,6 +265,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ClassTemplatePartialSpecialization:
return 0;
}
+
+ return 0;
}
void Decl::addAttr(Attr *NewAttr) {
@@ -663,6 +674,13 @@ void DeclContext::buildLookup(DeclContext *DCtx) {
if (D->getDeclContext() == DCtx)
makeDeclVisibleInContextImpl(ND);
+ // Insert any forward-declared Objective-C interfaces into the lookup
+ // data structure.
+ if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D))
+ for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end();
+ I != IEnd; ++I)
+ makeDeclVisibleInContextImpl(I->getInterface());
+
// If this declaration is itself a transparent declaration context,
// add its members (recursively).
if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D))
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index b4c0c59..a21c93f 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -211,7 +211,7 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context,
if (!ArgType.isConstQualified())
AcceptsConst = false;
}
- if (Context.getCanonicalType(ArgType).getUnqualifiedType() != ClassType)
+ if (!Context.hasSameUnqualifiedType(ArgType, ClassType))
continue;
MD = Method;
// We have a single argument of type cv X or cv X&, i.e. we've found the
@@ -276,10 +276,13 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
const_cast<CXXRecordDecl*>(this)));
- if (ClassType != Context.getCanonicalType(ArgType))
+ if (!Context.hasSameUnqualifiedType(ClassType, ArgType))
return;
// This is a copy assignment operator.
+ // Note on the decl that it is a copy assignment operator.
+ OpDecl->setCopyAssignment(true);
+
// Suppress the implicit declaration of a copy constructor.
UserDeclaredCopyAssignment = true;
@@ -749,6 +752,33 @@ bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const {
(getNumParams() > 1 && getParamDecl(1)->hasDefaultArg());
}
+bool CXXConstructorDecl::isCopyConstructorLikeSpecialization() const {
+ if ((getNumParams() < 1) ||
+ (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) ||
+ (getPrimaryTemplate() == 0) ||
+ (getDescribedFunctionTemplate() != 0))
+ return false;
+
+ const ParmVarDecl *Param = getParamDecl(0);
+
+ ASTContext &Context = getASTContext();
+ CanQualType ParamType = Context.getCanonicalType(Param->getType());
+
+ // Strip off the lvalue reference, if any.
+ if (CanQual<LValueReferenceType> ParamRefType
+ = ParamType->getAs<LValueReferenceType>())
+ ParamType = ParamRefType->getPointeeType();
+
+
+ // Is it the same as our our class type?
+ CanQualType ClassTy
+ = Context.getCanonicalType(Context.getTagDeclType(getParent()));
+ if (ParamType.getUnqualifiedType() != ClassTy)
+ return false;
+
+ return true;
+}
+
CXXDestructorDecl *
CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
@@ -761,12 +791,6 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
}
void
-CXXDestructorDecl::Destroy(ASTContext& C) {
- C.Deallocate(BaseOrMemberDestructions);
- CXXMethodDecl::Destroy(C);
-}
-
-void
CXXConstructorDecl::Destroy(ASTContext& C) {
C.Deallocate(BaseOrMemberInitializers);
CXXMethodDecl::Destroy(C);
@@ -890,22 +914,36 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
}
UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, SourceRange NNR, SourceLocation TargetNL,
- SourceLocation UL, NamedDecl* Target,
- NestedNameSpecifier* TargetNNS, bool IsTypeNameArg) {
- return new (C) UsingDecl(DC, L, NNR, TargetNL, UL, Target,
- TargetNNS, IsTypeNameArg);
-}
-
-UnresolvedUsingDecl *UnresolvedUsingDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation UsingLoc,
- SourceRange TargetNNR,
- NestedNameSpecifier *TargetNNS,
- SourceLocation TargetNameLoc,
- DeclarationName TargetName,
- bool IsTypeNameArg) {
- return new (C) UnresolvedUsingDecl(DC, UsingLoc, TargetNNR, TargetNNS,
- TargetNameLoc, TargetName, IsTypeNameArg);
+ SourceLocation L, SourceRange NNR, SourceLocation UL,
+ NestedNameSpecifier* TargetNNS, DeclarationName Name,
+ bool IsTypeNameArg) {
+ return new (C) UsingDecl(DC, L, NNR, UL, TargetNNS, Name, IsTypeNameArg);
+}
+
+UnresolvedUsingValueDecl *
+UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation UsingLoc,
+ SourceRange TargetNNR,
+ NestedNameSpecifier *TargetNNS,
+ SourceLocation TargetNameLoc,
+ DeclarationName TargetName) {
+ return new (C) UnresolvedUsingValueDecl(DC, C.DependentTy, UsingLoc,
+ TargetNNR, TargetNNS,
+ TargetNameLoc, TargetName);
+}
+
+UnresolvedUsingTypenameDecl *
+UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation UsingLoc,
+ SourceLocation TypenameLoc,
+ SourceRange TargetNNR,
+ NestedNameSpecifier *TargetNNS,
+ SourceLocation TargetNameLoc,
+ DeclarationName TargetName) {
+ return new (C) UnresolvedUsingTypenameDecl(DC, UsingLoc, TypenameLoc,
+ TargetNNR, TargetNNS,
+ TargetNameLoc,
+ TargetName.getAsIdentifierInfo());
}
StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC,
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 7b48b72..c33720f 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -571,34 +571,55 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel,
//===----------------------------------------------------------------------===//
ObjCClassDecl::ObjCClassDecl(DeclContext *DC, SourceLocation L,
- ObjCInterfaceDecl *const *Elts, unsigned nElts,
+ ObjCInterfaceDecl *const *Elts,
+ const SourceLocation *Locs,
+ unsigned nElts,
ASTContext &C)
: Decl(ObjCClass, DC, L) {
- ForwardDecls.set(Elts, nElts, C);
+ setClassList(C, Elts, Locs, nElts);
}
+void ObjCClassDecl::setClassList(ASTContext &C, ObjCInterfaceDecl*const*List,
+ const SourceLocation *Locs, unsigned Num) {
+ ForwardDecls = (ObjCClassRef*) C.Allocate(sizeof(ObjCClassRef)*Num,
+ llvm::alignof<ObjCClassRef>());
+ for (unsigned i = 0; i < Num; ++i)
+ new (&ForwardDecls[i]) ObjCClassRef(List[i], Locs[i]);
+
+ NumDecls = Num;
+}
ObjCClassDecl *ObjCClassDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
ObjCInterfaceDecl *const *Elts,
+ const SourceLocation *Locs,
unsigned nElts) {
- return new (C) ObjCClassDecl(DC, L, Elts, nElts, C);
+ return new (C) ObjCClassDecl(DC, L, Elts, Locs, nElts, C);
}
void ObjCClassDecl::Destroy(ASTContext &C) {
-
- // FIXME: There is no clear ownership policy now for referenced
- // ObjCInterfaceDecls. Some of them can be forward declarations that
- // are never later defined (in which case the ObjCClassDecl owns them)
- // or the ObjCInterfaceDecl later becomes a real definition later. Ideally
- // we should have separate objects for forward declarations and definitions,
- // obviating this problem. Because of this situation, referenced
- // ObjCInterfaceDecls are destroyed in ~TranslationUnit.
-
- ForwardDecls.Destroy(C);
+ // ObjCInterfaceDecls registered with a DeclContext will get destroyed
+ // when the DeclContext is destroyed. For those created only by a forward
+ // declaration, the first @class that created the ObjCInterfaceDecl gets
+ // to destroy it.
+ // FIXME: Note that this ownership role is very brittle; a better
+ // polict is surely need in the future.
+ for (iterator I = begin(), E = end(); I !=E ; ++I) {
+ ObjCInterfaceDecl *ID = I->getInterface();
+ if (ID->isForwardDecl() && ID->getLocStart() == getLocStart())
+ ID->Destroy(C);
+ }
+
+ C.Deallocate(ForwardDecls);
Decl::Destroy(C);
}
+SourceRange ObjCClassDecl::getSourceRange() const {
+ // FIXME: We should include the semicolon
+ assert(NumDecls);
+ return SourceRange(getLocation(), ForwardDecls[NumDecls-1].getLocation());
+}
+
//===----------------------------------------------------------------------===//
// ObjCForwardProtocolDecl
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index d9d1950..131de8b 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -71,8 +71,10 @@ namespace {
void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
- void VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D);
+ void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
+ void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
void VisitUsingDecl(UsingDecl *D);
+ void VisitUsingShadowDecl(UsingShadowDecl *D);
};
}
@@ -401,37 +403,6 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
}
}
- else if (CXXDestructorDecl *DDecl = dyn_cast<CXXDestructorDecl>(D)) {
- if (DDecl->getNumBaseOrMemberDestructions() > 0) {
- // List order of base/member destruction for visualization purposes.
- assert (D->isThisDeclarationADefinition() && "Destructor with dtor-list");
- Proto += "/* : ";
- for (CXXDestructorDecl::destr_const_iterator *B = DDecl->destr_begin(),
- *E = DDecl->destr_end();
- B != E; ++B) {
- uintptr_t BaseOrMember = (*B);
- if (B != DDecl->destr_begin())
- Proto += ", ";
-
- if (DDecl->isMemberToDestroy(BaseOrMember)) {
- FieldDecl *FD = DDecl->getMemberToDestroy(BaseOrMember);
- Proto += "~";
- Proto += FD->getNameAsString();
- }
- else // FIXME. skip dependent types for now.
- if (const RecordType *RT =
- DDecl->getAnyBaseClassToDestroy(BaseOrMember)
- ->getAs<RecordType>()) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(RT->getDecl());
- Proto += "~";
- Proto += BaseDecl->getNameAsString();
- }
- Proto += "()";
- }
- Proto += " */";
- }
- }
else
AFT->getResultType().getAsStringInternal(Proto, Policy);
} else {
@@ -654,7 +625,7 @@ void DeclPrinter::VisitObjCClassDecl(ObjCClassDecl *D) {
for (ObjCClassDecl::iterator I = D->begin(), E = D->end();
I != E; ++I) {
if (I != D->begin()) Out << ", ";
- Out << (*I)->getNameAsString();
+ Out << I->getInterface()->getNameAsString();
}
}
@@ -856,11 +827,22 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
void DeclPrinter::VisitUsingDecl(UsingDecl *D) {
Out << "using ";
D->getTargetNestedNameDecl()->print(Out, Policy);
- Out << D->getTargetDecl()->getNameAsString();
+ Out << D->getNameAsString();
+}
+
+void
+DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
+ Out << "using typename ";
+ D->getTargetNestedNameSpecifier()->print(Out, Policy);
+ Out << D->getDeclName().getAsString();
}
-void DeclPrinter::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) {
+void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
Out << "using ";
D->getTargetNestedNameSpecifier()->print(Out, Policy);
- Out << D->getTargetName().getAsString();
+ Out << D->getDeclName().getAsString();
+}
+
+void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) {
+ // ignore
}
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 9ebc91a..0c14714 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -220,7 +220,7 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) {
TemplateArgs.push_back(TemplateArgument(E));
} else {
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
- TemplateArgs.push_back(TemplateArgument(TTP));
+ TemplateArgs.push_back(TemplateArgument(TemplateName(TTP)));
}
}
@@ -285,11 +285,6 @@ TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC,
return new (C) TemplateTemplateParmDecl(DC, L, D, P, Id, Params);
}
-SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const {
- return DefaultArgument? DefaultArgument->getSourceRange().getBegin()
- : SourceLocation();
-}
-
//===----------------------------------------------------------------------===//
// TemplateArgumentListBuilder Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 8664c50..1ff068c 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -18,6 +18,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
+#include <cstdio>
using namespace clang;
namespace clang {
@@ -310,6 +311,10 @@ DeclarationName DeclarationName::getUsingDirectiveName() {
return DeclarationName(Ptr);
}
+void DeclarationName::dump() const {
+ fprintf(stderr, "%s\n", getAsString().c_str());
+}
+
DeclarationNameTable::DeclarationNameTable() {
CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>;
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index a8ea752..90b50c6 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -490,6 +490,8 @@ const char *CastExpr::getCastKindName() const {
return "BitCast";
case CastExpr::CK_NoOp:
return "NoOp";
+ case CastExpr::CK_BaseToDerived:
+ return "BaseToDerived";
case CastExpr::CK_DerivedToBase:
return "DerivedToBase";
case CastExpr::CK_Dynamic:
@@ -812,6 +814,11 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
}
return false;
}
+
+ case CXXTemporaryObjectExprClass:
+ case CXXConstructExprClass:
+ return false;
+
case ObjCMessageExprClass:
return false;
@@ -853,15 +860,19 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
Loc = cast<CStyleCastExpr>(this)->getLParenLoc();
R1 = cast<CStyleCastExpr>(this)->getSubExpr()->getSourceRange();
return true;
- case CXXFunctionalCastExprClass:
- // If this is a cast to void, check the operand. Otherwise, the result of
- // the cast is unused.
- if (getType()->isVoidType())
+ case CXXFunctionalCastExprClass: {
+ const CastExpr *CE = cast<CastExpr>(this);
+
+ // If this is a cast to void or a constructor conversion, check the operand.
+ // Otherwise, the result of the cast is unused.
+ if (CE->getCastKind() == CastExpr::CK_ToVoid ||
+ CE->getCastKind() == CastExpr::CK_ConstructorConversion)
return (cast<CastExpr>(this)->getSubExpr()
->isUnusedResultAWarning(Loc, R1, R2, Ctx));
Loc = cast<CXXFunctionalCastExpr>(this)->getTypeBeginLoc();
R1 = cast<CXXFunctionalCastExpr>(this)->getSubExpr()->getSourceRange();
return true;
+ }
case ImplicitCastExprClass:
// Check the operand, since implicit casts are inserted by Sema
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 7c6fc41..0ba4608 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -323,6 +323,14 @@ Expr *CXXMemberCallExpr::getImplicitObjectArgument() {
return 0;
}
+SourceRange CXXMemberCallExpr::getSourceRange() const {
+ SourceLocation LocStart = getCallee()->getLocStart();
+ if (LocStart.isInvalid() && getNumArgs() > 0)
+ LocStart = getArg(0)->getLocStart();
+ return SourceRange(LocStart, getRParenLoc());
+}
+
+
//===----------------------------------------------------------------------===//
// Named casts
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 7862c57..2689859 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -204,13 +204,6 @@ public:
bool VisitUnaryOperator(UnaryOperator *E) { return Visit(E->getSubExpr()); }
};
-bool HasSideEffects(const Expr* E, ASTContext &Ctx) {
- Expr::EvalResult Result;
- EvalInfo Info(Ctx, Result);
-
- return HasSideEffect(Info).Visit(const_cast<Expr*>(E));
-}
-
} // end anonymous namespace
//===----------------------------------------------------------------------===//
@@ -964,7 +957,7 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
}
}
- if (HasSideEffects(E->getArg(0), Info.Ctx)) {
+ if (E->getArg(0)->HasSideEffects(Info.Ctx)) {
if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() < 2)
return Success(-1ULL, E);
return Success(0, E);
@@ -1495,7 +1488,7 @@ public:
// FIXME: Missing: __real__/__imag__, array subscript of vector,
// member of vector, ImplicitValueInitExpr,
- // conditional ?:, comma
+ // conditional ?:
};
} // end anonymous namespace
@@ -1584,6 +1577,18 @@ bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
}
bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
+ if (E->getOpcode() == BinaryOperator::Comma) {
+ if (!EvaluateFloat(E->getRHS(), Result, Info))
+ return false;
+
+ // If we can't evaluate the LHS, it might have side effects;
+ // conservatively mark it.
+ if (!E->getLHS()->isEvaluatable(Info.Ctx))
+ Info.EvalResult.HasSideEffects = true;
+
+ return true;
+ }
+
// FIXME: Diagnostics? I really don't understand how the warnings
// and errors are supposed to work.
APFloat RHS(0.0);
@@ -1947,6 +1952,12 @@ bool Expr::isEvaluatable(ASTContext &Ctx) const {
return Evaluate(Result, Ctx) && !Result.HasSideEffects;
}
+bool Expr::HasSideEffects(ASTContext &Ctx) const {
+ Expr::EvalResult Result;
+ EvalInfo Info(Ctx, Result);
+ return HasSideEffect(Info).Visit(const_cast<Expr*>(this));
+}
+
APSInt Expr::EvaluateAsInt(ASTContext &Ctx) const {
EvalResult EvalResult;
bool Result = Evaluate(EvalResult, Ctx);
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index d969776..e26c0bb 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -167,7 +167,7 @@ NestedNameSpecifier::print(llvm::raw_ostream &OS,
InnerPolicy);
} else {
// Print the type normally
- T->getAsStringInternal(TypeStr, InnerPolicy);
+ TypeStr = QualType(T, 0).getAsString(InnerPolicy);
}
OS << TypeStr;
break;
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 021c53e..b9cfcfe 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -226,8 +226,7 @@ void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *Class,
if (RD == Class)
BaseOffset = getBaseOffset(Base);
else {
- const ASTRecordLayout &Layout
- = Ctx.getASTRecordLayout(RD);
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
BaseOffset = Offset + Layout.getBaseClassOffset(Base);
}
}
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index cf71d6b..93bf875 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -115,6 +115,7 @@ namespace {
// Exprs
void VisitExpr(Expr *Node);
void VisitCastExpr(CastExpr *Node);
+ void VisitImplicitCastExpr(ImplicitCastExpr *Node);
void VisitDeclRefExpr(DeclRefExpr *Node);
void VisitPredefinedExpr(PredefinedExpr *Node);
void VisitCharacterLiteral(CharacterLiteral *Node);
@@ -301,6 +302,12 @@ void StmtDumper::VisitCastExpr(CastExpr *Node) {
fprintf(F, " <%s>", Node->getCastKindName());
}
+void StmtDumper::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
+ VisitCastExpr(Node);
+ if (Node->isLvalueCast())
+ fprintf(F, " lvalue");
+}
+
void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
DumpExpr(Node);
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 02e0c74..4458c2b 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -695,6 +695,10 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
VisitType(Arg.getAsType());
break;
+ case TemplateArgument::Template:
+ VisitTemplateName(Arg.getAsTemplate());
+ break;
+
case TemplateArgument::Declaration:
VisitDecl(Arg.getAsDecl());
break;
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index 94e1ca1..ff02f9a 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -58,6 +58,11 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : 0);
break;
+ case Template:
+ ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate())
+ .getAsVoidPointer());
+ break;
+
case Integral:
getAsIntegral()->Profile(ID);
getIntegralType().Profile(ID);
@@ -82,10 +87,19 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
switch (Argument.getKind()) {
case TemplateArgument::Expression:
return getSourceExpression()->getSourceRange();
+
case TemplateArgument::Declaration:
return getSourceDeclExpression()->getSourceRange();
+
case TemplateArgument::Type:
return getSourceDeclaratorInfo()->getTypeLoc().getFullSourceRange();
+
+ case TemplateArgument::Template:
+ if (getTemplateQualifierRange().isValid())
+ return SourceRange(getTemplateQualifierRange().getBegin(),
+ getTemplateNameLoc());
+ return SourceRange(getTemplateNameLoc());
+
case TemplateArgument::Integral:
case TemplateArgument::Pack:
case TemplateArgument::Null:
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 779f680..297534e 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -98,6 +98,44 @@ const Type *Type::getArrayElementTypeNoTypeQual() const {
->getElementType().getTypePtr();
}
+/// \brief Retrieve the unqualified variant of the given type, removing as
+/// little sugar as possible.
+///
+/// This routine looks through various kinds of sugar to find the
+/// least-desuraged type that is unqualified. For example, given:
+///
+/// \code
+/// typedef int Integer;
+/// typedef const Integer CInteger;
+/// typedef CInteger DifferenceType;
+/// \endcode
+///
+/// Executing \c getUnqualifiedTypeSlow() on the type \c DifferenceType will
+/// desugar until we hit the type \c Integer, which has no qualifiers on it.
+QualType QualType::getUnqualifiedTypeSlow() const {
+ QualType Cur = *this;
+ while (true) {
+ if (!Cur.hasQualifiers())
+ return Cur;
+
+ const Type *CurTy = Cur.getTypePtr();
+ switch (CurTy->getTypeClass()) {
+#define ABSTRACT_TYPE(Class, Parent)
+#define TYPE(Class, Parent) \
+ case Type::Class: { \
+ const Class##Type *Ty = cast<Class##Type>(CurTy); \
+ if (!Ty->isSugared()) \
+ return Cur.getLocalUnqualifiedType(); \
+ Cur = Ty->desugar(); \
+ break; \
+ }
+#include "clang/AST/TypeNodes.def"
+ }
+ }
+
+ return Cur.getUnqualifiedType();
+}
+
/// getDesugaredType - Return the specified type with any "sugar" removed from
/// the type. This takes off typedefs, typeof's etc. If the outer level of
/// the type is already concrete, it returns it unmodified. This is similar
@@ -425,7 +463,7 @@ bool Type::isSignedIntegerType() const {
bool Type::isUnsignedIntegerType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
return BT->getKind() >= BuiltinType::Bool &&
- BT->getKind() <= BuiltinType::ULongLong;
+ BT->getKind() <= BuiltinType::UInt128;
}
if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
@@ -453,8 +491,7 @@ bool Type::isFloatingType() const {
bool Type::isRealFloatingType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
- return BT->getKind() >= BuiltinType::Float &&
- BT->getKind() <= BuiltinType::LongDouble;
+ return BT->isFloatingPoint();
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isRealFloatingType();
return false;
@@ -808,6 +845,9 @@ static bool isDependent(const TemplateArgument &Arg) {
case TemplateArgument::Type:
return Arg.getAsType()->isDependentType();
+ case TemplateArgument::Template:
+ return Arg.getAsTemplate().isDependent();
+
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
// Never dependent
@@ -907,539 +947,6 @@ QualType QualifierCollector::apply(const Type *T) const {
return Context->getQualifiedType(T, *this);
}
-
-//===----------------------------------------------------------------------===//
-// Type Printing
-//===----------------------------------------------------------------------===//
-
-void QualType::dump(const char *msg) const {
- std::string R = "identifier";
- LangOptions LO;
- getAsStringInternal(R, PrintingPolicy(LO));
- if (msg)
- fprintf(stderr, "%s: %s\n", msg, R.c_str());
- else
- fprintf(stderr, "%s\n", R.c_str());
-}
-void QualType::dump() const {
- dump("");
-}
-
-void Type::dump() const {
- std::string S = "identifier";
- LangOptions LO;
- getAsStringInternal(S, PrintingPolicy(LO));
- fprintf(stderr, "%s\n", S.c_str());
-}
-
-
-
-static void AppendTypeQualList(std::string &S, unsigned TypeQuals) {
- if (TypeQuals & Qualifiers::Const) {
- if (!S.empty()) S += ' ';
- S += "const";
- }
- if (TypeQuals & Qualifiers::Volatile) {
- if (!S.empty()) S += ' ';
- S += "volatile";
- }
- if (TypeQuals & Qualifiers::Restrict) {
- if (!S.empty()) S += ' ';
- S += "restrict";
- }
-}
-
-std::string Qualifiers::getAsString() const {
- LangOptions LO;
- return getAsString(PrintingPolicy(LO));
-}
-
-// Appends qualifiers to the given string, separated by spaces. Will
-// prefix a space if the string is non-empty. Will not append a final
-// space.
-void Qualifiers::getAsStringInternal(std::string &S,
- const PrintingPolicy&) const {
- AppendTypeQualList(S, getCVRQualifiers());
- if (unsigned AddressSpace = getAddressSpace()) {
- if (!S.empty()) S += ' ';
- S += "__attribute__((address_space(";
- S += llvm::utostr_32(AddressSpace);
- S += ")))";
- }
- if (Qualifiers::GC GCAttrType = getObjCGCAttr()) {
- if (!S.empty()) S += ' ';
- S += "__attribute__((objc_gc(";
- if (GCAttrType == Qualifiers::Weak)
- S += "weak";
- else
- S += "strong";
- S += ")))";
- }
-}
-
-std::string QualType::getAsString() const {
- std::string S;
- LangOptions LO;
- getAsStringInternal(S, PrintingPolicy(LO));
- return S;
-}
-
-void
-QualType::getAsStringInternal(std::string &S,
- const PrintingPolicy &Policy) const {
- if (isNull()) {
- S += "NULL TYPE";
- return;
- }
-
- if (Policy.SuppressSpecifiers && getTypePtr()->isSpecifierType())
- return;
-
- // Print qualifiers as appropriate.
- Qualifiers Quals = getQualifiers();
- if (!Quals.empty()) {
- std::string TQS;
- Quals.getAsStringInternal(TQS, Policy);
-
- if (!S.empty()) {
- TQS += ' ';
- TQS += S;
- }
- std::swap(S, TQS);
- }
-
- getTypePtr()->getAsStringInternal(S, Policy);
-}
-
-void BuiltinType::getAsStringInternal(std::string &S,
- const PrintingPolicy &Policy) const {
- if (S.empty()) {
- S = getName(Policy.LangOpts);
- } else {
- // Prefix the basic type, e.g. 'int X'.
- S = ' ' + S;
- S = getName(Policy.LangOpts) + S;
- }
-}
-
-void FixedWidthIntType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- // FIXME: Once we get bitwidth attribute, write as
- // "int __attribute__((bitwidth(x)))".
- std::string prefix = "__clang_fixedwidth";
- prefix += llvm::utostr_32(Width);
- prefix += (char)(Signed ? 'S' : 'U');
- if (S.empty()) {
- S = prefix;
- } else {
- // Prefix the basic type, e.g. 'int X'.
- S = prefix + S;
- }
-}
-
-
-void ComplexType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- ElementType->getAsStringInternal(S, Policy);
- S = "_Complex " + S;
-}
-
-void PointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S = '*' + S;
-
- // Handle things like 'int (*A)[4];' correctly.
- // FIXME: this should include vectors, but vectors use attributes I guess.
- if (isa<ArrayType>(getPointeeType()))
- S = '(' + S + ')';
-
- getPointeeType().getAsStringInternal(S, Policy);
-}
-
-void BlockPointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S = '^' + S;
- PointeeType.getAsStringInternal(S, Policy);
-}
-
-void LValueReferenceType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S = '&' + S;
-
- // Handle things like 'int (&A)[4];' correctly.
- // FIXME: this should include vectors, but vectors use attributes I guess.
- if (isa<ArrayType>(getPointeeTypeAsWritten()))
- S = '(' + S + ')';
-
- getPointeeTypeAsWritten().getAsStringInternal(S, Policy);
-}
-
-void RValueReferenceType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S = "&&" + S;
-
- // Handle things like 'int (&&A)[4];' correctly.
- // FIXME: this should include vectors, but vectors use attributes I guess.
- if (isa<ArrayType>(getPointeeTypeAsWritten()))
- S = '(' + S + ')';
-
- getPointeeTypeAsWritten().getAsStringInternal(S, Policy);
-}
-
-void MemberPointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- std::string C;
- Class->getAsStringInternal(C, Policy);
- C += "::*";
- S = C + S;
-
- // Handle things like 'int (Cls::*A)[4];' correctly.
- // FIXME: this should include vectors, but vectors use attributes I guess.
- if (isa<ArrayType>(getPointeeType()))
- S = '(' + S + ')';
-
- getPointeeType().getAsStringInternal(S, Policy);
-}
-
-void ConstantArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S += '[';
- S += llvm::utostr(getSize().getZExtValue());
- S += ']';
-
- getElementType().getAsStringInternal(S, Policy);
-}
-
-void IncompleteArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S += "[]";
-
- getElementType().getAsStringInternal(S, Policy);
-}
-
-void VariableArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S += '[';
-
- if (getIndexTypeQualifiers().hasQualifiers()) {
- AppendTypeQualList(S, getIndexTypeCVRQualifiers());
- S += ' ';
- }
-
- if (getSizeModifier() == Static)
- S += "static";
- else if (getSizeModifier() == Star)
- S += '*';
-
- if (getSizeExpr()) {
- std::string SStr;
- llvm::raw_string_ostream s(SStr);
- getSizeExpr()->printPretty(s, 0, Policy);
- S += s.str();
- }
- S += ']';
-
- getElementType().getAsStringInternal(S, Policy);
-}
-
-void DependentSizedArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S += '[';
-
- if (getIndexTypeQualifiers().hasQualifiers()) {
- AppendTypeQualList(S, getIndexTypeCVRQualifiers());
- S += ' ';
- }
-
- if (getSizeModifier() == Static)
- S += "static";
- else if (getSizeModifier() == Star)
- S += '*';
-
- if (getSizeExpr()) {
- std::string SStr;
- llvm::raw_string_ostream s(SStr);
- getSizeExpr()->printPretty(s, 0, Policy);
- S += s.str();
- }
- S += ']';
-
- getElementType().getAsStringInternal(S, Policy);
-}
-
-void DependentSizedExtVectorType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- getElementType().getAsStringInternal(S, Policy);
-
- S += " __attribute__((ext_vector_type(";
- if (getSizeExpr()) {
- std::string SStr;
- llvm::raw_string_ostream s(SStr);
- getSizeExpr()->printPretty(s, 0, Policy);
- S += s.str();
- }
- S += ")))";
-}
-
-void VectorType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- // FIXME: We prefer to print the size directly here, but have no way
- // to get the size of the type.
- S += " __attribute__((__vector_size__(";
- S += llvm::utostr_32(NumElements); // convert back to bytes.
- S += " * sizeof(" + ElementType.getAsString() + "))))";
- ElementType.getAsStringInternal(S, Policy);
-}
-
-void ExtVectorType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S += " __attribute__((ext_vector_type(";
- S += llvm::utostr_32(NumElements);
- S += ")))";
- ElementType.getAsStringInternal(S, Policy);
-}
-
-void TypeOfExprType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(e) X'.
- InnerString = ' ' + InnerString;
- std::string Str;
- llvm::raw_string_ostream s(Str);
- getUnderlyingExpr()->printPretty(s, 0, Policy);
- InnerString = "typeof " + s.str() + InnerString;
-}
-
-void TypeOfType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(t) X'.
- InnerString = ' ' + InnerString;
- std::string Tmp;
- getUnderlyingType().getAsStringInternal(Tmp, Policy);
- InnerString = "typeof(" + Tmp + ")" + InnerString;
-}
-
-void DecltypeType::getAsStringInternal(std::string &InnerString,
- const PrintingPolicy &Policy) const {
- if (!InnerString.empty()) // Prefix the basic type, e.g. 'decltype(t) X'.
- InnerString = ' ' + InnerString;
- std::string Str;
- llvm::raw_string_ostream s(Str);
- getUnderlyingExpr()->printPretty(s, 0, Policy);
- InnerString = "decltype(" + s.str() + ")" + InnerString;
-}
-
-void FunctionNoProtoType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- // If needed for precedence reasons, wrap the inner part in grouping parens.
- if (!S.empty())
- S = "(" + S + ")";
-
- S += "()";
- if (getNoReturnAttr())
- S += " __attribute__((noreturn))";
- getResultType().getAsStringInternal(S, Policy);
-}
-
-void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- // If needed for precedence reasons, wrap the inner part in grouping parens.
- if (!S.empty())
- S = "(" + S + ")";
-
- S += "(";
- std::string Tmp;
- PrintingPolicy ParamPolicy(Policy);
- ParamPolicy.SuppressSpecifiers = false;
- for (unsigned i = 0, e = getNumArgs(); i != e; ++i) {
- if (i) S += ", ";
- getArgType(i).getAsStringInternal(Tmp, ParamPolicy);
- S += Tmp;
- Tmp.clear();
- }
-
- if (isVariadic()) {
- if (getNumArgs())
- S += ", ";
- S += "...";
- } else if (getNumArgs() == 0 && !Policy.LangOpts.CPlusPlus) {
- // Do not emit int() if we have a proto, emit 'int(void)'.
- S += "void";
- }
-
- S += ")";
- if (getNoReturnAttr())
- S += " __attribute__((noreturn))";
- getResultType().getAsStringInternal(S, Policy);
-}
-
-
-void TypedefType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
- InnerString = ' ' + InnerString;
- InnerString = getDecl()->getIdentifier()->getName().str() + InnerString;
-}
-
-void TemplateTypeParmType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- if (!InnerString.empty()) // Prefix the basic type, e.g. 'parmname X'.
- InnerString = ' ' + InnerString;
-
- if (!Name)
- InnerString = "type-parameter-" + llvm::utostr_32(Depth) + '-' +
- llvm::utostr_32(Index) + InnerString;
- else
- InnerString = Name->getName().str() + InnerString;
-}
-
-void SubstTemplateTypeParmType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- getReplacementType().getAsStringInternal(InnerString, Policy);
-}
-
-static void PrintTemplateArgument(std::string &Buffer,
- const TemplateArgument &Arg,
- const PrintingPolicy &Policy) {
- switch (Arg.getKind()) {
- case TemplateArgument::Null:
- assert(false && "Null template argument");
- break;
-
- case TemplateArgument::Type:
- Arg.getAsType().getAsStringInternal(Buffer, Policy);
- break;
-
- case TemplateArgument::Declaration:
- Buffer = cast<NamedDecl>(Arg.getAsDecl())->getNameAsString();
- break;
-
- case TemplateArgument::Integral:
- Buffer = Arg.getAsIntegral()->toString(10, true);
- break;
-
- case TemplateArgument::Expression: {
- llvm::raw_string_ostream s(Buffer);
- Arg.getAsExpr()->printPretty(s, 0, Policy);
- break;
- }
-
- case TemplateArgument::Pack:
- assert(0 && "FIXME: Implement!");
- break;
- }
-}
-
-std::string
-TemplateSpecializationType::PrintTemplateArgumentList(
- const TemplateArgument *Args,
- unsigned NumArgs,
- const PrintingPolicy &Policy) {
- std::string SpecString;
- SpecString += '<';
- for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
- if (Arg)
- SpecString += ", ";
-
- // Print the argument into a string.
- std::string ArgString;
- PrintTemplateArgument(ArgString, Args[Arg], Policy);
-
- // If this is the first argument and its string representation
- // begins with the global scope specifier ('::foo'), add a space
- // to avoid printing the diagraph '<:'.
- if (!Arg && !ArgString.empty() && ArgString[0] == ':')
- SpecString += ' ';
-
- SpecString += ArgString;
- }
-
- // If the last character of our string is '>', add another space to
- // keep the two '>''s separate tokens. We don't *have* to do this in
- // C++0x, but it's still good hygiene.
- if (SpecString[SpecString.size() - 1] == '>')
- SpecString += ' ';
-
- SpecString += '>';
-
- return SpecString;
-}
-
-// Sadly, repeat all that with TemplateArgLoc.
-std::string TemplateSpecializationType::
-PrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs,
- const PrintingPolicy &Policy) {
- std::string SpecString;
- SpecString += '<';
- for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
- if (Arg)
- SpecString += ", ";
-
- // Print the argument into a string.
- std::string ArgString;
- PrintTemplateArgument(ArgString, Args[Arg].getArgument(), Policy);
-
- // If this is the first argument and its string representation
- // begins with the global scope specifier ('::foo'), add a space
- // to avoid printing the diagraph '<:'.
- if (!Arg && !ArgString.empty() && ArgString[0] == ':')
- SpecString += ' ';
-
- SpecString += ArgString;
- }
-
- // If the last character of our string is '>', add another space to
- // keep the two '>''s separate tokens. We don't *have* to do this in
- // C++0x, but it's still good hygiene.
- if (SpecString[SpecString.size() - 1] == '>')
- SpecString += ' ';
-
- SpecString += '>';
-
- return SpecString;
-}
-
-void
-TemplateSpecializationType::
-getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- std::string SpecString;
-
- {
- llvm::raw_string_ostream OS(SpecString);
- Template.print(OS, Policy);
- }
-
- SpecString += PrintTemplateArgumentList(getArgs(), getNumArgs(), Policy);
- if (InnerString.empty())
- InnerString.swap(SpecString);
- else
- InnerString = SpecString + ' ' + InnerString;
-}
-
-void QualifiedNameType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- std::string MyString;
-
- {
- llvm::raw_string_ostream OS(MyString);
- NNS->print(OS, Policy);
- }
-
- std::string TypeStr;
- PrintingPolicy InnerPolicy(Policy);
- InnerPolicy.SuppressTagKind = true;
- InnerPolicy.SuppressScope = true;
- NamedType.getAsStringInternal(TypeStr, InnerPolicy);
-
- MyString += TypeStr;
- if (InnerString.empty())
- InnerString.swap(MyString);
- else
- InnerString = MyString + ' ' + InnerString;
-}
-
-void TypenameType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- std::string MyString;
-
- {
- llvm::raw_string_ostream OS(MyString);
- OS << "typename ";
- NNS->print(OS, Policy);
-
- if (const IdentifierInfo *Ident = getIdentifier())
- OS << Ident->getName();
- else if (const TemplateSpecializationType *Spec = getTemplateId()) {
- Spec->getTemplateName().print(OS, Policy, true);
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Spec->getArgs(),
- Spec->getNumArgs(),
- Policy);
- }
- }
-
- if (InnerString.empty())
- InnerString.swap(MyString);
- else
- InnerString = MyString + ' ' + InnerString;
-}
-
void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID,
const ObjCInterfaceDecl *Decl,
ObjCProtocolDecl **protocols,
@@ -1455,134 +962,3 @@ void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID) {
else
Profile(ID, getDecl(), 0, 0);
}
-
-void ObjCInterfaceType::getAsStringInternal(std::string &InnerString,
- const PrintingPolicy &Policy) const {
- if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
- InnerString = ' ' + InnerString;
-
- std::string ObjCQIString = getDecl()->getNameAsString();
- if (getNumProtocols()) {
- ObjCQIString += '<';
- bool isFirst = true;
- for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) {
- if (isFirst)
- isFirst = false;
- else
- ObjCQIString += ',';
- ObjCQIString += (*I)->getNameAsString();
- }
- ObjCQIString += '>';
- }
- InnerString = ObjCQIString + InnerString;
-}
-
-void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString,
- const PrintingPolicy &Policy) const {
- std::string ObjCQIString;
-
- if (isObjCIdType() || isObjCQualifiedIdType())
- ObjCQIString = "id";
- else if (isObjCClassType() || isObjCQualifiedClassType())
- ObjCQIString = "Class";
- else
- ObjCQIString = getInterfaceDecl()->getNameAsString();
-
- if (!qual_empty()) {
- ObjCQIString += '<';
- for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) {
- ObjCQIString += (*I)->getNameAsString();
- if (I+1 != E)
- ObjCQIString += ',';
- }
- ObjCQIString += '>';
- }
-
- PointeeType.getQualifiers().getAsStringInternal(ObjCQIString, Policy);
-
- if (!isObjCIdType() && !isObjCQualifiedIdType())
- ObjCQIString += " *"; // Don't forget the implicit pointer.
- else if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
- InnerString = ' ' + InnerString;
-
- InnerString = ObjCQIString + InnerString;
-}
-
-void ElaboratedType::getAsStringInternal(std::string &InnerString,
- const PrintingPolicy &Policy) const {
- std::string TypeStr;
- PrintingPolicy InnerPolicy(Policy);
- InnerPolicy.SuppressTagKind = true;
- UnderlyingType.getAsStringInternal(InnerString, InnerPolicy);
-
- InnerString = std::string(getNameForTagKind(getTagKind())) + ' ' + InnerString;
-}
-
-void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- if (Policy.SuppressTag)
- return;
-
- if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
- InnerString = ' ' + InnerString;
-
- const char *Kind = Policy.SuppressTagKind? 0 : getDecl()->getKindName();
- const char *ID;
- if (const IdentifierInfo *II = getDecl()->getIdentifier())
- ID = II->getNameStart();
- else if (TypedefDecl *Typedef = getDecl()->getTypedefForAnonDecl()) {
- Kind = 0;
- assert(Typedef->getIdentifier() && "Typedef without identifier?");
- ID = Typedef->getIdentifier()->getNameStart();
- } else
- ID = "<anonymous>";
-
- // If this is a class template specialization, print the template
- // arguments.
- if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(getDecl())) {
- const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- std::string TemplateArgsStr
- = TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs.getFlatArgumentList(),
- TemplateArgs.flat_size(),
- Policy);
- InnerString = TemplateArgsStr + InnerString;
- }
-
- if (!Policy.SuppressScope) {
- // Compute the full nested-name-specifier for this type. In C,
- // this will always be empty.
- std::string ContextStr;
- for (DeclContext *DC = getDecl()->getDeclContext();
- !DC->isTranslationUnit(); DC = DC->getParent()) {
- std::string MyPart;
- if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) {
- if (NS->getIdentifier())
- MyPart = NS->getNameAsString();
- } else if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
- const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- std::string TemplateArgsStr
- = TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs.getFlatArgumentList(),
- TemplateArgs.flat_size(),
- Policy);
- MyPart = Spec->getIdentifier()->getName().str() + TemplateArgsStr;
- } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
- if (TypedefDecl *Typedef = Tag->getTypedefForAnonDecl())
- MyPart = Typedef->getIdentifier()->getName();
- else if (Tag->getIdentifier())
- MyPart = Tag->getIdentifier()->getName();
- }
-
- if (!MyPart.empty())
- ContextStr = MyPart + "::" + ContextStr;
- }
-
- if (Kind)
- InnerString = std::string(Kind) + ' ' + ContextStr + ID + InnerString;
- else
- InnerString = ContextStr + ID + InnerString;
- } else
- InnerString = ID + InnerString;
-}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
new file mode 100644
index 0000000..a482333
--- /dev/null
+++ b/lib/AST/TypePrinter.cpp
@@ -0,0 +1,728 @@
+//===--- TypePrinter.cpp - Pretty-Print Clang Types -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to print types from Clang's type system.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+namespace {
+ class TypePrinter {
+ PrintingPolicy Policy;
+
+ public:
+ explicit TypePrinter(const PrintingPolicy &Policy) : Policy(Policy) { }
+
+ void Print(QualType T, std::string &S);
+ void PrintTag(const TagType *T, std::string &S);
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define TYPE(CLASS, PARENT) \
+ void Print##CLASS(const CLASS##Type *T, std::string &S);
+#include "clang/AST/TypeNodes.def"
+ };
+}
+
+static void AppendTypeQualList(std::string &S, unsigned TypeQuals) {
+ if (TypeQuals & Qualifiers::Const) {
+ if (!S.empty()) S += ' ';
+ S += "const";
+ }
+ if (TypeQuals & Qualifiers::Volatile) {
+ if (!S.empty()) S += ' ';
+ S += "volatile";
+ }
+ if (TypeQuals & Qualifiers::Restrict) {
+ if (!S.empty()) S += ' ';
+ S += "restrict";
+ }
+}
+
+void TypePrinter::Print(QualType T, std::string &S) {
+ if (T.isNull()) {
+ S += "NULL TYPE";
+ return;
+ }
+
+ if (Policy.SuppressSpecifiers && T->isSpecifierType())
+ return;
+
+ // Print qualifiers as appropriate.
+ Qualifiers Quals = T.getLocalQualifiers();
+ if (!Quals.empty()) {
+ std::string TQS;
+ Quals.getAsStringInternal(TQS, Policy);
+
+ if (!S.empty()) {
+ TQS += ' ';
+ TQS += S;
+ }
+ std::swap(S, TQS);
+ }
+
+ switch (T->getTypeClass()) {
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define TYPE(CLASS, PARENT) case Type::CLASS: \
+ Print##CLASS(cast<CLASS##Type>(T.getTypePtr()), S); \
+ break;
+#include "clang/AST/TypeNodes.def"
+ }
+}
+
+void TypePrinter::PrintBuiltin(const BuiltinType *T, std::string &S) {
+ if (S.empty()) {
+ S = T->getName(Policy.LangOpts);
+ } else {
+ // Prefix the basic type, e.g. 'int X'.
+ S = ' ' + S;
+ S = T->getName(Policy.LangOpts) + S;
+ }
+}
+
+void TypePrinter::PrintFixedWidthInt(const FixedWidthIntType *T,
+ std::string &S) {
+ // FIXME: Once we get bitwidth attribute, write as
+ // "int __attribute__((bitwidth(x)))".
+ std::string prefix = "__clang_fixedwidth";
+ prefix += llvm::utostr_32(T->getWidth());
+ prefix += (char)(T->isSigned() ? 'S' : 'U');
+ if (S.empty()) {
+ S = prefix;
+ } else {
+ // Prefix the basic type, e.g. 'int X'.
+ S = prefix + S;
+ }
+}
+
+void TypePrinter::PrintComplex(const ComplexType *T, std::string &S) {
+ Print(T->getElementType(), S);
+ S = "_Complex " + S;
+}
+
+void TypePrinter::PrintPointer(const PointerType *T, std::string &S) {
+ S = '*' + S;
+
+ // Handle things like 'int (*A)[4];' correctly.
+ // FIXME: this should include vectors, but vectors use attributes I guess.
+ if (isa<ArrayType>(T->getPointeeType()))
+ S = '(' + S + ')';
+
+ Print(T->getPointeeType(), S);
+}
+
+void TypePrinter::PrintBlockPointer(const BlockPointerType *T, std::string &S) {
+ S = '^' + S;
+ Print(T->getPointeeType(), S);
+}
+
+void TypePrinter::PrintLValueReference(const LValueReferenceType *T,
+ std::string &S) {
+ S = '&' + S;
+
+ // Handle things like 'int (&A)[4];' correctly.
+ // FIXME: this should include vectors, but vectors use attributes I guess.
+ if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
+ S = '(' + S + ')';
+
+ Print(T->getPointeeTypeAsWritten(), S);
+}
+
+void TypePrinter::PrintRValueReference(const RValueReferenceType *T,
+ std::string &S) {
+ S = "&&" + S;
+
+ // Handle things like 'int (&&A)[4];' correctly.
+ // FIXME: this should include vectors, but vectors use attributes I guess.
+ if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
+ S = '(' + S + ')';
+
+ Print(T->getPointeeTypeAsWritten(), S);
+}
+
+void TypePrinter::PrintMemberPointer(const MemberPointerType *T,
+ std::string &S) {
+ std::string C;
+ Print(QualType(T->getClass(), 0), C);
+ C += "::*";
+ S = C + S;
+
+ // Handle things like 'int (Cls::*A)[4];' correctly.
+ // FIXME: this should include vectors, but vectors use attributes I guess.
+ if (isa<ArrayType>(T->getPointeeType()))
+ S = '(' + S + ')';
+
+ Print(T->getPointeeType(), S);
+}
+
+void TypePrinter::PrintConstantArray(const ConstantArrayType *T,
+ std::string &S) {
+ S += '[';
+ S += llvm::utostr(T->getSize().getZExtValue());
+ S += ']';
+
+ Print(T->getElementType(), S);
+}
+
+void TypePrinter::PrintIncompleteArray(const IncompleteArrayType *T,
+ std::string &S) {
+ S += "[]";
+ Print(T->getElementType(), S);
+}
+
+void TypePrinter::PrintVariableArray(const VariableArrayType *T,
+ std::string &S) {
+ S += '[';
+
+ if (T->getIndexTypeQualifiers().hasQualifiers()) {
+ AppendTypeQualList(S, T->getIndexTypeCVRQualifiers());
+ S += ' ';
+ }
+
+ if (T->getSizeModifier() == VariableArrayType::Static)
+ S += "static";
+ else if (T->getSizeModifier() == VariableArrayType::Star)
+ S += '*';
+
+ if (T->getSizeExpr()) {
+ std::string SStr;
+ llvm::raw_string_ostream s(SStr);
+ T->getSizeExpr()->printPretty(s, 0, Policy);
+ S += s.str();
+ }
+ S += ']';
+
+ Print(T->getElementType(), S);
+}
+
+void TypePrinter::PrintDependentSizedArray(const DependentSizedArrayType *T,
+ std::string &S) {
+ S += '[';
+
+ if (T->getSizeExpr()) {
+ std::string SStr;
+ llvm::raw_string_ostream s(SStr);
+ T->getSizeExpr()->printPretty(s, 0, Policy);
+ S += s.str();
+ }
+ S += ']';
+
+ Print(T->getElementType(), S);
+}
+
+void TypePrinter::PrintDependentSizedExtVector(
+ const DependentSizedExtVectorType *T,
+ std::string &S) {
+ Print(T->getElementType(), S);
+
+ S += " __attribute__((ext_vector_type(";
+ if (T->getSizeExpr()) {
+ std::string SStr;
+ llvm::raw_string_ostream s(SStr);
+ T->getSizeExpr()->printPretty(s, 0, Policy);
+ S += s.str();
+ }
+ S += ")))";
+}
+
+void TypePrinter::PrintVector(const VectorType *T, std::string &S) {
+ // FIXME: We prefer to print the size directly here, but have no way
+ // to get the size of the type.
+ S += " __attribute__((__vector_size__(";
+ S += llvm::utostr_32(T->getNumElements()); // convert back to bytes.
+ std::string ET;
+ Print(T->getElementType(), ET);
+ S += " * sizeof(" + ET + "))))";
+ Print(T->getElementType(), S);
+}
+
+void TypePrinter::PrintExtVector(const ExtVectorType *T, std::string &S) {
+ S += " __attribute__((ext_vector_type(";
+ S += llvm::utostr_32(T->getNumElements());
+ S += ")))";
+ Print(T->getElementType(), S);
+}
+
+void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
+ std::string &S) {
+ // If needed for precedence reasons, wrap the inner part in grouping parens.
+ if (!S.empty())
+ S = "(" + S + ")";
+
+ S += "(";
+ std::string Tmp;
+ PrintingPolicy ParamPolicy(Policy);
+ ParamPolicy.SuppressSpecifiers = false;
+ for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) {
+ if (i) S += ", ";
+ Print(T->getArgType(i), Tmp);
+ S += Tmp;
+ Tmp.clear();
+ }
+
+ if (T->isVariadic()) {
+ if (T->getNumArgs())
+ S += ", ";
+ S += "...";
+ } else if (T->getNumArgs() == 0 && !Policy.LangOpts.CPlusPlus) {
+ // Do not emit int() if we have a proto, emit 'int(void)'.
+ S += "void";
+ }
+
+ S += ")";
+ if (T->getNoReturnAttr())
+ S += " __attribute__((noreturn))";
+ Print(T->getResultType(), S);
+
+}
+
+void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T,
+ std::string &S) {
+ // If needed for precedence reasons, wrap the inner part in grouping parens.
+ if (!S.empty())
+ S = "(" + S + ")";
+
+ S += "()";
+ if (T->getNoReturnAttr())
+ S += " __attribute__((noreturn))";
+ Print(T->getResultType(), S);
+}
+
+void TypePrinter::PrintTypedef(const TypedefType *T, std::string &S) {
+ if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ S = ' ' + S;
+ S = T->getDecl()->getIdentifier()->getName().str() + S;
+}
+
+void TypePrinter::PrintTypeOfExpr(const TypeOfExprType *T, std::string &S) {
+ if (!S.empty()) // Prefix the basic type, e.g. 'typeof(e) X'.
+ S = ' ' + S;
+ std::string Str;
+ llvm::raw_string_ostream s(Str);
+ T->getUnderlyingExpr()->printPretty(s, 0, Policy);
+ S = "typeof " + s.str() + S;
+}
+
+void TypePrinter::PrintTypeOf(const TypeOfType *T, std::string &S) {
+ if (!S.empty()) // Prefix the basic type, e.g. 'typeof(t) X'.
+ S = ' ' + S;
+ std::string Tmp;
+ Print(T->getUnderlyingType(), Tmp);
+ S = "typeof(" + Tmp + ")" + S;
+}
+
+void TypePrinter::PrintDecltype(const DecltypeType *T, std::string &S) {
+ if (!S.empty()) // Prefix the basic type, e.g. 'decltype(t) X'.
+ S = ' ' + S;
+ std::string Str;
+ llvm::raw_string_ostream s(Str);
+ T->getUnderlyingExpr()->printPretty(s, 0, Policy);
+ S = "decltype(" + s.str() + ")" + S;
+}
+
+void TypePrinter::PrintTag(const TagType *T, std::string &InnerString) {
+ if (Policy.SuppressTag)
+ return;
+
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ InnerString = ' ' + InnerString;
+
+ const char *Kind = Policy.SuppressTagKind? 0 : T->getDecl()->getKindName();
+ const char *ID;
+ if (const IdentifierInfo *II = T->getDecl()->getIdentifier())
+ ID = II->getNameStart();
+ else if (TypedefDecl *Typedef = T->getDecl()->getTypedefForAnonDecl()) {
+ Kind = 0;
+ assert(Typedef->getIdentifier() && "Typedef without identifier?");
+ ID = Typedef->getIdentifier()->getNameStart();
+ } else
+ ID = "<anonymous>";
+
+ // If this is a class template specialization, print the template
+ // arguments.
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl())) {
+ const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+ std::string TemplateArgsStr
+ = TemplateSpecializationType::PrintTemplateArgumentList(
+ TemplateArgs.getFlatArgumentList(),
+ TemplateArgs.flat_size(),
+ Policy);
+ InnerString = TemplateArgsStr + InnerString;
+ }
+
+ if (!Policy.SuppressScope) {
+ // Compute the full nested-name-specifier for this type. In C,
+ // this will always be empty.
+ std::string ContextStr;
+ for (DeclContext *DC = T->getDecl()->getDeclContext();
+ !DC->isTranslationUnit(); DC = DC->getParent()) {
+ std::string MyPart;
+ if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) {
+ if (NS->getIdentifier())
+ MyPart = NS->getNameAsString();
+ } else if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
+ const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+ std::string TemplateArgsStr
+ = TemplateSpecializationType::PrintTemplateArgumentList(
+ TemplateArgs.getFlatArgumentList(),
+ TemplateArgs.flat_size(),
+ Policy);
+ MyPart = Spec->getIdentifier()->getName().str() + TemplateArgsStr;
+ } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
+ if (TypedefDecl *Typedef = Tag->getTypedefForAnonDecl())
+ MyPart = Typedef->getIdentifier()->getName();
+ else if (Tag->getIdentifier())
+ MyPart = Tag->getIdentifier()->getName();
+ }
+
+ if (!MyPart.empty())
+ ContextStr = MyPart + "::" + ContextStr;
+ }
+
+ if (Kind)
+ InnerString = std::string(Kind) + ' ' + ContextStr + ID + InnerString;
+ else
+ InnerString = ContextStr + ID + InnerString;
+ } else
+ InnerString = ID + InnerString;
+}
+
+void TypePrinter::PrintRecord(const RecordType *T, std::string &S) {
+ PrintTag(T, S);
+}
+
+void TypePrinter::PrintEnum(const EnumType *T, std::string &S) {
+ PrintTag(T, S);
+}
+
+void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) {
+ std::string TypeStr;
+ PrintingPolicy InnerPolicy(Policy);
+ InnerPolicy.SuppressTagKind = true;
+ TypePrinter(InnerPolicy).Print(T->getUnderlyingType(), S);
+
+ S = std::string(T->getNameForTagKind(T->getTagKind())) + ' ' + S;
+}
+
+void TypePrinter::PrintTemplateTypeParm(const TemplateTypeParmType *T,
+ std::string &S) {
+ if (!S.empty()) // Prefix the basic type, e.g. 'parmname X'.
+ S = ' ' + S;
+
+ if (!T->getName())
+ S = "type-parameter-" + llvm::utostr_32(T->getDepth()) + '-' +
+ llvm::utostr_32(T->getIndex()) + S;
+ else
+ S = T->getName()->getName().str() + S;
+}
+
+void TypePrinter::PrintSubstTemplateTypeParm(const SubstTemplateTypeParmType *T,
+ std::string &S) {
+ Print(T->getReplacementType(), S);
+}
+
+void TypePrinter::PrintTemplateSpecialization(
+ const TemplateSpecializationType *T,
+ std::string &S) {
+ std::string SpecString;
+
+ {
+ llvm::raw_string_ostream OS(SpecString);
+ T->getTemplateName().print(OS, Policy);
+ }
+
+ SpecString += TemplateSpecializationType::PrintTemplateArgumentList(
+ T->getArgs(),
+ T->getNumArgs(),
+ Policy);
+ if (S.empty())
+ S.swap(SpecString);
+ else
+ S = SpecString + ' ' + S;
+}
+
+void TypePrinter::PrintQualifiedName(const QualifiedNameType *T,
+ std::string &S) {
+ std::string MyString;
+
+ {
+ llvm::raw_string_ostream OS(MyString);
+ T->getQualifier()->print(OS, Policy);
+ }
+
+ std::string TypeStr;
+ PrintingPolicy InnerPolicy(Policy);
+ InnerPolicy.SuppressTagKind = true;
+ InnerPolicy.SuppressScope = true;
+ TypePrinter(InnerPolicy).Print(T->getNamedType(), TypeStr);
+
+ MyString += TypeStr;
+ if (S.empty())
+ S.swap(MyString);
+ else
+ S = MyString + ' ' + S;
+}
+
+void TypePrinter::PrintTypename(const TypenameType *T, std::string &S) {
+ std::string MyString;
+
+ {
+ llvm::raw_string_ostream OS(MyString);
+ OS << "typename ";
+ T->getQualifier()->print(OS, Policy);
+
+ if (const IdentifierInfo *Ident = T->getIdentifier())
+ OS << Ident->getName();
+ else if (const TemplateSpecializationType *Spec = T->getTemplateId()) {
+ Spec->getTemplateName().print(OS, Policy, true);
+ OS << TemplateSpecializationType::PrintTemplateArgumentList(
+ Spec->getArgs(),
+ Spec->getNumArgs(),
+ Policy);
+ }
+ }
+
+ if (S.empty())
+ S.swap(MyString);
+ else
+ S = MyString + ' ' + S;
+}
+
+void TypePrinter::PrintObjCInterface(const ObjCInterfaceType *T,
+ std::string &S) {
+ if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ S = ' ' + S;
+
+ std::string ObjCQIString = T->getDecl()->getNameAsString();
+ if (T->getNumProtocols()) {
+ ObjCQIString += '<';
+ bool isFirst = true;
+ for (ObjCInterfaceType::qual_iterator I = T->qual_begin(),
+ E = T->qual_end();
+ I != E; ++I) {
+ if (isFirst)
+ isFirst = false;
+ else
+ ObjCQIString += ',';
+ ObjCQIString += (*I)->getNameAsString();
+ }
+ ObjCQIString += '>';
+ }
+ S = ObjCQIString + S;
+}
+
+void TypePrinter::PrintObjCObjectPointer(const ObjCObjectPointerType *T,
+ std::string &S) {
+ std::string ObjCQIString;
+
+ if (T->isObjCIdType() || T->isObjCQualifiedIdType())
+ ObjCQIString = "id";
+ else if (T->isObjCClassType() || T->isObjCQualifiedClassType())
+ ObjCQIString = "Class";
+ else
+ ObjCQIString = T->getInterfaceDecl()->getNameAsString();
+
+ if (!T->qual_empty()) {
+ ObjCQIString += '<';
+ for (ObjCObjectPointerType::qual_iterator I = T->qual_begin(),
+ E = T->qual_end();
+ I != E; ++I) {
+ ObjCQIString += (*I)->getNameAsString();
+ if (I+1 != E)
+ ObjCQIString += ',';
+ }
+ ObjCQIString += '>';
+ }
+
+ T->getPointeeType().getLocalQualifiers().getAsStringInternal(ObjCQIString,
+ Policy);
+
+ if (!T->isObjCIdType() && !T->isObjCQualifiedIdType())
+ ObjCQIString += " *"; // Don't forget the implicit pointer.
+ else if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ S = ' ' + S;
+
+ S = ObjCQIString + S;
+}
+
+static void PrintTemplateArgument(std::string &Buffer,
+ const TemplateArgument &Arg,
+ const PrintingPolicy &Policy) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ assert(false && "Null template argument");
+ break;
+
+ case TemplateArgument::Type:
+ Arg.getAsType().getAsStringInternal(Buffer, Policy);
+ break;
+
+ case TemplateArgument::Declaration:
+ Buffer = cast<NamedDecl>(Arg.getAsDecl())->getNameAsString();
+ break;
+
+ case TemplateArgument::Template: {
+ llvm::raw_string_ostream s(Buffer);
+ Arg.getAsTemplate().print(s, Policy);
+ break;
+ }
+
+ case TemplateArgument::Integral:
+ Buffer = Arg.getAsIntegral()->toString(10, true);
+ break;
+
+ case TemplateArgument::Expression: {
+ llvm::raw_string_ostream s(Buffer);
+ Arg.getAsExpr()->printPretty(s, 0, Policy);
+ break;
+ }
+
+ case TemplateArgument::Pack:
+ assert(0 && "FIXME: Implement!");
+ break;
+ }
+}
+
+std::string
+TemplateSpecializationType::PrintTemplateArgumentList(
+ const TemplateArgument *Args,
+ unsigned NumArgs,
+ const PrintingPolicy &Policy) {
+ std::string SpecString;
+ SpecString += '<';
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+ if (Arg)
+ SpecString += ", ";
+
+ // Print the argument into a string.
+ std::string ArgString;
+ PrintTemplateArgument(ArgString, Args[Arg], Policy);
+
+ // If this is the first argument and its string representation
+ // begins with the global scope specifier ('::foo'), add a space
+ // to avoid printing the diagraph '<:'.
+ if (!Arg && !ArgString.empty() && ArgString[0] == ':')
+ SpecString += ' ';
+
+ SpecString += ArgString;
+ }
+
+ // If the last character of our string is '>', add another space to
+ // keep the two '>''s separate tokens. We don't *have* to do this in
+ // C++0x, but it's still good hygiene.
+ if (SpecString[SpecString.size() - 1] == '>')
+ SpecString += ' ';
+
+ SpecString += '>';
+
+ return SpecString;
+}
+
+// Sadly, repeat all that with TemplateArgLoc.
+std::string TemplateSpecializationType::
+PrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs,
+ const PrintingPolicy &Policy) {
+ std::string SpecString;
+ SpecString += '<';
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+ if (Arg)
+ SpecString += ", ";
+
+ // Print the argument into a string.
+ std::string ArgString;
+ PrintTemplateArgument(ArgString, Args[Arg].getArgument(), Policy);
+
+ // If this is the first argument and its string representation
+ // begins with the global scope specifier ('::foo'), add a space
+ // to avoid printing the diagraph '<:'.
+ if (!Arg && !ArgString.empty() && ArgString[0] == ':')
+ SpecString += ' ';
+
+ SpecString += ArgString;
+ }
+
+ // If the last character of our string is '>', add another space to
+ // keep the two '>''s separate tokens. We don't *have* to do this in
+ // C++0x, but it's still good hygiene.
+ if (SpecString[SpecString.size() - 1] == '>')
+ SpecString += ' ';
+
+ SpecString += '>';
+
+ return SpecString;
+}
+
+void QualType::dump(const char *msg) const {
+ std::string R = "identifier";
+ LangOptions LO;
+ getAsStringInternal(R, PrintingPolicy(LO));
+ if (msg)
+ fprintf(stderr, "%s: %s\n", msg, R.c_str());
+ else
+ fprintf(stderr, "%s\n", R.c_str());
+}
+void QualType::dump() const {
+ dump("");
+}
+
+void Type::dump() const {
+ QualType(this, 0).dump();
+}
+
+std::string Qualifiers::getAsString() const {
+ LangOptions LO;
+ return getAsString(PrintingPolicy(LO));
+}
+
+// Appends qualifiers to the given string, separated by spaces. Will
+// prefix a space if the string is non-empty. Will not append a final
+// space.
+void Qualifiers::getAsStringInternal(std::string &S,
+ const PrintingPolicy&) const {
+ AppendTypeQualList(S, getCVRQualifiers());
+ if (unsigned AddressSpace = getAddressSpace()) {
+ if (!S.empty()) S += ' ';
+ S += "__attribute__((address_space(";
+ S += llvm::utostr_32(AddressSpace);
+ S += ")))";
+ }
+ if (Qualifiers::GC GCAttrType = getObjCGCAttr()) {
+ if (!S.empty()) S += ' ';
+ S += "__attribute__((objc_gc(";
+ if (GCAttrType == Qualifiers::Weak)
+ S += "weak";
+ else
+ S += "strong";
+ S += ")))";
+ }
+}
+
+std::string QualType::getAsString() const {
+ std::string S;
+ LangOptions LO;
+ getAsStringInternal(S, PrintingPolicy(LO));
+ return S;
+}
+
+void QualType::getAsStringInternal(std::string &S,
+ const PrintingPolicy &Policy) const {
+ TypePrinter Printer(Policy);
+ Printer.Print(*this, S);
+}
+
diff --git a/lib/Analysis/AnalysisManager.cpp b/lib/Analysis/AnalysisManager.cpp
deleted file mode 100644
index c2733fa..0000000
--- a/lib/Analysis/AnalysisManager.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-//== AnalysisManager.cpp - Path sensitive analysis data manager ----*- C++ -*-//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the AnalysisManager class.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Analysis/PathSensitive/AnalysisManager.h"
-#include "clang/Basic/SourceManager.h"
-
-using namespace clang;
-
-void AnalysisManager::DisplayFunction(Decl *D) {
-
- if (DisplayedFunction)
- return;
-
- DisplayedFunction = true;
-
- // FIXME: Is getCodeDecl() always a named decl?
- if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
- const NamedDecl *ND = cast<NamedDecl>(D);
- SourceManager &SM = getASTContext().getSourceManager();
- (llvm::errs() << "ANALYZE: "
- << SM.getPresumedLoc(ND->getLocation()).getFilename()
- << ' ' << ND->getNameAsString() << '\n').flush();
- }
-}
-
diff --git a/lib/Analysis/ArrayBoundChecker.cpp b/lib/Analysis/ArrayBoundChecker.cpp
new file mode 100644
index 0000000..549a22b
--- /dev/null
+++ b/lib/Analysis/ArrayBoundChecker.cpp
@@ -0,0 +1,86 @@
+//== ArrayBoundChecker.cpp ------------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines ArrayBoundChecker, which is a path-sensitive check
+// which looks for an out-of-bound array element access.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN ArrayBoundChecker :
+ public CheckerVisitor<ArrayBoundChecker> {
+ BuiltinBug *BT;
+public:
+ ArrayBoundChecker() : BT(0) {}
+ static void *getTag();
+ void VisitLocation(CheckerContext &C, const Stmt *S, SVal l);
+};
+}
+
+void clang::RegisterArrayBoundChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new ArrayBoundChecker());
+}
+
+void *ArrayBoundChecker::getTag() {
+ static int x = 0; return &x;
+}
+
+void ArrayBoundChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l){
+ // Check for out of bound array element access.
+ const MemRegion *R = l.getAsRegion();
+ if (!R)
+ return;
+
+ R = R->StripCasts();
+
+ const ElementRegion *ER = dyn_cast<ElementRegion>(R);
+ if (!ER)
+ return;
+
+ // Get the index of the accessed element.
+ DefinedOrUnknownSVal &Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
+
+ const GRState *state = C.getState();
+
+ // Get the size of the array.
+ DefinedOrUnknownSVal NumElements
+ = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion());
+
+ const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true);
+ const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false);
+ if (StOutBound && !StInBound) {
+ ExplodedNode *N = C.GenerateNode(S, StOutBound, true);
+
+ if (!N)
+ return;
+
+ if (!BT)
+ BT = new BuiltinBug("Out-of-bound array access",
+ "Access out-of-bound array element (buffer overflow)");
+
+ // FIXME: It would be nice to eventually make this diagnostic more clear,
+ // e.g., by referencing the original declaration or by saying *why* this
+ // reference is outside the range.
+
+ // Generate a report for this bug.
+ RangedBugReport *report =
+ new RangedBugReport(*BT, BT->getDescription(), N);
+
+ report->addRange(S->getSourceRange());
+
+ C.EmitReport(report);
+ }
+}
diff --git a/lib/Analysis/AttrNonNullChecker.cpp b/lib/Analysis/AttrNonNullChecker.cpp
index 1cf5d0c..01e1a1f 100644
--- a/lib/Analysis/AttrNonNullChecker.cpp
+++ b/lib/Analysis/AttrNonNullChecker.cpp
@@ -12,14 +12,28 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "GRExprEngineInternalChecks.h"
using namespace clang;
-void *AttrNonNullChecker::getTag() {
- static int x = 0;
- return &x;
+namespace {
+class VISIBILITY_HIDDEN AttrNonNullChecker
+ : public CheckerVisitor<AttrNonNullChecker> {
+ BugType *BT;
+public:
+ AttrNonNullChecker() : BT(0) {}
+ static void *getTag() {
+ static int x = 0;
+ return &x;
+ }
+ void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+} // end anonymous namespace
+
+void clang::RegisterAttrNonNullChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new AttrNonNullChecker());
}
void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C,
diff --git a/lib/Analysis/BadCallChecker.cpp b/lib/Analysis/BadCallChecker.cpp
index 33bb515..7a7ea18 100644
--- a/lib/Analysis/BadCallChecker.cpp
+++ b/lib/Analysis/BadCallChecker.cpp
@@ -12,14 +12,27 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/Checkers/BadCallChecker.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "GRExprEngineInternalChecks.h"
using namespace clang;
-void *BadCallChecker::getTag() {
- static int x = 0;
- return &x;
+namespace {
+class VISIBILITY_HIDDEN BadCallChecker : public CheckerVisitor<BadCallChecker> {
+ BuiltinBug *BT;
+public:
+ BadCallChecker() : BT(0) {}
+ static void *getTag() {
+ static int x = 0;
+ return &x;
+ }
+ void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+} // end anonymous namespace
+
+void clang::RegisterBadCallChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new BadCallChecker());
}
void BadCallChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
@@ -29,11 +42,11 @@ void BadCallChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
if (L.isUndef() || isa<loc::ConcreteInt>(L)) {
if (ExplodedNode *N = C.GenerateNode(CE, true)) {
if (!BT)
- BT = new BuiltinBug(0, "Invalid function call",
+ BT = new BuiltinBug("Invalid function call",
"Called function pointer is a null or undefined pointer value");
EnhancedBugReport *R =
- new EnhancedBugReport(*BT, BT->getDescription().c_str(), N);
+ new EnhancedBugReport(*BT, BT->getDescription(), N);
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
bugreporter::GetCalleeExpr(N));
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp
index 4781d5e..c2ecfa1 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -384,7 +384,7 @@ bool AuditCFNumberCreate::Audit(ExplodedNode* N,GRStateManager&){
if (!LV)
return false;
- const TypedRegion* R = dyn_cast<TypedRegion>(LV->getBaseRegion());
+ const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts());
if (!R)
return false;
diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp
index 888af9b..800a76f 100644
--- a/lib/Analysis/BasicStore.cpp
+++ b/lib/Analysis/BasicStore.cpp
@@ -268,20 +268,6 @@ SValuator::CastResult BasicStoreManager::Retrieve(const GRState *state,
case loc::MemRegionKind: {
const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion();
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- // Just support void**, void***, intptr_t*, intptr_t**, etc., for now.
- // This is needed to handle OSCompareAndSwapPtr() and friends.
- ASTContext &Ctx = StateMgr.getContext();
- QualType T = ER->getLocationType(Ctx);
-
- if (!isHigherOrderRawPtr(T, Ctx))
- return SValuator::CastResult(state, UnknownVal());
-
- // FIXME: Should check for element 0.
- // Otherwise, strip the element region.
- R = ER->getSuperRegion();
- }
-
if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
return SValuator::CastResult(state, UnknownVal());
@@ -291,7 +277,8 @@ SValuator::CastResult BasicStoreManager::Retrieve(const GRState *state,
if (!Val)
break;
- return CastRetrievedVal(*Val, state, cast<TypedRegion>(R), T);
+ return SValuator::CastResult(state,
+ CastRetrievedVal(*Val, cast<TypedRegion>(R), T));
}
case loc::ConcreteIntKind:
@@ -624,7 +611,7 @@ const GRState *BasicStoreManager::InvalidateRegion(const GRState *state,
const Expr *E,
unsigned Count,
InvalidatedSymbols *IS) {
- R = R->getBaseRegion();
+ R = R->StripCasts();
if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
return state;
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index 03614e8..55e5f17 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -308,7 +308,234 @@ public:
}
};
+//===----------------------------------------------------------------------===//
+// Reference-counting logic (typestate + counts).
+//===----------------------------------------------------------------------===//
+class VISIBILITY_HIDDEN RefVal {
+public:
+ enum Kind {
+ Owned = 0, // Owning reference.
+ NotOwned, // Reference is not owned by still valid (not freed).
+ Released, // Object has been released.
+ ReturnedOwned, // Returned object passes ownership to caller.
+ ReturnedNotOwned, // Return object does not pass ownership to caller.
+ ERROR_START,
+ ErrorDeallocNotOwned, // -dealloc called on non-owned object.
+ ErrorDeallocGC, // Calling -dealloc with GC enabled.
+ ErrorUseAfterRelease, // Object used after released.
+ ErrorReleaseNotOwned, // Release of an object that was not owned.
+ ERROR_LEAK_START,
+ ErrorLeak, // A memory leak due to excessive reference counts.
+ ErrorLeakReturned, // A memory leak due to the returning method not having
+ // the correct naming conventions.
+ ErrorGCLeakReturned,
+ ErrorOverAutorelease,
+ ErrorReturnedNotOwned
+ };
+
+private:
+ Kind kind;
+ RetEffect::ObjKind okind;
+ unsigned Cnt;
+ unsigned ACnt;
+ QualType T;
+
+ RefVal(Kind k, RetEffect::ObjKind o, unsigned cnt, unsigned acnt, QualType t)
+ : kind(k), okind(o), Cnt(cnt), ACnt(acnt), T(t) {}
+
+ RefVal(Kind k, unsigned cnt = 0)
+ : kind(k), okind(RetEffect::AnyObj), Cnt(cnt), ACnt(0) {}
+
+public:
+ Kind getKind() const { return kind; }
+
+ RetEffect::ObjKind getObjKind() const { return okind; }
+
+ unsigned getCount() const { return Cnt; }
+ unsigned getAutoreleaseCount() const { return ACnt; }
+ unsigned getCombinedCounts() const { return Cnt + ACnt; }
+ void clearCounts() { Cnt = 0; ACnt = 0; }
+ void setCount(unsigned i) { Cnt = i; }
+ void setAutoreleaseCount(unsigned i) { ACnt = i; }
+
+ QualType getType() const { return T; }
+
+ // Useful predicates.
+
+ static bool isError(Kind k) { return k >= ERROR_START; }
+
+ static bool isLeak(Kind k) { return k >= ERROR_LEAK_START; }
+
+ bool isOwned() const {
+ return getKind() == Owned;
+ }
+
+ bool isNotOwned() const {
+ return getKind() == NotOwned;
+ }
+
+ bool isReturnedOwned() const {
+ return getKind() == ReturnedOwned;
+ }
+
+ bool isReturnedNotOwned() const {
+ return getKind() == ReturnedNotOwned;
+ }
+
+ bool isNonLeakError() const {
+ Kind k = getKind();
+ return isError(k) && !isLeak(k);
+ }
+
+ static RefVal makeOwned(RetEffect::ObjKind o, QualType t,
+ unsigned Count = 1) {
+ return RefVal(Owned, o, Count, 0, t);
+ }
+
+ static RefVal makeNotOwned(RetEffect::ObjKind o, QualType t,
+ unsigned Count = 0) {
+ return RefVal(NotOwned, o, Count, 0, t);
+ }
+
+ // Comparison, profiling, and pretty-printing.
+
+ bool operator==(const RefVal& X) const {
+ return kind == X.kind && Cnt == X.Cnt && T == X.T && ACnt == X.ACnt;
+ }
+
+ RefVal operator-(size_t i) const {
+ return RefVal(getKind(), getObjKind(), getCount() - i,
+ getAutoreleaseCount(), getType());
+ }
+
+ RefVal operator+(size_t i) const {
+ return RefVal(getKind(), getObjKind(), getCount() + i,
+ getAutoreleaseCount(), getType());
+ }
+
+ RefVal operator^(Kind k) const {
+ return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(),
+ getType());
+ }
+
+ RefVal autorelease() const {
+ return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1,
+ getType());
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.AddInteger((unsigned) kind);
+ ID.AddInteger(Cnt);
+ ID.AddInteger(ACnt);
+ ID.Add(T);
+ }
+
+ void print(llvm::raw_ostream& Out) const;
+};
+
+void RefVal::print(llvm::raw_ostream& Out) const {
+ if (!T.isNull())
+ Out << "Tracked Type:" << T.getAsString() << '\n';
+
+ switch (getKind()) {
+ default: assert(false);
+ case Owned: {
+ Out << "Owned";
+ unsigned cnt = getCount();
+ if (cnt) Out << " (+ " << cnt << ")";
+ break;
+ }
+
+ case NotOwned: {
+ Out << "NotOwned";
+ unsigned cnt = getCount();
+ if (cnt) Out << " (+ " << cnt << ")";
+ break;
+ }
+
+ case ReturnedOwned: {
+ Out << "ReturnedOwned";
+ unsigned cnt = getCount();
+ if (cnt) Out << " (+ " << cnt << ")";
+ break;
+ }
+
+ case ReturnedNotOwned: {
+ Out << "ReturnedNotOwned";
+ unsigned cnt = getCount();
+ if (cnt) Out << " (+ " << cnt << ")";
+ break;
+ }
+
+ case Released:
+ Out << "Released";
+ break;
+
+ case ErrorDeallocGC:
+ Out << "-dealloc (GC)";
+ break;
+
+ case ErrorDeallocNotOwned:
+ Out << "-dealloc (not-owned)";
+ break;
+
+ case ErrorLeak:
+ Out << "Leaked";
+ break;
+
+ case ErrorLeakReturned:
+ Out << "Leaked (Bad naming)";
+ break;
+
+ case ErrorGCLeakReturned:
+ Out << "Leaked (GC-ed at return)";
+ break;
+
+ case ErrorUseAfterRelease:
+ Out << "Use-After-Release [ERROR]";
+ break;
+
+ case ErrorReleaseNotOwned:
+ Out << "Release of Not-Owned [ERROR]";
+ break;
+
+ case RefVal::ErrorOverAutorelease:
+ Out << "Over autoreleased";
+ break;
+
+ case RefVal::ErrorReturnedNotOwned:
+ Out << "Non-owned object returned instead of owned";
+ break;
+ }
+
+ if (ACnt) {
+ Out << " [ARC +" << ACnt << ']';
+ }
+}
+} //end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// RefBindings - State used to track object reference counts.
+//===----------------------------------------------------------------------===//
+
+typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings;
+
+namespace clang {
+ template<>
+ struct GRStateTrait<RefBindings> : public GRStatePartialTrait<RefBindings> {
+ static void* GDMIndex() {
+ static int RefBIndex = 0;
+ return &RefBIndex;
+ }
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// Summaries
+//===----------------------------------------------------------------------===//
+
+namespace {
class VISIBILITY_HIDDEN RetainSummary {
/// Args - an ordered vector of (index, ArgEffect) pairs, where index
/// specifies the argument (starting from 0). This can be sparsely
@@ -757,7 +984,11 @@ public:
RetainSummary* getSummary(FunctionDecl* FD);
- RetainSummary* getInstanceMethodSummary(ObjCMessageExpr* ME,
+ RetainSummary *getInstanceMethodSummary(const ObjCMessageExpr *ME,
+ const GRState *state,
+ const LocationContext *LC);
+
+ RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME,
const ObjCInterfaceDecl* ID) {
return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(),
ID, ME->getMethodDecl(), ME->getType());
@@ -773,7 +1004,7 @@ public:
const ObjCMethodDecl *MD,
QualType RetTy);
- RetainSummary *getClassMethodSummary(ObjCMessageExpr *ME) {
+ RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) {
return getClassMethodSummary(ME->getSelector(), ME->getClassName(),
ME->getClassInfo().first,
ME->getMethodDecl(), ME->getType());
@@ -1306,7 +1537,7 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
E = MD->param_end(); I != E; ++I, ++i)
if (ParmVarDecl *PD = *I) {
QualType Ty = Ctx.getCanonicalType(PD->getType());
- if (Ty.getUnqualifiedType() == Ctx.VoidPtrTy)
+ if (Ty.getLocalUnqualifiedType() == Ctx.VoidPtrTy)
ScratchArgs = AF.Add(ScratchArgs, i, StopTracking);
}
}
@@ -1350,6 +1581,61 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
}
RetainSummary*
+RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME,
+ const GRState *state,
+ const LocationContext *LC) {
+
+ // We need the type-information of the tracked receiver object
+ // Retrieve it from the state.
+ const Expr *Receiver = ME->getReceiver();
+ const ObjCInterfaceDecl* ID = 0;
+
+ // FIXME: Is this really working as expected? There are cases where
+ // we just use the 'ID' from the message expression.
+ SVal receiverV = state->getSValAsScalarOrLoc(Receiver);
+
+ // FIXME: Eventually replace the use of state->get<RefBindings> with
+ // a generic API for reasoning about the Objective-C types of symbolic
+ // objects.
+ if (SymbolRef Sym = receiverV.getAsLocSymbol())
+ if (const RefVal *T = state->get<RefBindings>(Sym))
+ if (const ObjCObjectPointerType* PT =
+ T->getType()->getAs<ObjCObjectPointerType>())
+ ID = PT->getInterfaceDecl();
+
+ // FIXME: this is a hack. This may or may not be the actual method
+ // that is called.
+ if (!ID) {
+ if (const ObjCObjectPointerType *PT =
+ Receiver->getType()->getAs<ObjCObjectPointerType>())
+ ID = PT->getInterfaceDecl();
+ }
+
+ // FIXME: The receiver could be a reference to a class, meaning that
+ // we should use the class method.
+ RetainSummary *Summ = getInstanceMethodSummary(ME, ID);
+
+ // Special-case: are we sending a mesage to "self"?
+ // This is a hack. When we have full-IP this should be removed.
+ if (isa<ObjCMethodDecl>(LC->getDecl())) {
+ if (const loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&receiverV)) {
+ // Get the region associated with 'self'.
+ if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) {
+ SVal SelfVal = state->getSVal(state->getRegion(SelfDecl, LC));
+ if (L->StripCasts() == SelfVal.getAsRegion()) {
+ // Update the summary to make the default argument effect
+ // 'StopTracking'.
+ Summ = copySummary(Summ);
+ Summ->setDefaultArgEffect(StopTracking);
+ }
+ }
+ }
+ }
+
+ return Summ ? Summ : getDefaultSummary();
+}
+
+RetainSummary*
RetainSummaryManager::getInstanceMethodSummary(Selector S,
IdentifierInfo *ClsName,
const ObjCInterfaceDecl* ID,
@@ -1569,230 +1855,6 @@ void RetainSummaryManager::InitializeMethodSummaries() {
}
//===----------------------------------------------------------------------===//
-// Reference-counting logic (typestate + counts).
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class VISIBILITY_HIDDEN RefVal {
-public:
- enum Kind {
- Owned = 0, // Owning reference.
- NotOwned, // Reference is not owned by still valid (not freed).
- Released, // Object has been released.
- ReturnedOwned, // Returned object passes ownership to caller.
- ReturnedNotOwned, // Return object does not pass ownership to caller.
- ERROR_START,
- ErrorDeallocNotOwned, // -dealloc called on non-owned object.
- ErrorDeallocGC, // Calling -dealloc with GC enabled.
- ErrorUseAfterRelease, // Object used after released.
- ErrorReleaseNotOwned, // Release of an object that was not owned.
- ERROR_LEAK_START,
- ErrorLeak, // A memory leak due to excessive reference counts.
- ErrorLeakReturned, // A memory leak due to the returning method not having
- // the correct naming conventions.
- ErrorGCLeakReturned,
- ErrorOverAutorelease,
- ErrorReturnedNotOwned
- };
-
-private:
- Kind kind;
- RetEffect::ObjKind okind;
- unsigned Cnt;
- unsigned ACnt;
- QualType T;
-
- RefVal(Kind k, RetEffect::ObjKind o, unsigned cnt, unsigned acnt, QualType t)
- : kind(k), okind(o), Cnt(cnt), ACnt(acnt), T(t) {}
-
- RefVal(Kind k, unsigned cnt = 0)
- : kind(k), okind(RetEffect::AnyObj), Cnt(cnt), ACnt(0) {}
-
-public:
- Kind getKind() const { return kind; }
-
- RetEffect::ObjKind getObjKind() const { return okind; }
-
- unsigned getCount() const { return Cnt; }
- unsigned getAutoreleaseCount() const { return ACnt; }
- unsigned getCombinedCounts() const { return Cnt + ACnt; }
- void clearCounts() { Cnt = 0; ACnt = 0; }
- void setCount(unsigned i) { Cnt = i; }
- void setAutoreleaseCount(unsigned i) { ACnt = i; }
-
- QualType getType() const { return T; }
-
- // Useful predicates.
-
- static bool isError(Kind k) { return k >= ERROR_START; }
-
- static bool isLeak(Kind k) { return k >= ERROR_LEAK_START; }
-
- bool isOwned() const {
- return getKind() == Owned;
- }
-
- bool isNotOwned() const {
- return getKind() == NotOwned;
- }
-
- bool isReturnedOwned() const {
- return getKind() == ReturnedOwned;
- }
-
- bool isReturnedNotOwned() const {
- return getKind() == ReturnedNotOwned;
- }
-
- bool isNonLeakError() const {
- Kind k = getKind();
- return isError(k) && !isLeak(k);
- }
-
- static RefVal makeOwned(RetEffect::ObjKind o, QualType t,
- unsigned Count = 1) {
- return RefVal(Owned, o, Count, 0, t);
- }
-
- static RefVal makeNotOwned(RetEffect::ObjKind o, QualType t,
- unsigned Count = 0) {
- return RefVal(NotOwned, o, Count, 0, t);
- }
-
- // Comparison, profiling, and pretty-printing.
-
- bool operator==(const RefVal& X) const {
- return kind == X.kind && Cnt == X.Cnt && T == X.T && ACnt == X.ACnt;
- }
-
- RefVal operator-(size_t i) const {
- return RefVal(getKind(), getObjKind(), getCount() - i,
- getAutoreleaseCount(), getType());
- }
-
- RefVal operator+(size_t i) const {
- return RefVal(getKind(), getObjKind(), getCount() + i,
- getAutoreleaseCount(), getType());
- }
-
- RefVal operator^(Kind k) const {
- return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(),
- getType());
- }
-
- RefVal autorelease() const {
- return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1,
- getType());
- }
-
- void Profile(llvm::FoldingSetNodeID& ID) const {
- ID.AddInteger((unsigned) kind);
- ID.AddInteger(Cnt);
- ID.AddInteger(ACnt);
- ID.Add(T);
- }
-
- void print(llvm::raw_ostream& Out) const;
-};
-
-void RefVal::print(llvm::raw_ostream& Out) const {
- if (!T.isNull())
- Out << "Tracked Type:" << T.getAsString() << '\n';
-
- switch (getKind()) {
- default: assert(false);
- case Owned: {
- Out << "Owned";
- unsigned cnt = getCount();
- if (cnt) Out << " (+ " << cnt << ")";
- break;
- }
-
- case NotOwned: {
- Out << "NotOwned";
- unsigned cnt = getCount();
- if (cnt) Out << " (+ " << cnt << ")";
- break;
- }
-
- case ReturnedOwned: {
- Out << "ReturnedOwned";
- unsigned cnt = getCount();
- if (cnt) Out << " (+ " << cnt << ")";
- break;
- }
-
- case ReturnedNotOwned: {
- Out << "ReturnedNotOwned";
- unsigned cnt = getCount();
- if (cnt) Out << " (+ " << cnt << ")";
- break;
- }
-
- case Released:
- Out << "Released";
- break;
-
- case ErrorDeallocGC:
- Out << "-dealloc (GC)";
- break;
-
- case ErrorDeallocNotOwned:
- Out << "-dealloc (not-owned)";
- break;
-
- case ErrorLeak:
- Out << "Leaked";
- break;
-
- case ErrorLeakReturned:
- Out << "Leaked (Bad naming)";
- break;
-
- case ErrorGCLeakReturned:
- Out << "Leaked (GC-ed at return)";
- break;
-
- case ErrorUseAfterRelease:
- Out << "Use-After-Release [ERROR]";
- break;
-
- case ErrorReleaseNotOwned:
- Out << "Release of Not-Owned [ERROR]";
- break;
-
- case RefVal::ErrorOverAutorelease:
- Out << "Over autoreleased";
- break;
-
- case RefVal::ErrorReturnedNotOwned:
- Out << "Non-owned object returned instead of owned";
- break;
- }
-
- if (ACnt) {
- Out << " [ARC +" << ACnt << ']';
- }
-}
-
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
-// RefBindings - State used to track object reference counts.
-//===----------------------------------------------------------------------===//
-
-typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings;
-static int RefBIndex = 0;
-
-namespace clang {
- template<>
- struct GRStateTrait<RefBindings> : public GRStatePartialTrait<RefBindings> {
- static inline void* GDMIndex() { return &RefBIndex; }
- };
-}
-
-//===----------------------------------------------------------------------===//
// AutoreleaseBindings - State used to track objects in autorelease pools.
//===----------------------------------------------------------------------===//
@@ -3004,69 +3066,14 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
GRStmtNodeBuilder& Builder,
ObjCMessageExpr* ME,
ExplodedNode* Pred) {
- RetainSummary* Summ = 0;
-
- if (Expr* Receiver = ME->getReceiver()) {
- // We need the type-information of the tracked receiver object
- // Retrieve it from the state.
- const ObjCInterfaceDecl* ID = 0;
-
- // FIXME: Wouldn't it be great if this code could be reduced? It's just
- // a chain of lookups.
- // FIXME: Is this really working as expected? There are cases where
- // we just use the 'ID' from the message expression.
- const GRState* St = Builder.GetState(Pred);
- SVal V = St->getSValAsScalarOrLoc(Receiver);
-
- SymbolRef Sym = V.getAsLocSymbol();
-
- if (Sym) {
- if (const RefVal* T = St->get<RefBindings>(Sym)) {
- if (const ObjCObjectPointerType* PT =
- T->getType()->getAs<ObjCObjectPointerType>())
- ID = PT->getInterfaceDecl();
- }
- }
-
- // FIXME: this is a hack. This may or may not be the actual method
- // that is called.
- if (!ID) {
- if (const ObjCObjectPointerType *PT =
- Receiver->getType()->getAs<ObjCObjectPointerType>())
- ID = PT->getInterfaceDecl();
- }
-
- // FIXME: The receiver could be a reference to a class, meaning that
- // we should use the class method.
- Summ = Summaries.getInstanceMethodSummary(ME, ID);
-
- // Special-case: are we sending a mesage to "self"?
- // This is a hack. When we have full-IP this should be removed.
- if (isa<ObjCMethodDecl>(Pred->getLocationContext()->getDecl())) {
- if (Expr* Receiver = ME->getReceiver()) {
- SVal X = St->getSValAsScalarOrLoc(Receiver);
- if (loc::MemRegionVal* L = dyn_cast<loc::MemRegionVal>(&X)) {
- // Get the region associated with 'self'.
- const LocationContext *LC = Pred->getLocationContext();
- if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) {
- SVal SelfVal = St->getSVal(St->getRegion(SelfDecl, LC));
- if (L->getBaseRegion() == SelfVal.getAsRegion()) {
- // Update the summary to make the default argument effect
- // 'StopTracking'.
- Summ = Summaries.copySummary(Summ);
- Summ->setDefaultArgEffect(StopTracking);
- }
- }
- }
- }
- }
- }
- else
- Summ = Summaries.getClassMethodSummary(ME);
-
- if (!Summ)
- Summ = Summaries.getDefaultSummary();
+
+ RetainSummary *Summ =
+ ME->getReceiver()
+ ? Summaries.getInstanceMethodSummary(ME, Builder.GetState(Pred),
+ Pred->getLocationContext())
+ : Summaries.getClassMethodSummary(ME);
+ assert(Summ && "RetainSummary is null");
EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ,
ME->arg_begin(), ME->arg_end(), Pred);
}
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index cd4697f..8e8c1e7 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -2,7 +2,7 @@ set(LLVM_NO_RTTI 1)
add_clang_library(clangAnalysis
AnalysisContext.cpp
- AnalysisManager.cpp
+ ArrayBoundChecker.cpp
AttrNonNullChecker.cpp
BadCallChecker.cpp
BasicConstraintManager.cpp
@@ -15,27 +15,39 @@ add_clang_library(clangAnalysis
CFRefCount.cpp
CallGraph.cpp
CallInliner.cpp
+ CastToStructChecker.cpp
CheckDeadStores.cpp
CheckObjCDealloc.cpp
CheckObjCInstMethSignature.cpp
CheckObjCUnusedIVars.cpp
CheckSecuritySyntaxOnly.cpp
+ CheckSizeofPointer.cpp
DereferenceChecker.cpp
DivZeroChecker.cpp
Environment.cpp
ExplodedGraph.cpp
+ FixedAddressChecker.cpp
GRBlockCounter.cpp
GRCoreEngine.cpp
GRExprEngine.cpp
+ GRExprEngineExperimentalChecks.cpp
GRExprEngineInternalChecks.cpp
GRState.cpp
LiveVariables.cpp
+ MallocChecker.cpp
+ ManagerRegistry.cpp
MemRegion.cpp
NSAutoreleasePoolChecker.cpp
NSErrorChecker.cpp
PathDiagnostic.cpp
+ PointerArithChecker.cpp
+ PointerSubChecker.cpp
+ PthreadLockChecker.cpp
RangeConstraintManager.cpp
RegionStore.cpp
+ ReturnPointerRangeChecker.cpp
+ ReturnStackAddressChecker.cpp
+ ReturnUndefChecker.cpp
SVals.cpp
SValuator.cpp
SimpleConstraintManager.cpp
@@ -43,10 +55,11 @@ add_clang_library(clangAnalysis
Store.cpp
SymbolManager.cpp
UndefinedArgChecker.cpp
+ UndefinedArraySubscriptChecker.cpp
UndefinedAssignmentChecker.cpp
UninitializedValues.cpp
- ValueManager.cpp
VLASizeChecker.cpp
+ ValueManager.cpp
)
add_dependencies(clangAnalysis ClangDiagnosticAnalysis)
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
index 17dc068..06e3317 100644
--- a/lib/Analysis/CallGraph.cpp
+++ b/lib/Analysis/CallGraph.cpp
@@ -117,7 +117,7 @@ void CallGraph::print(llvm::raw_ostream &os) {
<< " calls:\n";
for (CallGraphNode::iterator CI = I->second->begin(),
CE = I->second->end(); CI != CE; ++CI) {
- os << " " << CI->second->getName().c_str();
+ os << " " << CI->second->getName();
}
os << '\n';
}
diff --git a/lib/Analysis/CastToStructChecker.cpp b/lib/Analysis/CastToStructChecker.cpp
new file mode 100644
index 0000000..ccd4a33
--- /dev/null
+++ b/lib/Analysis/CastToStructChecker.cpp
@@ -0,0 +1,77 @@
+//=== CastToStructChecker.cpp - Fixed address usage checker ----*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This files defines CastToStructChecker, a builtin checker that checks for
+// assignment of a fixed address to a pointer.
+// This check corresponds to CWE-588.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "GRExprEngineInternalChecks.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN CastToStructChecker
+ : public CheckerVisitor<CastToStructChecker> {
+ BuiltinBug *BT;
+public:
+ CastToStructChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitCastExpr(CheckerContext &C, const CastExpr *B);
+};
+}
+
+void *CastToStructChecker::getTag() {
+ static int x;
+ return &x;
+}
+
+void CastToStructChecker::PreVisitCastExpr(CheckerContext &C,
+ const CastExpr *CE) {
+ const Expr *E = CE->getSubExpr();
+ ASTContext &Ctx = C.getASTContext();
+ QualType OrigTy = Ctx.getCanonicalType(E->getType());
+ QualType ToTy = Ctx.getCanonicalType(CE->getType());
+
+ PointerType *OrigPTy = dyn_cast<PointerType>(OrigTy.getTypePtr());
+ PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
+
+ if (!ToPTy || !OrigPTy)
+ return;
+
+ QualType OrigPointeeTy = OrigPTy->getPointeeType();
+ QualType ToPointeeTy = ToPTy->getPointeeType();
+
+ if (!ToPointeeTy->isStructureType())
+ return;
+
+ // We allow cast from void*.
+ if (OrigPointeeTy->isVoidType())
+ return;
+
+ // Now the cast-to-type is struct pointer, the original type is not void*.
+ if (!OrigPointeeTy->isRecordType()) {
+ if (ExplodedNode *N = C.GenerateNode(CE)) {
+ if (!BT)
+ BT = new BuiltinBug("Cast from non-struct type to struct type",
+ "Casting a non-structure type to a structure type "
+ "and accessing a field can lead to memory access "
+ "errors or data corruption.");
+ RangedBugReport *R = new RangedBugReport(*BT,BT->getDescription(), N);
+ R->addRange(CE->getSourceRange());
+ C.EmitReport(R);
+ }
+ }
+}
+
+void clang::RegisterCastToStructChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new CastToStructChecker());
+}
diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
index 9f0d059..f1b9c21 100644
--- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp
+++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
@@ -23,6 +23,7 @@ namespace {
class VISIBILITY_HIDDEN WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
IdentifierInfo *II_gets;
+ IdentifierInfo *II_getpw;
enum { num_rands = 9 };
IdentifierInfo *II_rand[num_rands];
IdentifierInfo *II_random;
@@ -31,7 +32,7 @@ class VISIBILITY_HIDDEN WalkAST : public StmtVisitor<WalkAST> {
public:
WalkAST(BugReporter &br) : BR(br),
- II_gets(0), II_rand(), II_random(0), II_setid() {}
+ II_gets(0), II_getpw(0), II_rand(), II_random(0), II_setid() {}
// Statement visitor methods.
void VisitCallExpr(CallExpr *CE);
@@ -47,6 +48,7 @@ public:
// Checker-specific methods.
void CheckLoopConditionForFloat(const ForStmt *FS);
void CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD);
+ void CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
void CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD);
void CheckCall_random(const CallExpr *CE, const FunctionDecl *FD);
void CheckUncheckedReturnValue(CallExpr *CE);
@@ -77,6 +79,7 @@ void WalkAST::VisitChildren(Stmt *S) {
void WalkAST::VisitCallExpr(CallExpr *CE) {
if (const FunctionDecl *FD = CE->getDirectCallee()) {
CheckCall_gets(CE, FD);
+ CheckCall_getpw(CE, FD);
CheckCall_rand(CE, FD);
CheckCall_random(CE, FD);
}
@@ -215,22 +218,23 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
// Check: Any use of 'gets' is insecure.
// Originally: <rdar://problem/6335715>
// Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
+// CWE-242: Use of Inherently Dangerous Function
//===----------------------------------------------------------------------===//
void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
if (FD->getIdentifier() != GetIdentifier(II_gets, "gets"))
return;
- const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FD->getType());
- if (!FTP)
+ const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType());
+ if (!FPT)
return;
// Verify that the function takes a single argument.
- if (FTP->getNumArgs() != 1)
+ if (FPT->getNumArgs() != 1)
return;
// Is the argument a 'char*'?
- const PointerType *PT = dyn_cast<PointerType>(FTP->getArgType(0));
+ const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
if (!PT)
return;
@@ -247,6 +251,44 @@ void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
}
//===----------------------------------------------------------------------===//
+// Check: Any use of 'getpwd' is insecure.
+// CWE-477: Use of Obsolete Functions
+//===----------------------------------------------------------------------===//
+
+void WalkAST::CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
+ if (FD->getIdentifier() != GetIdentifier(II_getpw, "getpw"))
+ return;
+
+ const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType());
+ if (!FPT)
+ return;
+
+ // Verify that the function takes two arguments.
+ if (FPT->getNumArgs() != 2)
+ return;
+
+ // Verify the first argument type is integer.
+ if (!FPT->getArgType(0)->isIntegerType())
+ return;
+
+ // Verify the second argument type is char*.
+ const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(1));
+ if (!PT)
+ return;
+
+ if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
+ return;
+
+ // Issue a warning.
+ SourceRange R = CE->getCallee()->getSourceRange();
+ BR.EmitBasicReport("Potential buffer overflow in call to 'getpw'",
+ "Security",
+ "The getpw() function is dangerous as it may overflow the "
+ "provided buffer. It is obsoleted by getpwuid().",
+ CE->getLocStart(), &R, 1);
+}
+
+//===----------------------------------------------------------------------===//
// Check: Linear congruent random number generators should not be used
// Originally: <rdar://problem/63371000>
// CWE-338: Use of cryptographically weak prng
diff --git a/lib/Analysis/CheckSizeofPointer.cpp b/lib/Analysis/CheckSizeofPointer.cpp
new file mode 100644
index 0000000..174beef
--- /dev/null
+++ b/lib/Analysis/CheckSizeofPointer.cpp
@@ -0,0 +1,72 @@
+//==- CheckSizeofPointer.cpp - Check for sizeof on pointers ------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a check for unintended use of sizeof() on pointer
+// expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/LocalCheckers.h"
+#include "llvm/Support/Compiler.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN WalkAST : public StmtVisitor<WalkAST> {
+ BugReporter &BR;
+
+public:
+ WalkAST(BugReporter &br) : BR(br) {}
+ void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
+ void VisitStmt(Stmt *S) { VisitChildren(S); }
+ void VisitChildren(Stmt *S);
+};
+}
+
+void WalkAST::VisitChildren(Stmt *S) {
+ for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
+ if (Stmt *child = *I)
+ Visit(child);
+}
+
+// CWE-467: Use of sizeof() on a Pointer Type
+void WalkAST::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+ if (!E->isSizeOf())
+ return;
+
+ // If an explicit type is used in the code, usually the coder knows what he is
+ // doing.
+ if (E->isArgumentType())
+ return;
+
+ QualType T = E->getTypeOfArgument();
+ if (T->isPointerType()) {
+
+ // Many false positives have the form 'sizeof *p'. This is reasonable
+ // because people know what they are doing when they intentionally
+ // dereference the pointer.
+ Expr *ArgEx = E->getArgumentExpr();
+ if (!isa<DeclRefExpr>(ArgEx->IgnoreParens()))
+ return;
+
+ SourceRange R = ArgEx->getSourceRange();
+ BR.EmitBasicReport("Potential unintended use of sizeof() on pointer type",
+ "Logic",
+ "The code calls sizeof() on a pointer type. "
+ "This can produce an unexpected result.",
+ E->getLocStart(), &R, 1);
+ }
+}
+
+void clang::CheckSizeofPointer(const Decl *D, BugReporter &BR) {
+ WalkAST walker(BR);
+ walker.Visit(D->getBody());
+}
diff --git a/lib/Analysis/DereferenceChecker.cpp b/lib/Analysis/DereferenceChecker.cpp
index 33c85d5..c3aa8f3 100644
--- a/lib/Analysis/DereferenceChecker.cpp
+++ b/lib/Analysis/DereferenceChecker.cpp
@@ -13,100 +13,103 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h"
+#include "clang/Analysis/PathSensitive/Checker.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "GRExprEngineInternalChecks.h"
using namespace clang;
-void *NullDerefChecker::getTag() {
- static int x = 0;
- return &x;
-}
-
-ExplodedNode *NullDerefChecker::CheckLocation(const Stmt *S, ExplodedNode *Pred,
- const GRState *state, SVal V,
- GRExprEngine &Eng) {
- Loc *LV = dyn_cast<Loc>(&V);
-
- // If the value is not a location, don't touch the node.
- if (!LV)
- return Pred;
-
- const GRState *NotNullState = state->Assume(*LV, true);
- const GRState *NullState = state->Assume(*LV, false);
+namespace {
+class VISIBILITY_HIDDEN DereferenceChecker : public Checker {
+ BuiltinBug *BT_null;
+ BuiltinBug *BT_undef;
+ llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes;
+public:
+ DereferenceChecker() : BT_null(0), BT_undef(0) {}
+ static void *getTag() { static int tag = 0; return &tag; }
+ void VisitLocation(CheckerContext &C, const Stmt *S, SVal location);
- GRStmtNodeBuilder &Builder = Eng.getBuilder();
- BugReporter &BR = Eng.getBugReporter();
-
- // The explicit NULL case.
- if (NullState) {
- // Use the GDM to mark in the state what lval was null.
- const SVal *PersistentLV = Eng.getBasicVals().getPersistentSVal(*LV);
- NullState = NullState->set<GRState::NullDerefTag>(PersistentLV);
-
- ExplodedNode *N = Builder.generateNode(S, NullState, Pred,
- ProgramPoint::PostNullCheckFailedKind);
- if (N) {
- N->markAsSink();
-
- if (!NotNullState) { // Explicit null case.
- if (!BT)
- BT = new BuiltinBug(NULL, "Null dereference",
- "Dereference of null pointer");
-
- EnhancedBugReport *R =
- new EnhancedBugReport(*BT, BT->getDescription().c_str(), N);
-
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- bugreporter::GetDerefExpr(N));
-
- BR.EmitReport(R);
-
- return 0;
- } else // Implicit null case.
- ImplicitNullDerefNodes.push_back(N);
- }
+ std::pair<ExplodedNode * const*, ExplodedNode * const*>
+ getImplicitNodes() const {
+ return std::make_pair(ImplicitNullDerefNodes.data(),
+ ImplicitNullDerefNodes.data() +
+ ImplicitNullDerefNodes.size());
}
-
- if (!NotNullState)
- return 0;
+};
+} // end anonymous namespace
- return Builder.generateNode(S, NotNullState, Pred,
- ProgramPoint::PostLocationChecksSucceedKind);
+void clang::RegisterDereferenceChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new DereferenceChecker());
}
-
-void *UndefDerefChecker::getTag() {
- static int x = 0;
- return &x;
+std::pair<ExplodedNode * const *, ExplodedNode * const *>
+clang::GetImplicitNullDereferences(GRExprEngine &Eng) {
+ DereferenceChecker *checker = Eng.getChecker<DereferenceChecker>();
+ if (!checker)
+ return std::make_pair((ExplodedNode * const *) 0,
+ (ExplodedNode * const *) 0);
+ return checker->getImplicitNodes();
}
-ExplodedNode *UndefDerefChecker::CheckLocation(const Stmt *S,
- ExplodedNode *Pred,
- const GRState *state, SVal V,
- GRExprEngine &Eng) {
- GRStmtNodeBuilder &Builder = Eng.getBuilder();
- BugReporter &BR = Eng.getBugReporter();
-
- if (V.isUndef()) {
- ExplodedNode *N = Builder.generateNode(S, state, Pred,
- ProgramPoint::PostUndefLocationCheckFailedKind);
+void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
+ SVal l) {
+ // Check for dereference of an undefined value.
+ if (l.isUndef()) {
+ ExplodedNode *N = C.GenerateNode(S, true);
if (N) {
- N->markAsSink();
+ if (!BT_undef)
+ BT_undef = new BuiltinBug("Dereference of undefined pointer value");
+
+ EnhancedBugReport *report =
+ new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ bugreporter::GetDerefExpr(N));
+ C.EmitReport(report);
+ }
+ return;
+ }
+
+ DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);
+
+ // Check for null dereferences.
+ if (!isa<Loc>(location))
+ return;
+
+ const GRState *state = C.getState();
+ const GRState *notNullState, *nullState;
+ llvm::tie(notNullState, nullState) = state->Assume(location);
+
+ // The explicit NULL case.
+ if (nullState) {
+ // Generate an error node.
+ ExplodedNode *N = C.GenerateNode(S, nullState, true);
+ if (N) {
+ if (!notNullState) {
+ // We know that 'location' cannot be non-null. This is what
+ // we call an "explicit" null dereference.
+ if (!BT_null)
+ BT_null = new BuiltinBug("Null pointer dereference",
+ "Dereference of null pointer");
- if (!BT)
- BT = new BuiltinBug(0, "Undefined dereference",
- "Dereference of undefined pointer value");
+ EnhancedBugReport *report =
+ new EnhancedBugReport(*BT_null, BT_null->getDescription(), N);
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ bugreporter::GetDerefExpr(N));
+
+ C.EmitReport(report);
+ return;
+ }
- EnhancedBugReport *R =
- new EnhancedBugReport(*BT, BT->getDescription().c_str(), N);
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- bugreporter::GetDerefExpr(N));
- BR.EmitReport(R);
+ // Otherwise, we have the case where the location could either be
+ // null or not-null. Record the error node as an "implicit" null
+ // dereference.
+ ImplicitNullDerefNodes.push_back(N);
}
- return 0;
}
-
- return Pred;
+
+ // From this point forward, we know that the location is not null.
+ assert(notNullState);
+ C.addTransition(state != nullState ? C.GenerateNode(S, notNullState) :
+ C.getPredecessor());
}
-
diff --git a/lib/Analysis/DivZeroChecker.cpp b/lib/Analysis/DivZeroChecker.cpp
index 9c2359f..a8630f1 100644
--- a/lib/Analysis/DivZeroChecker.cpp
+++ b/lib/Analysis/DivZeroChecker.cpp
@@ -12,10 +12,25 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/Checkers/DivZeroChecker.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "GRExprEngineInternalChecks.h"
using namespace clang;
+namespace {
+class VISIBILITY_HIDDEN DivZeroChecker : public CheckerVisitor<DivZeroChecker> {
+ BuiltinBug *BT;
+public:
+ DivZeroChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+};
+} // end anonymous namespace
+
+void clang::RegisterDivZeroChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new DivZeroChecker());
+}
+
void *DivZeroChecker::getTag() {
static int x;
return &x;
@@ -50,10 +65,10 @@ void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C,
if (stateZero && !stateNotZero) {
if (ExplodedNode *N = C.GenerateNode(B, stateZero, true)) {
if (!BT)
- BT = new BuiltinBug(0, "Division by zero");
+ BT = new BuiltinBug("Division by zero");
EnhancedBugReport *R =
- new EnhancedBugReport(*BT, BT->getDescription().c_str(), N);
+ new EnhancedBugReport(*BT, BT->getDescription(), N);
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
bugreporter::GetDenomExpr(N));
diff --git a/lib/Analysis/ExplodedGraph.cpp b/lib/Analysis/ExplodedGraph.cpp
index 0dc81a4..3b339ff 100644
--- a/lib/Analysis/ExplodedGraph.cpp
+++ b/lib/Analysis/ExplodedGraph.cpp
@@ -273,7 +273,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
ExplodedNode*
InterExplodedGraphMap::getMappedNode(const ExplodedNode* N) const {
- llvm::DenseMap<const ExplodedNode*, ExplodedNode*>::iterator I =
+ llvm::DenseMap<const ExplodedNode*, ExplodedNode*>::const_iterator I =
M.find(N);
return I == M.end() ? 0 : I->second;
diff --git a/lib/Analysis/FixedAddressChecker.cpp b/lib/Analysis/FixedAddressChecker.cpp
new file mode 100644
index 0000000..80096dc
--- /dev/null
+++ b/lib/Analysis/FixedAddressChecker.cpp
@@ -0,0 +1,70 @@
+//=== FixedAddressChecker.cpp - Fixed address usage checker ----*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This files defines FixedAddressChecker, a builtin checker that checks for
+// assignment of a fixed address to a pointer.
+// This check corresponds to CWE-587.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "GRExprEngineInternalChecks.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN FixedAddressChecker
+ : public CheckerVisitor<FixedAddressChecker> {
+ BuiltinBug *BT;
+public:
+ FixedAddressChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+};
+}
+
+void *FixedAddressChecker::getTag() {
+ static int x;
+ return &x;
+}
+
+void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C,
+ const BinaryOperator *B) {
+ // Using a fixed address is not portable because that address will probably
+ // not be valid in all environments or platforms.
+
+ if (B->getOpcode() != BinaryOperator::Assign)
+ return;
+
+ QualType T = B->getType();
+ if (!T->isPointerType())
+ return;
+
+ const GRState *state = C.getState();
+
+ SVal RV = state->getSVal(B->getRHS());
+
+ if (!RV.isConstant() || RV.isZeroConstant())
+ return;
+
+ if (ExplodedNode *N = C.GenerateNode(B)) {
+ if (!BT)
+ BT = new BuiltinBug("Use fixed address",
+ "Using a fixed address is not portable because that "
+ "address will probably not be valid in all "
+ "environments or platforms.");
+ RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
+ R->addRange(B->getRHS()->getSourceRange());
+ C.EmitReport(R);
+ }
+}
+
+void clang::RegisterFixedAddressChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new FixedAddressChecker());
+}
diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Analysis/GRCoreEngine.cpp
index 8747247..b99ba4f 100644
--- a/lib/Analysis/GRCoreEngine.cpp
+++ b/lib/Analysis/GRCoreEngine.cpp
@@ -418,51 +418,38 @@ void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) {
Eng.WList->Enqueue(Succ, B, Idx+1);
}
-static inline PostStmt GetPostLoc(const Stmt* S, ProgramPoint::Kind K,
- const LocationContext *L, const void *tag) {
+static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K,
+ const LocationContext *LC, const void *tag){
switch (K) {
default:
- assert(false && "Invalid PostXXXKind.");
-
+ assert(false && "Unhandled ProgramPoint kind");
+ case ProgramPoint::PreStmtKind:
+ return PreStmt(S, LC, tag);
case ProgramPoint::PostStmtKind:
- return PostStmt(S, L, tag);
-
+ return PostStmt(S, LC, tag);
+ case ProgramPoint::PreLoadKind:
+ return PreLoad(S, LC, tag);
case ProgramPoint::PostLoadKind:
- return PostLoad(S, L, tag);
-
- case ProgramPoint::PostUndefLocationCheckFailedKind:
- return PostUndefLocationCheckFailed(S, L, tag);
-
- case ProgramPoint::PostLocationChecksSucceedKind:
- return PostLocationChecksSucceed(S, L, tag);
-
- case ProgramPoint::PostOutOfBoundsCheckFailedKind:
- return PostOutOfBoundsCheckFailed(S, L, tag);
-
- case ProgramPoint::PostNullCheckFailedKind:
- return PostNullCheckFailed(S, L, tag);
-
+ return PostLoad(S, LC, tag);
+ case ProgramPoint::PreStoreKind:
+ return PreStore(S, LC, tag);
case ProgramPoint::PostStoreKind:
- return PostStore(S, L, tag);
-
+ return PostStore(S, LC, tag);
case ProgramPoint::PostLValueKind:
- return PostLValue(S, L, tag);
-
+ return PostLValue(S, LC, tag);
case ProgramPoint::PostPurgeDeadSymbolsKind:
- return PostPurgeDeadSymbols(S, L, tag);
+ return PostPurgeDeadSymbols(S, LC, tag);
}
}
ExplodedNode*
-GRStmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* State,
+GRStmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* state,
ExplodedNode* Pred,
ProgramPoint::Kind K,
const void *tag) {
- return K == ProgramPoint::PreStmtKind
- ? generateNodeInternal(PreStmt(S, Pred->getLocationContext(),tag),
- State, Pred)
- : generateNodeInternal(GetPostLoc(S, K, Pred->getLocationContext(), tag),
- State, Pred);
+
+ const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),tag);
+ return generateNodeInternal(L, state, Pred);
}
ExplodedNode*
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 212fea3..2633177 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -293,9 +293,7 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) {
Builder = &builder;
EntryNode = builder.getLastNode();
- // FIXME: Consolidate.
CurrentStmt = S;
- StateMgr.CurrentStmt = S;
// Set up our simple checks.
if (BatchAuditor)
@@ -320,9 +318,32 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) {
SaveAndRestore<bool> OldPurgeDeadSymbols(Builder->PurgingDeadSymbols);
Builder->PurgingDeadSymbols = true;
- getTF().EvalDeadSymbols(Tmp, *this, *Builder, EntryNode, S,
+ // FIXME: This should soon be removed.
+ ExplodedNodeSet Tmp2;
+ getTF().EvalDeadSymbols(Tmp2, *this, *Builder, EntryNode, S,
CleanedState, SymReaper);
+ if (Checkers.empty())
+ Tmp = Tmp2;
+ else {
+ ExplodedNodeSet Tmp3;
+ ExplodedNodeSet *SrcSet = &Tmp2;
+ for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
+ I != E; ++I) {
+ ExplodedNodeSet *DstSet = (I+1 == E) ? &Tmp
+ : (SrcSet == &Tmp2) ? &Tmp3
+ : &Tmp2;
+ DstSet->clear();
+ void *tag = I->first;
+ Checker *checker = I->second;
+ for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end();
+ NI != NE; ++NI)
+ checker->GR_EvalDeadSymbols(*DstSet, *Builder, *this, S, *NI,
+ SymReaper, tag);
+ SrcSet = DstSet;
+ }
+ }
+
if (!Builder->BuildSinks && !Builder->HasGeneratedNode)
Tmp.Add(EntryNode);
}
@@ -353,8 +374,6 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) {
CleanedState = NULL;
EntryNode = NULL;
- // FIXME: Consolidate.
- StateMgr.CurrentStmt = 0;
CurrentStmt = 0;
Builder = NULL;
@@ -878,6 +897,18 @@ void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R,
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, X, true));
}
+/// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path
+/// nodes when the control reaches the end of a function.
+void GRExprEngine::ProcessEndPath(GREndPathNodeBuilder& builder) {
+ getTF().EvalEndPath(*this, builder);
+ StateMgr.EndPath(builder.getState());
+ for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){
+ void *tag = I->first;
+ Checker *checker = I->second;
+ checker->EvalEndPath(builder, tag, *this);
+ }
+}
+
/// ProcessSwitch - Called by GRCoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a switch statement.
void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
@@ -1080,7 +1111,10 @@ void GRExprEngine::VisitArraySubscriptExpr(ArraySubscriptExpr* A,
ExplodedNodeSet Tmp2;
Visit(Idx, *I1, Tmp2); // Evaluate the index.
- for (ExplodedNodeSet::iterator I2=Tmp2.begin(),E2=Tmp2.end();I2!=E2; ++I2) {
+ ExplodedNodeSet Tmp3;
+ CheckerVisit(A, Tmp3, Tmp2, true);
+
+ for (ExplodedNodeSet::iterator I2=Tmp3.begin(),E2=Tmp3.end();I2!=E2; ++I2) {
const GRState* state = GetState(*I2);
SVal V = state->getLValue(A->getType(), state->getSVal(Idx),
state->getSVal(Base));
@@ -1190,112 +1224,87 @@ void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr *AssignE,
assert(Builder && "GRStmtNodeBuilder must be defined.");
// Evaluate the location (checks for bad dereferences).
- Pred = EvalLocation(StoreE, Pred, state, location, tag);
+ ExplodedNodeSet Tmp;
+ EvalLocation(Tmp, StoreE, Pred, state, location, tag, false);
- if (!Pred)
+ if (Tmp.empty())
return;
- assert (!location.isUndef());
- state = GetState(Pred);
+ assert(!location.isUndef());
+ SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind,
+ ProgramPoint::PostStoreKind);
+ SaveAndRestore<const void*> OldTag(Builder->Tag, tag);
+
// Proceed with the store.
- SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
- SaveAndRestore<const void*> OldTag(Builder->Tag);
- Builder->PointKind = ProgramPoint::PostStoreKind;
- Builder->Tag = tag;
- EvalBind(Dst, AssignE, StoreE, Pred, state, location, Val);
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
+ EvalBind(Dst, AssignE, StoreE, *NI, GetState(*NI), location, Val);
}
-void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred,
+void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred,
const GRState* state, SVal location,
- const void *tag) {
+ const void *tag, QualType LoadTy) {
// Evaluate the location (checks for bad dereferences).
- Pred = EvalLocation(Ex, Pred, state, location, tag);
+ ExplodedNodeSet Tmp;
+ EvalLocation(Tmp, Ex, Pred, state, location, tag, true);
- if (!Pred)
+ if (Tmp.empty())
return;
-
- state = GetState(Pred);
+
+ assert(!location.isUndef());
+
+ SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
+ SaveAndRestore<const void*> OldTag(Builder->Tag);
// Proceed with the load.
- ProgramPoint::Kind K = ProgramPoint::PostLoadKind;
-
- // FIXME: Currently symbolic analysis "generates" new symbols
- // for the contents of values. We need a better approach.
-
- if (location.isUnknown()) {
- // This is important. We must nuke the old binding.
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, UnknownVal()),
- K, tag);
- }
- else {
- SVal V = state->getSVal(cast<Loc>(location), Ex->getType());
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), K, tag);
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
+ state = GetState(*NI);
+ if (location.isUnknown()) {
+ // This is important. We must nuke the old binding.
+ MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, UnknownVal()),
+ ProgramPoint::PostLoadKind, tag);
+ }
+ else {
+ SVal V = state->getSVal(cast<Loc>(location), LoadTy.isNull() ?
+ Ex->getType() : LoadTy);
+ MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, V), ProgramPoint::PostLoadKind,
+ tag);
+ }
}
}
-ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred,
- const GRState* state, SVal location,
- const void *tag) {
-
- SaveAndRestore<const void*> OldTag(Builder->Tag);
- Builder->Tag = tag;
+void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
+ ExplodedNode* Pred,
+ const GRState* state, SVal location,
+ const void *tag, bool isLoad) {
- if (location.isUnknown() || Checkers.empty())
- return Pred;
-
-
- for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I)
- {
- Pred = I->second->CheckLocation(Ex, Pred, state, location, *this);
- if (!Pred)
- break;
+ if (location.isUnknown() || Checkers.empty()) {
+ Dst.Add(Pred);
+ return;
}
- return Pred;
-
- // FIXME: Temporarily disable out-of-bounds checking until we make
- // the logic reflect recent changes to CastRegion and friends.
-#if 0
- // Check for out-of-bound array access.
- if (isa<loc::MemRegionVal>(LV)) {
- const MemRegion* R = cast<loc::MemRegionVal>(LV).getRegion();
- if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) {
- // Get the index of the accessed element.
- SVal Idx = ER->getIndex();
- // Get the extent of the array.
- SVal NumElements = getStoreManager().getSizeInElements(StNotNull,
- ER->getSuperRegion());
-
- const GRState * StInBound = StNotNull->AssumeInBound(Idx, NumElements,
- true);
- const GRState* StOutBound = StNotNull->AssumeInBound(Idx, NumElements,
- false);
-
- if (StOutBound) {
- // Report warning. Make sink node manually.
- ExplodedNode* OOBNode =
- Builder->generateNode(Ex, StOutBound, Pred,
- ProgramPoint::PostOutOfBoundsCheckFailedKind);
-
- if (OOBNode) {
- OOBNode->markAsSink();
-
- if (StInBound)
- ImplicitOOBMemAccesses.insert(OOBNode);
- else
- ExplicitOOBMemAccesses.insert(OOBNode);
- }
- }
-
- if (!StInBound)
- return NULL;
-
- StNotNull = StInBound;
- }
+ ExplodedNodeSet Src, Tmp;
+ Src.Add(Pred);
+ ExplodedNodeSet *PrevSet = &Src;
+
+ for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
+ {
+ ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst
+ : (PrevSet == &Tmp) ? &Src : &Tmp;
+
+ CurrSet->clear();
+ void *tag = I->first;
+ Checker *checker = I->second;
+
+ for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
+ NI != NE; ++NI)
+ checker->GR_VisitLocation(*CurrSet, *Builder, *this, S, *NI, state,
+ location, tag, isLoad);
+
+ // Update which NodeSet is the current one.
+ PrevSet = CurrSet;
}
-#endif
}
//===----------------------------------------------------------------------===//
@@ -1311,8 +1320,7 @@ ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred,
static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet& Dst,
GRExprEngine& Engine,
GRStmtNodeBuilder& Builder,
- CallExpr* CE, SVal L,
- ExplodedNode* Pred) {
+ CallExpr* CE, ExplodedNode* Pred) {
// Not enough arguments to match OSAtomicCompareAndSwap?
if (CE->getNumArgs() != 3)
@@ -1354,7 +1362,13 @@ static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet& Dst,
const GRState *state = Pred->getState();
ExplodedNodeSet Tmp;
SVal location = state->getSVal(theValueExpr);
- Engine.EvalLoad(Tmp, theValueExpr, Pred, state, location, OSAtomicLoadTag);
+ // Here we should use the value type of the region as the load type.
+ const MemRegion *R = location.getAsRegion();
+ QualType LoadTy;
+ if (R)
+ LoadTy = cast<TypedRegion>(R)->getValueType(C);
+ Engine.EvalLoad(Tmp, theValueExpr, Pred, state, location, OSAtomicLoadTag,
+ LoadTy);
for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
I != E; ++I) {
@@ -1432,7 +1446,7 @@ static bool EvalOSAtomic(ExplodedNodeSet& Dst,
// Check for compare and swap.
if (strncmp(FName, "OSAtomicCompareAndSwap", 22) == 0 ||
strncmp(FName, "objc_atomicCompareAndSwap", 25) == 0)
- return EvalOSAtomicCompareAndSwap(Dst, Engine, Builder, CE, L, Pred);
+ return EvalOSAtomicCompareAndSwap(Dst, Engine, Builder, CE, Pred);
// FIXME: Other atomics.
return false;
@@ -1521,17 +1535,6 @@ bool GRExprEngine::EvalBuiltinFunction(const FunctionDecl *FD, CallExpr *CE,
return false;
}
-void GRExprEngine::EvalCall(ExplodedNodeSet& Dst, CallExpr* CE, SVal L,
- ExplodedNode* Pred) {
- assert (Builder && "GRStmtNodeBuilder must be defined.");
-
- // FIXME: Allow us to chain together transfer functions.
- if (EvalOSAtomic(Dst, *this, *Builder, CE, L, Pred))
- return;
-
- getTF().EvalCall(Dst, *this, *Builder, CE, L, Pred);
-}
-
void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
CallExpr::arg_iterator AI,
CallExpr::arg_iterator AE,
@@ -1609,17 +1612,25 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred,
continue;
// Dispatch to the plug-in transfer function.
-
- unsigned size = Dst.size();
SaveOr OldHasGen(Builder->HasGeneratedNode);
- EvalCall(Dst, CE, L, *DI);
+ Pred = *DI;
+
+ // Dispatch to transfer function logic to handle the call itself.
+ // FIXME: Allow us to chain together transfer functions.
+ assert(Builder && "GRStmtNodeBuilder must be defined.");
+ ExplodedNodeSet DstTmp;
+
+ if (!EvalOSAtomic(DstTmp, *this, *Builder, CE, L, Pred))
+ getTF().EvalCall(DstTmp, *this, *Builder, CE, L, Pred);
// Handle the case where no nodes where generated. Auto-generate that
// contains the updated state if we aren't generating sinks.
-
- if (!Builder->BuildSinks && Dst.size() == size &&
+ if (!Builder->BuildSinks && DstTmp.empty() &&
!Builder->HasGeneratedNode)
- MakeNode(Dst, CE, *DI, state);
+ MakeNode(DstTmp, CE, Pred, state);
+
+ // Perform the post-condition check of the CallExpr.
+ CheckerVisit(CE, Dst, DstTmp, false);
}
}
@@ -1749,46 +1760,47 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S,
ExplodedNode* Pred, ExplodedNodeSet& Dst,
SVal ElementV) {
-
-
- // Get the current state. Use 'EvalLocation' to determine if it is a null
- // pointer, etc.
+ // Check if the location we are writing back to is a null pointer.
Stmt* elem = S->getElement();
-
- Pred = EvalLocation(elem, Pred, GetState(Pred), ElementV);
- if (!Pred)
+ ExplodedNodeSet Tmp;
+ EvalLocation(Tmp, elem, Pred, GetState(Pred), ElementV, NULL, false);
+
+ if (Tmp.empty())
return;
+
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
+ Pred = *NI;
+ const GRState *state = GetState(Pred);
+
+ // Handle the case where the container still has elements.
+ SVal TrueV = ValMgr.makeTruthVal(1);
+ const GRState *hasElems = state->BindExpr(S, TrueV);
+
+ // Handle the case where the container has no elements.
+ SVal FalseV = ValMgr.makeTruthVal(0);
+ const GRState *noElems = state->BindExpr(S, FalseV);
+
+ if (loc::MemRegionVal* MV = dyn_cast<loc::MemRegionVal>(&ElementV))
+ if (const TypedRegion* R = dyn_cast<TypedRegion>(MV->getRegion())) {
+ // FIXME: The proper thing to do is to really iterate over the
+ // container. We will do this with dispatch logic to the store.
+ // For now, just 'conjure' up a symbolic value.
+ QualType T = R->getValueType(getContext());
+ assert(Loc::IsLocType(T));
+ unsigned Count = Builder->getCurrentBlockCount();
+ SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
+ SVal V = ValMgr.makeLoc(Sym);
+ hasElems = hasElems->bindLoc(ElementV, V);
+
+ // Bind the location to 'nil' on the false branch.
+ SVal nilV = ValMgr.makeIntVal(0, T);
+ noElems = noElems->bindLoc(ElementV, nilV);
+ }
- const GRState *state = GetState(Pred);
-
- // Handle the case where the container still has elements.
- SVal TrueV = ValMgr.makeTruthVal(1);
- const GRState *hasElems = state->BindExpr(S, TrueV);
-
- // Handle the case where the container has no elements.
- SVal FalseV = ValMgr.makeTruthVal(0);
- const GRState *noElems = state->BindExpr(S, FalseV);
-
- if (loc::MemRegionVal* MV = dyn_cast<loc::MemRegionVal>(&ElementV))
- if (const TypedRegion* R = dyn_cast<TypedRegion>(MV->getRegion())) {
- // FIXME: The proper thing to do is to really iterate over the
- // container. We will do this with dispatch logic to the store.
- // For now, just 'conjure' up a symbolic value.
- QualType T = R->getValueType(getContext());
- assert (Loc::IsLocType(T));
- unsigned Count = Builder->getCurrentBlockCount();
- SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
- SVal V = ValMgr.makeLoc(Sym);
- hasElems = hasElems->bindLoc(ElementV, V);
-
- // Bind the location to 'nil' on the false branch.
- SVal nilV = ValMgr.makeIntVal(0, T);
- noElems = noElems->bindLoc(ElementV, nilV);
- }
-
- // Create the new nodes.
- MakeNode(Dst, S, Pred, hasElems);
- MakeNode(Dst, S, Pred, noElems);
+ // Create the new nodes.
+ MakeNode(Dst, S, Pred, hasElems);
+ MakeNode(Dst, S, Pred, noElems);
+ }
}
//===----------------------------------------------------------------------===//
@@ -2035,7 +2047,8 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
// Transfer functions: Miscellaneous statements.
//===----------------------------------------------------------------------===//
-void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst){
+void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst){
ExplodedNodeSet S1;
QualType T = CastE->getType();
QualType ExTy = Ex->getType();
@@ -2048,16 +2061,18 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, Exploded
else
Visit(Ex, Pred, S1);
+ ExplodedNodeSet S2;
+ CheckerVisit(CastE, S2, S1, true);
+
// Check for casting to "void".
if (T->isVoidType()) {
- for (ExplodedNodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1)
- Dst.Add(*I1);
-
+ for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I)
+ Dst.Add(*I);
return;
}
- for (ExplodedNodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) {
- ExplodedNode* N = *I1;
+ for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
+ ExplodedNode* N = *I;
const GRState* state = GetState(N);
SVal V = state->getSVal(Ex);
const SValuator::CastResult &Res = SVator.EvalCast(V, state, T, ExTy);
@@ -2107,23 +2122,12 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
else
Tmp.Add(Pred);
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+ ExplodedNodeSet Tmp2;
+ CheckerVisit(DS, Tmp2, Tmp, true);
+
+ for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) {
ExplodedNode *N = *I;
- const GRState *state;
-
- for (CheckersOrdered::iterator CI = Checkers.begin(), CE = Checkers.end();
- CI != CE; ++CI) {
- state = GetState(N);
- N = CI->second->CheckType(getContext().getCanonicalType(VD->getType()),
- N, state, DS, *this);
- if (!N)
- break;
- }
-
- if (!N)
- continue;
-
- state = GetState(N);
+ const GRState *state = GetState(N);
// Decls without InitExpr are not initialized explicitly.
const LocationContext *LC = N->getLocationContext();
@@ -2628,63 +2632,37 @@ void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A,
VisitAsmStmtHelperInputs(A, I, E, *NI, Dst);
}
-void GRExprEngine::EvalReturn(ExplodedNodeSet& Dst, ReturnStmt* S,
- ExplodedNode* Pred) {
- assert (Builder && "GRStmtNodeBuilder must be defined.");
-
- unsigned size = Dst.size();
-
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- SaveOr OldHasGen(Builder->HasGeneratedNode);
-
- getTF().EvalReturn(Dst, *this, *Builder, S, Pred);
-
- // Handle the case where no nodes where generated.
-
- if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode)
- MakeNode(Dst, S, Pred, GetState(Pred));
-}
-
-void GRExprEngine::VisitReturnStmt(ReturnStmt* S, ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
-
- Expr* R = S->getRetValue();
-
- if (!R) {
- EvalReturn(Dst, S, Pred);
- return;
+void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+
+ ExplodedNodeSet Src;
+ if (Expr *RetE = RS->getRetValue()) {
+ Visit(RetE, Pred, Src);
}
+ else {
+ Src.Add(Pred);
+ }
+
+ ExplodedNodeSet CheckedSet;
+ CheckerVisit(RS, CheckedSet, Src, true);
+
+ for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
+ I != E; ++I) {
- ExplodedNodeSet Tmp;
- Visit(R, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
- SVal X = (*I)->getState()->getSVal(R);
-
- // Check if we return the address of a stack variable.
- if (isa<loc::MemRegionVal>(X)) {
- // Determine if the value is on the stack.
- const MemRegion* R = cast<loc::MemRegionVal>(&X)->getRegion();
-
- if (R && R->hasStackStorage()) {
- // Create a special node representing the error.
- if (ExplodedNode* N = Builder->generateNode(S, GetState(*I), *I)) {
- N->markAsSink();
- RetsStackAddr.insert(N);
- }
- continue;
- }
- }
- // Check if we return an undefined value.
- else if (X.isUndef()) {
- if (ExplodedNode* N = Builder->generateNode(S, GetState(*I), *I)) {
- N->markAsSink();
- RetsUndef.insert(N);
- }
- continue;
- }
-
- EvalReturn(Dst, S, *I);
+ assert(Builder && "GRStmtNodeBuilder must be defined.");
+
+ Pred = *I;
+ unsigned size = Dst.size();
+
+ SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
+
+ getTF().EvalReturn(Dst, *this, *Builder, RS, Pred);
+
+ // Handle the case where no nodes where generated.
+ if (!Builder->BuildSinks && Dst.size() == size &&
+ !Builder->HasGeneratedNode)
+ MakeNode(Dst, RS, Pred, GetState(Pred));
}
}
@@ -2878,7 +2856,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
//===----------------------------------------------------------------------===//
Checker *GRExprEngine::lookupChecker(void *tag) const {
- CheckerMap::iterator I = CheckerM.find(tag);
+ CheckerMap::const_iterator I = CheckerM.find(tag);
return (I == CheckerM.end()) ? NULL : Checkers[I->second].second;
}
@@ -2898,6 +2876,9 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> :
// work.
static std::string getNodeAttributes(const ExplodedNode* N, void*) {
+#if 0
+ // FIXME: Replace with a general scheme to tell if the node is
+ // an error node.
if (GraphPrintCheckerState->isImplicitNullDeref(N) ||
GraphPrintCheckerState->isExplicitNullDeref(N) ||
GraphPrintCheckerState->isUndefDeref(N) ||
@@ -2907,6 +2888,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> :
GraphPrintCheckerState->isBadCall(N) ||
GraphPrintCheckerState->isUndefArg(N))
return "color=\"red\",style=\"filled\"";
+#endif
if (GraphPrintCheckerState->isNoReturnCall(N))
return "color=\"blue\",style=\"filled\"";
@@ -2957,11 +2939,10 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> :
Out << "\\lPostStore\\l";
else if (isa<PostLValue>(Loc))
Out << "\\lPostLValue\\l";
- else if (isa<PostLocationChecksSucceed>(Loc))
- Out << "\\lPostLocationChecksSucceed\\l";
- else if (isa<PostNullCheckFailed>(Loc))
- Out << "\\lPostNullCheckFailed\\l";
+#if 0
+ // FIXME: Replace with a general scheme to determine
+ // the name of the check.
if (GraphPrintCheckerState->isImplicitNullDeref(N))
Out << "\\|Implicit-Null Dereference.\\l";
else if (GraphPrintCheckerState->isExplicitNullDeref(N))
@@ -2978,6 +2959,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> :
Out << "\\|Call to NULL/Undefined.";
else if (GraphPrintCheckerState->isUndefArg(N))
Out << "\\|Argument in call is undefined";
+#endif
break;
}
@@ -3039,9 +3021,13 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> :
Out << "\\l";
}
+#if 0
+ // FIXME: Replace with a general scheme to determine
+ // the name of the check.
if (GraphPrintCheckerState->isUndefControlFlow(N)) {
Out << "\\|Control-flow based on\\lUndefined value.\\l";
}
+#endif
}
}
diff --git a/lib/Analysis/GRExprEngineExperimentalChecks.cpp b/lib/Analysis/GRExprEngineExperimentalChecks.cpp
new file mode 100644
index 0000000..2fb7e9f
--- /dev/null
+++ b/lib/Analysis/GRExprEngineExperimentalChecks.cpp
@@ -0,0 +1,38 @@
+//=-- GRExprEngineExperimentalChecks.h ------------------------------*- C++ -*-=
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines functions to instantiate and register experimental
+// checks in GRExprEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "GRExprEngineExperimentalChecks.h"
+#include "clang/Analysis/LocalCheckers.h"
+
+using namespace clang;
+
+void clang::RegisterExperimentalChecks(GRExprEngine &Eng) {
+ // These are checks that never belong as internal checks
+ // within GRExprEngine.
+ RegisterPthreadLockChecker(Eng);
+ RegisterMallocChecker(Eng);
+}
+
+void clang::RegisterExperimentalInternalChecks(GRExprEngine &Eng) {
+ // These are internal checks that should eventually migrate to
+ // RegisterInternalChecks() once they have been further tested.
+
+ // Note that this must be registered after ReturnStackAddresEngsChecker.
+ RegisterReturnPointerRangeChecker(Eng);
+ RegisterPointerSubChecker(Eng);
+ RegisterPointerArithChecker(Eng);
+ RegisterCastToStructChecker(Eng);
+ RegisterArrayBoundChecker(Eng);
+}
diff --git a/lib/Analysis/GRExprEngineExperimentalChecks.h b/lib/Analysis/GRExprEngineExperimentalChecks.h
new file mode 100644
index 0000000..9a9da32
--- /dev/null
+++ b/lib/Analysis/GRExprEngineExperimentalChecks.h
@@ -0,0 +1,26 @@
+//=-- GRExprEngineExperimentalChecks.h ------------------------------*- C++ -*-=
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines functions to instantiate and register experimental
+// checks in GRExprEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GREXPRENGINE_EXPERIMENTAL_CHECKS
+#define LLVM_CLANG_GREXPRENGINE_EXPERIMENTAL_CHECKS
+
+namespace clang {
+
+class GRExprEngine;
+
+void RegisterPthreadLockChecker(GRExprEngine &Eng);
+void RegisterMallocChecker(GRExprEngine &Eng);
+
+} // end clang namespace
+#endif
diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp
index 695f0b0..d0f60fd 100644
--- a/lib/Analysis/GRExprEngineInternalChecks.cpp
+++ b/lib/Analysis/GRExprEngineInternalChecks.cpp
@@ -12,16 +12,11 @@
//
//===----------------------------------------------------------------------===//
+#include "GRExprEngineInternalChecks.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h"
-#include "clang/Analysis/PathSensitive/Checkers/DivZeroChecker.h"
-#include "clang/Analysis/PathSensitive/Checkers/BadCallChecker.h"
-#include "clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h"
#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h"
-#include "clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h"
-#include "clang/Analysis/PathSensitive/Checkers/VLASizeChecker.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/Compiler.h"
@@ -290,79 +285,6 @@ public:
}
};
-class VISIBILITY_HIDDEN RetStack : public BuiltinBug {
-public:
- RetStack(GRExprEngine* eng)
- : BuiltinBug(eng, "Return of address to stack-allocated memory") {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- for (GRExprEngine::ret_stackaddr_iterator I=Eng.ret_stackaddr_begin(),
- End = Eng.ret_stackaddr_end(); I!=End; ++I) {
-
- ExplodedNode* N = *I;
- const Stmt *S = cast<PostStmt>(N->getLocation()).getStmt();
- const Expr* E = cast<ReturnStmt>(S)->getRetValue();
- assert(E && "Return expression cannot be NULL");
-
- // Get the value associated with E.
- loc::MemRegionVal V = cast<loc::MemRegionVal>(N->getState()->getSVal(E));
-
- // Generate a report for this bug.
- std::string buf;
- llvm::raw_string_ostream os(buf);
- SourceRange R;
-
- // Check if the region is a compound literal.
- if (const CompoundLiteralRegion* CR =
- dyn_cast<CompoundLiteralRegion>(V.getRegion())) {
-
- const CompoundLiteralExpr* CL = CR->getLiteralExpr();
- os << "Address of stack memory associated with a compound literal "
- "declared on line "
- << BR.getSourceManager()
- .getInstantiationLineNumber(CL->getLocStart())
- << " returned.";
-
- R = CL->getSourceRange();
- }
- else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(V.getRegion())) {
- const Expr* ARE = AR->getExpr();
- SourceLocation L = ARE->getLocStart();
- R = ARE->getSourceRange();
-
- os << "Address of stack memory allocated by call to alloca() on line "
- << BR.getSourceManager().getInstantiationLineNumber(L)
- << " returned.";
- }
- else {
- os << "Address of stack memory associated with local variable '"
- << V.getRegion()->getString() << "' returned.";
- }
-
- RangedBugReport *report = new RangedBugReport(*this, os.str().c_str(), N);
- report->addRange(E->getSourceRange());
- if (R.isValid()) report->addRange(R);
- BR.EmitReport(report);
- }
- }
-};
-
-class VISIBILITY_HIDDEN RetUndef : public BuiltinBug {
-public:
- RetUndef(GRExprEngine* eng) : BuiltinBug(eng, "Garbage return value",
- "Undefined or garbage value returned to caller") {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- Emit(BR, Eng.ret_undef_begin(), Eng.ret_undef_end());
- }
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
- registerTrackNullOrUndefValue(BRC, GetRetValExpr(N), N);
- }
-};
-
class VISIBILITY_HIDDEN UndefBranch : public BuiltinBug {
struct VISIBILITY_HIDDEN FindUndefExpr {
GRStateManager& VM;
@@ -439,17 +361,6 @@ public:
}
};
-class VISIBILITY_HIDDEN OutOfBoundMemoryAccess : public BuiltinBug {
-public:
- OutOfBoundMemoryAccess(GRExprEngine* eng)
- : BuiltinBug(eng,"Out-of-bounds memory access",
- "Load or store into an out-of-bound memory position.") {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- Emit(BR, Eng.explicit_oob_memacc_begin(), Eng.explicit_oob_memacc_end());
- }
-};
-
} // end clang namespace
//===----------------------------------------------------------------------===//
@@ -464,11 +375,8 @@ void GRExprEngine::RegisterInternalChecks() {
// to 'FlushReports' from BugReporter.
BR.Register(new UndefBranch(this));
BR.Register(new UndefResult(this));
- BR.Register(new RetStack(this));
- BR.Register(new RetUndef(this));
BR.Register(new BadMsgExprArg(this));
BR.Register(new BadReceiver(this));
- BR.Register(new OutOfBoundMemoryAccess(this));
BR.Register(new NilReceiverStructRet(this));
BR.Register(new NilReceiverLargerThanVoidPtrRet(this));
@@ -476,14 +384,17 @@ void GRExprEngine::RegisterInternalChecks() {
// explicitly registered with the BugReporter. If they issue any BugReports,
// their associated BugType will get registered with the BugReporter
// automatically. Note that the check itself is owned by the GRExprEngine
- // object.
- registerCheck(new AttrNonNullChecker());
- registerCheck(new UndefinedArgChecker());
+ // object.
registerCheck(new UndefinedAssignmentChecker());
- registerCheck(new BadCallChecker());
- registerCheck(new DivZeroChecker());
- registerCheck(new UndefDerefChecker());
- registerCheck(new NullDerefChecker());
- registerCheck(new UndefSizedVLAChecker());
- registerCheck(new ZeroSizedVLAChecker());
+
+ RegisterAttrNonNullChecker(*this);
+ RegisterUndefinedArgChecker(*this);
+ RegisterBadCallChecker(*this);
+ RegisterDereferenceChecker(*this);
+ RegisterVLASizeChecker(*this);
+ RegisterDivZeroChecker(*this);
+ RegisterReturnStackAddressChecker(*this);
+ RegisterReturnUndefChecker(*this);
+ RegisterFixedAddressChecker(*this);
+ RegisterUndefinedArraySubscriptChecker(*this);
}
diff --git a/lib/Analysis/GRExprEngineInternalChecks.h b/lib/Analysis/GRExprEngineInternalChecks.h
new file mode 100644
index 0000000..a9077bf
--- /dev/null
+++ b/lib/Analysis/GRExprEngineInternalChecks.h
@@ -0,0 +1,39 @@
+//=-- GRExprEngineInternalChecks.h- Builtin GRExprEngine Checks -----*- C++ -*-=
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines functions to instantiate and register the "built-in"
+// checks in GRExprEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GREXPRENGINE_INTERNAL_CHECKS
+#define LLVM_CLANG_GREXPRENGINE_INTERNAL_CHECKS
+
+namespace clang {
+
+class GRExprEngine;
+
+void RegisterAttrNonNullChecker(GRExprEngine &Eng);
+void RegisterBadCallChecker(GRExprEngine &Eng);
+void RegisterDereferenceChecker(GRExprEngine &Eng);
+void RegisterDivZeroChecker(GRExprEngine &Eng);
+void RegisterReturnPointerRangeChecker(GRExprEngine &Eng);
+void RegisterReturnStackAddressChecker(GRExprEngine &Eng);
+void RegisterReturnUndefChecker(GRExprEngine &Eng);
+void RegisterVLASizeChecker(GRExprEngine &Eng);
+void RegisterPointerSubChecker(GRExprEngine &Eng);
+void RegisterPointerArithChecker(GRExprEngine &Eng);
+void RegisterFixedAddressChecker(GRExprEngine &Eng);
+void RegisterCastToStructChecker(GRExprEngine &Eng);
+void RegisterUndefinedArgChecker(GRExprEngine &Eng);
+void RegisterArrayBoundChecker(GRExprEngine &Eng);
+void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng);
+
+} // end clang namespace
+#endif
diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp
index f269824..23ee0b2 100644
--- a/lib/Analysis/GRState.cpp
+++ b/lib/Analysis/GRState.cpp
@@ -332,9 +332,3 @@ bool GRStateManager::isEqual(const GRState* state, const Expr* Ex,
bool GRStateManager::isEqual(const GRState* state, const Expr* Ex, uint64_t x) {
return isEqual(state, Ex, getBasicVals().getValue(x, Ex->getType()));
}
-
-//===----------------------------------------------------------------------===//
-// Persistent values for indexing into the Generic Data Map.
-
-int GRState::NullDerefTag::TagInt = 0;
-
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index ae78d1f..2510445 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -18,6 +18,7 @@
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
+#include "clang/Analysis/Support/SaveAndRestore.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
@@ -301,10 +302,9 @@ void LiveVariables::runOnAllBlocks(const CFG& cfg,
LiveVariables::ObserverTy* Obs,
bool recordStmtValues) {
Solver S(*this);
- ObserverTy* OldObserver = getAnalysisData().Observer;
- getAnalysisData().Observer = Obs;
+ SaveAndRestore<LiveVariables::ObserverTy*> SRObs(getAnalysisData().Observer,
+ Obs);
S.runOnAllBlocks(cfg, recordStmtValues);
- getAnalysisData().Observer = OldObserver;
}
//===----------------------------------------------------------------------===//
@@ -333,7 +333,7 @@ bool LiveVariables::isLive(const Stmt* Loc, const VarDecl* D) const {
// printing liveness state for debugging
//
-void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const {
+void LiveVariables::dumpLiveness(const ValTy& V, const SourceManager& SM) const {
const AnalysisDataTy& AD = getAnalysisData();
for (AnalysisDataTy::decl_iterator I = AD.begin_decl(),
@@ -345,8 +345,8 @@ void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const {
}
}
-void LiveVariables::dumpBlockLiveness(SourceManager& M) const {
- for (BlockDataMapTy::iterator I = getBlockDataMap().begin(),
+void LiveVariables::dumpBlockLiveness(const SourceManager& M) const {
+ for (BlockDataMapTy::const_iterator I = getBlockDataMap().begin(),
E = getBlockDataMap().end(); I!=E; ++I) {
llvm::errs() << "\n[ B" << I->first->getBlockID()
<< " (live variables at block exit) ]\n";
diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp
new file mode 100644
index 0000000..93e7083
--- /dev/null
+++ b/lib/Analysis/MallocChecker.cpp
@@ -0,0 +1,218 @@
+//=== MallocChecker.cpp - A malloc/free checker -------------------*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines malloc/free checker, which checks for potential memory
+// leaks, double free, and use-after-free problems.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineExperimentalChecks.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/PathSensitive/GRStateTrait.h"
+#include "clang/Analysis/PathSensitive/SymbolManager.h"
+#include "llvm/ADT/ImmutableMap.h"
+using namespace clang;
+
+namespace {
+
+struct RefState {
+ enum Kind { Allocated, Released, Escaped } K;
+ const Stmt *S;
+
+ RefState(Kind k, const Stmt *s) : K(k), S(s) {}
+
+ bool isAllocated() const { return K == Allocated; }
+ bool isReleased() const { return K == Released; }
+ bool isEscaped() const { return K == Escaped; }
+
+ bool operator==(const RefState &X) const {
+ return K == X.K && S == X.S;
+ }
+
+ static RefState getAllocated(const Stmt *s) { return RefState(Allocated, s); }
+ static RefState getReleased(const Stmt *s) { return RefState(Released, s); }
+ static RefState getEscaped(const Stmt *s) { return RefState(Escaped, s); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(K);
+ ID.AddPointer(S);
+ }
+};
+
+class VISIBILITY_HIDDEN RegionState {};
+
+class VISIBILITY_HIDDEN MallocChecker : public CheckerVisitor<MallocChecker> {
+ BuiltinBug *BT_DoubleFree;
+ BuiltinBug *BT_Leak;
+ IdentifierInfo *II_malloc;
+ IdentifierInfo *II_free;
+
+public:
+ MallocChecker() : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0) {}
+ static void *getTag();
+ void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+ void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper);
+ void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng);
+ void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
+private:
+ void MallocMem(CheckerContext &C, const CallExpr *CE);
+ void FreeMem(CheckerContext &C, const CallExpr *CE);
+};
+}
+
+namespace clang {
+ template <>
+ struct GRStateTrait<RegionState>
+ : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, RefState> > {
+ static void *GDMIndex() { return MallocChecker::getTag(); }
+ };
+}
+
+void clang::RegisterMallocChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new MallocChecker());
+}
+
+void *MallocChecker::getTag() {
+ static int x;
+ return &x;
+}
+
+void MallocChecker::PostVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
+ const FunctionDecl *FD = CE->getDirectCallee();
+ if (!FD)
+ return;
+
+ ASTContext &Ctx = C.getASTContext();
+ if (!II_malloc)
+ II_malloc = &Ctx.Idents.get("malloc");
+ if (!II_free)
+ II_free = &Ctx.Idents.get("free");
+
+ if (FD->getIdentifier() == II_malloc) {
+ MallocMem(C, CE);
+ return;
+ }
+
+ if (FD->getIdentifier() == II_free) {
+ FreeMem(C, CE);
+ return;
+ }
+}
+
+void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
+ const GRState *state = C.getState();
+ SVal CallVal = state->getSVal(CE);
+ SymbolRef Sym = CallVal.getAsLocSymbol();
+ assert(Sym);
+ // Set the symbol's state to Allocated.
+ const GRState *AllocState
+ = state->set<RegionState>(Sym, RefState::getAllocated(CE));
+ C.addTransition(C.GenerateNode(CE, AllocState));
+}
+
+void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
+ const GRState *state = C.getState();
+ SVal ArgVal = state->getSVal(CE->getArg(0));
+ SymbolRef Sym = ArgVal.getAsLocSymbol();
+ assert(Sym);
+
+ const RefState *RS = state->get<RegionState>(Sym);
+ assert(RS);
+
+ // Check double free.
+ if (RS->isReleased()) {
+ ExplodedNode *N = C.GenerateNode(CE, true);
+ if (N) {
+ if (!BT_DoubleFree)
+ BT_DoubleFree = new BuiltinBug("Double free",
+ "Try to free a memory block that has been released");
+ // FIXME: should find where it's freed last time.
+ BugReport *R = new BugReport(*BT_DoubleFree,
+ BT_DoubleFree->getDescription(), N);
+ C.EmitReport(R);
+ }
+ return;
+ }
+
+ // Normal free.
+ const GRState *FreedState
+ = state->set<RegionState>(Sym, RefState::getReleased(CE));
+ C.addTransition(C.GenerateNode(CE, FreedState));
+}
+
+void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
+ SymbolReaper &SymReaper) {
+ for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
+ E = SymReaper.dead_end(); I != E; ++I) {
+ SymbolRef Sym = *I;
+ const GRState *state = C.getState();
+ const RefState *RS = state->get<RegionState>(Sym);
+ if (!RS)
+ return;
+
+ if (RS->isAllocated()) {
+ ExplodedNode *N = C.GenerateNode(S, true);
+ if (N) {
+ if (!BT_Leak)
+ BT_Leak = new BuiltinBug("Memory leak",
+ "Allocated memory never released. Potential memory leak.");
+ // FIXME: where it is allocated.
+ BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
+ C.EmitReport(R);
+ }
+ }
+ }
+}
+
+void MallocChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
+ GRExprEngine &Eng) {
+ const GRState *state = B.getState();
+ typedef llvm::ImmutableMap<SymbolRef, RefState> SymMap;
+ SymMap M = state->get<RegionState>();
+
+ for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
+ RefState RS = I->second;
+ if (RS.isAllocated()) {
+ ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
+ if (N) {
+ if (!BT_Leak)
+ BT_Leak = new BuiltinBug("Memory leak",
+ "Allocated memory never released. Potential memory leak.");
+ BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
+ Eng.getBugReporter().EmitReport(R);
+ }
+ }
+ }
+}
+
+void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
+ const Expr *RetE = S->getRetValue();
+ if (!RetE)
+ return;
+
+ const GRState *state = C.getState();
+
+ SymbolRef Sym = state->getSVal(RetE).getAsSymbol();
+
+ if (!Sym)
+ return;
+
+ const RefState *RS = state->get<RegionState>(Sym);
+ if (!RS)
+ return;
+
+ // FIXME: check other cases.
+ if (RS->isAllocated())
+ state = state->set<RegionState>(Sym, RefState::getEscaped(S));
+
+ ExplodedNode *N = C.GenerateNode(S, state);
+ if (N)
+ C.addTransition(N);
+}
diff --git a/lib/Frontend/ManagerRegistry.cpp b/lib/Analysis/ManagerRegistry.cpp
index 79f1e81..8943db2 100644
--- a/lib/Frontend/ManagerRegistry.cpp
+++ b/lib/Analysis/ManagerRegistry.cpp
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/ManagerRegistry.h"
+#include "clang/Analysis/ManagerRegistry.h"
using namespace clang;
diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp
index 353e632..8c0b85c 100644
--- a/lib/Analysis/MemRegion.cpp
+++ b/lib/Analysis/MemRegion.cpp
@@ -378,11 +378,29 @@ bool MemRegion::hasGlobalsOrParametersStorage() const {
return false;
}
+// getBaseRegion strips away all elements and fields, and get the base region
+// of them.
+const MemRegion *MemRegion::getBaseRegion() const {
+ const MemRegion *R = this;
+ while (true) {
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ R = ER->getSuperRegion();
+ continue;
+ }
+ if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) {
+ R = FR->getSuperRegion();
+ continue;
+ }
+ break;
+ }
+ return R;
+}
+
//===----------------------------------------------------------------------===//
// View handling.
//===----------------------------------------------------------------------===//
-const MemRegion *MemRegion::getBaseRegion() const {
+const MemRegion *MemRegion::StripCasts() const {
const MemRegion *R = this;
while (true) {
if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
diff --git a/lib/Analysis/NSErrorChecker.cpp b/lib/Analysis/NSErrorChecker.cpp
index 307686f..93b617b 100644
--- a/lib/Analysis/NSErrorChecker.cpp
+++ b/lib/Analysis/NSErrorChecker.cpp
@@ -209,15 +209,12 @@ void NSErrorChecker::CheckParamDeref(const VarDecl *Param,
return;
// Iterate over the implicit-null dereferences.
- NullDerefChecker *Checker = Eng.getChecker<NullDerefChecker>();
- assert(Checker && "NullDerefChecker not exist.");
- for (NullDerefChecker::iterator I = Checker->implicit_nodes_begin(),
- E = Checker->implicit_nodes_end(); I != E; ++I) {
-
+ ExplodedNode *const* I, *const* E;
+ llvm::tie(I, E) = GetImplicitNullDereferences(Eng);
+ for ( ; I != E; ++I) {
const GRState *state = (*I)->getState();
- const SVal* X = state->get<GRState::NullDerefTag>();
-
- if (!X || X->getAsSymbol() != ParamSym)
+ SVal location = state->getSVal((*I)->getLocationAs<StmtPoint>()->getStmt());
+ if (location.getAsSymbol() != ParamSym)
continue;
// Emit an error.
diff --git a/lib/Analysis/PointerArithChecker.cpp b/lib/Analysis/PointerArithChecker.cpp
new file mode 100644
index 0000000..9382348
--- /dev/null
+++ b/lib/Analysis/PointerArithChecker.cpp
@@ -0,0 +1,71 @@
+//=== PointerArithChecker.cpp - Pointer arithmetic checker -----*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This files defines PointerArithChecker, a builtin checker that checks for
+// pointer arithmetic on locations other than array elements.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "GRExprEngineInternalChecks.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN PointerArithChecker
+ : public CheckerVisitor<PointerArithChecker> {
+ BuiltinBug *BT;
+public:
+ PointerArithChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+};
+}
+
+void *PointerArithChecker::getTag() {
+ static int x;
+ return &x;
+}
+
+void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C,
+ const BinaryOperator *B) {
+ if (B->getOpcode() != BinaryOperator::Sub &&
+ B->getOpcode() != BinaryOperator::Add)
+ return;
+
+ const GRState *state = C.getState();
+ SVal LV = state->getSVal(B->getLHS());
+ SVal RV = state->getSVal(B->getRHS());
+
+ const MemRegion *LR = LV.getAsRegion();
+
+ if (!LR || !RV.isConstant())
+ return;
+
+ // If pointer arithmetic is done on variables of non-array type, this often
+ // means behavior rely on memory organization, which is dangerous.
+ if (isa<VarRegion>(LR) || isa<CodeTextRegion>(LR) ||
+ isa<CompoundLiteralRegion>(LR)) {
+
+ if (ExplodedNode *N = C.GenerateNode(B)) {
+ if (!BT)
+ BT = new BuiltinBug("Dangerous pointer arithmetic",
+ "Pointer arithmetic done on non-array variables "
+ "means reliance on memory layout, which is "
+ "dangerous.");
+ RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
+ R->addRange(B->getSourceRange());
+ C.EmitReport(R);
+ }
+ }
+}
+
+void clang::RegisterPointerArithChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new PointerArithChecker());
+}
diff --git a/lib/Analysis/PointerSubChecker.cpp b/lib/Analysis/PointerSubChecker.cpp
new file mode 100644
index 0000000..4c7906f
--- /dev/null
+++ b/lib/Analysis/PointerSubChecker.cpp
@@ -0,0 +1,77 @@
+//=== PointerSubChecker.cpp - Pointer subtraction checker ------*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This files defines PointerSubChecker, a builtin checker that checks for
+// pointer subtractions on two pointers pointing to different memory chunks.
+// This check corresponds to CWE-469.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "GRExprEngineInternalChecks.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN PointerSubChecker
+ : public CheckerVisitor<PointerSubChecker> {
+ BuiltinBug *BT;
+public:
+ PointerSubChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+};
+}
+
+void *PointerSubChecker::getTag() {
+ static int x;
+ return &x;
+}
+
+void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C,
+ const BinaryOperator *B) {
+ // When doing pointer subtraction, if the two pointers do not point to the
+ // same memory chunk, emit a warning.
+ if (B->getOpcode() != BinaryOperator::Sub)
+ return;
+
+ const GRState *state = C.getState();
+ SVal LV = state->getSVal(B->getLHS());
+ SVal RV = state->getSVal(B->getRHS());
+
+ const MemRegion *LR = LV.getAsRegion();
+ const MemRegion *RR = RV.getAsRegion();
+
+ if (!(LR && RR))
+ return;
+
+ const MemRegion *BaseLR = LR->getBaseRegion();
+ const MemRegion *BaseRR = RR->getBaseRegion();
+
+ if (BaseLR == BaseRR)
+ return;
+
+ // Allow arithmetic on different symbolic regions.
+ if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR))
+ return;
+
+ if (ExplodedNode *N = C.GenerateNode(B)) {
+ if (!BT)
+ BT = new BuiltinBug("Pointer subtraction",
+ "Subtraction of two pointers that do not point to "
+ "the same memory chunk may cause incorrect result.");
+ RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
+ R->addRange(B->getSourceRange());
+ C.EmitReport(R);
+ }
+}
+
+void clang::RegisterPointerSubChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new PointerSubChecker());
+}
diff --git a/lib/Analysis/PthreadLockChecker.cpp b/lib/Analysis/PthreadLockChecker.cpp
new file mode 100644
index 0000000..6620661
--- /dev/null
+++ b/lib/Analysis/PthreadLockChecker.cpp
@@ -0,0 +1,141 @@
+//===--- PthreadLockChecker.h - Undefined arguments checker ----*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines PthreadLockChecker, a simple lock -> unlock checker. Eventually
+// this shouldn't be registered with GRExprEngineInternalChecks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/GRStateTrait.h"
+#include "GRExprEngineExperimentalChecks.h"
+#include "llvm/ADT/ImmutableSet.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN PthreadLockChecker
+ : public CheckerVisitor<PthreadLockChecker> {
+ BugType *BT;
+public:
+ PthreadLockChecker() : BT(0) {}
+ static void *getTag() {
+ static int x = 0;
+ return &x;
+ }
+ void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+
+ void AcquireLock(CheckerContext &C, const CallExpr *CE,
+ SVal lock, bool isTryLock);
+
+ void ReleaseLock(CheckerContext &C, const CallExpr *CE,
+ SVal lock);
+
+};
+} // end anonymous namespace
+
+// GDM Entry for tracking lock state.
+namespace { class VISIBILITY_HIDDEN LockSet {}; }
+namespace clang {
+template <> struct GRStateTrait<LockSet> :
+ public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
+ static void* GDMIndex() { return PthreadLockChecker::getTag(); }
+};
+} // end clang namespace
+
+void clang::RegisterPthreadLockChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new PthreadLockChecker());
+}
+
+
+void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C,
+ const CallExpr *CE) {
+ const GRState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ const CodeTextRegion *R =
+ dyn_cast_or_null<CodeTextRegion>(state->getSVal(Callee).getAsRegion());
+
+ if (!R)
+ return;
+
+ llvm::StringRef FName = R->getDecl()->getName();
+
+ if (FName == "pthread_mutex_lock") {
+ if (CE->getNumArgs() != 1)
+ return;
+ AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false);
+ }
+ else if (FName == "pthread_mutex_trylock") {
+ if (CE->getNumArgs() != 1)
+ return;
+ AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true);
+ }
+ else if (FName == "pthread_mutex_unlock") {
+ if (CE->getNumArgs() != 1)
+ return;
+ ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
+ }
+}
+
+void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
+ SVal lock, bool isTryLock) {
+
+ const MemRegion *lockR = lock.getAsRegion();
+ if (!lockR)
+ return;
+
+ const GRState *state = C.getState();
+
+ SVal X = state->getSVal(CE);
+ if (X.isUnknownOrUndef())
+ return;
+
+ DefinedSVal retVal = cast<DefinedSVal>(X);
+ const GRState *lockSucc = state;
+
+ if (isTryLock) {
+ // Bifurcate the state, and allow a mode where the lock acquisition fails.
+ const GRState *lockFail;
+ llvm::tie(lockFail, lockSucc) = state->Assume(retVal);
+ assert(lockFail && lockSucc);
+ C.addTransition(C.GenerateNode(CE, lockFail));
+ }
+ else {
+ // Assume that the return value was 0.
+ lockSucc = state->Assume(retVal, false);
+ assert(lockSucc);
+ }
+
+ // Record that the lock was acquired.
+ lockSucc = lockSucc->add<LockSet>(lockR);
+
+ C.addTransition(lockSucc != state ? C.GenerateNode(CE, lockSucc) :
+ C.getPredecessor());
+}
+
+void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
+ SVal lock) {
+
+ const MemRegion *lockR = lock.getAsRegion();
+ if (!lockR)
+ return;
+
+ const GRState *state = C.getState();
+
+ // Record that the lock was released.
+ // FIXME: Handle unlocking locks that were never acquired. This may
+ // require IPA for wrappers.
+ const GRState *unlockState = state->remove<LockSet>(lockR);
+
+ if (state == unlockState)
+ return;
+
+ C.addTransition(C.GenerateNode(CE, unlockState));
+}
diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp
index 73b445e..f5cae69 100644
--- a/lib/Analysis/RangeConstraintManager.cpp
+++ b/lib/Analysis/RangeConstraintManager.cpp
@@ -16,7 +16,7 @@
#include "clang/Analysis/PathSensitive/GRState.h"
#include "clang/Analysis/PathSensitive/GRStateTrait.h"
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
-#include "clang/Frontend/ManagerRegistry.h"
+#include "clang/Analysis/ManagerRegistry.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/FoldingSet.h"
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index dbf8c42..ae3fa14 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -164,7 +164,7 @@ public:
~RegionStoreSubRegionMap() {}
bool iterSubRegions(const MemRegion* Parent, Visitor& V) const {
- Map::iterator I = M.find(Parent);
+ Map::const_iterator I = M.find(Parent);
if (I == M.end())
return true;
@@ -360,7 +360,8 @@ public:
//===------------------------------------------------------------------===//
const GRState *setExtent(const GRState *state, const MemRegion* R, SVal Extent);
- SVal getSizeInElements(const GRState *state, const MemRegion* R);
+ DefinedOrUnknownSVal getSizeInElements(const GRState *state,
+ const MemRegion* R);
//===------------------------------------------------------------------===//
// Utility methods.
@@ -461,7 +462,7 @@ const GRState *RegionStoreManager::InvalidateRegion(const GRState *state,
ASTContext& Ctx = StateMgr.getContext();
// Strip away casts.
- R = R->getBaseRegion();
+ R = R->StripCasts();
// Get the mapping of regions -> subregions.
llvm::OwningPtr<RegionStoreSubRegionMap>
@@ -696,8 +697,8 @@ SVal RegionStoreManager::getLValueElement(QualType elementType, SVal Offset,
// Extents for regions.
//===----------------------------------------------------------------------===//
-SVal RegionStoreManager::getSizeInElements(const GRState *state,
- const MemRegion *R) {
+DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
+ const MemRegion *R) {
switch (R->getKind()) {
case MemRegion::MemSpaceRegionKind:
@@ -1028,16 +1029,20 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
return SValuator::CastResult(state, UnknownVal());
if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
- return CastRetrievedVal(RetrieveField(state, FR), state, FR, T);
+ return SValuator::CastResult(state,
+ CastRetrievedVal(RetrieveField(state, FR), FR, T));
if (const ElementRegion* ER = dyn_cast<ElementRegion>(R))
- return CastRetrievedVal(RetrieveElement(state, ER), state, ER, T);
+ return SValuator::CastResult(state,
+ CastRetrievedVal(RetrieveElement(state, ER), ER, T));
if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R))
- return CastRetrievedVal(RetrieveObjCIvar(state, IVR), state, IVR, T);
+ return SValuator::CastResult(state,
+ CastRetrievedVal(RetrieveObjCIvar(state, IVR), IVR, T));
if (const VarRegion *VR = dyn_cast<VarRegion>(R))
- return CastRetrievedVal(RetrieveVar(state, VR), state, VR, T);
+ return SValuator::CastResult(state,
+ CastRetrievedVal(RetrieveVar(state, VR), VR, T));
RegionBindings B = GetRegionBindings(state->getStore());
RegionBindings::data_type* V = B.lookup(R);
@@ -1109,7 +1114,7 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state,
// FIXME: Handle loads from strings where the literal is treated as
// an integer, e.g., *((unsigned int*)"hello")
ASTContext &Ctx = getContext();
- QualType T = StrR->getValueType(Ctx)->getAs<ArrayType>()->getElementType();
+ QualType T = Ctx.getAsArrayType(StrR->getValueType(Ctx))->getElementType();
if (T != Ctx.getCanonicalType(R->getElementType()))
return UnknownVal();
diff --git a/lib/Analysis/ReturnPointerRangeChecker.cpp b/lib/Analysis/ReturnPointerRangeChecker.cpp
new file mode 100644
index 0000000..44887b2
--- /dev/null
+++ b/lib/Analysis/ReturnPointerRangeChecker.cpp
@@ -0,0 +1,97 @@
+//== ReturnPointerRangeChecker.cpp ------------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines ReturnPointerRangeChecker, which is a path-sensitive check
+// which looks for an out-of-bound pointer being returned to callers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN ReturnPointerRangeChecker :
+ public CheckerVisitor<ReturnPointerRangeChecker> {
+ BuiltinBug *BT;
+public:
+ ReturnPointerRangeChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
+};
+}
+
+void clang::RegisterReturnPointerRangeChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new ReturnPointerRangeChecker());
+}
+
+void *ReturnPointerRangeChecker::getTag() {
+ static int x = 0; return &x;
+}
+
+void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C,
+ const ReturnStmt *RS) {
+ const GRState *state = C.getState();
+
+ const Expr *RetE = RS->getRetValue();
+ if (!RetE)
+ return;
+
+ SVal V = state->getSVal(RetE);
+ const MemRegion *R = V.getAsRegion();
+ if (!R)
+ return;
+
+ R = R->StripCasts();
+ if (!R)
+ return;
+
+ const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R);
+ if (!ER)
+ return;
+
+ DefinedOrUnknownSVal &Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
+
+ // FIXME: All of this out-of-bounds checking should eventually be refactored
+ // into a common place.
+
+ DefinedOrUnknownSVal NumElements
+ = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion());
+
+ const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true);
+ const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false);
+ if (StOutBound && !StInBound) {
+ ExplodedNode *N = C.GenerateNode(RS, StOutBound, true);
+
+ if (!N)
+ return;
+
+ // FIXME: This bug correspond to CWE-466. Eventually we should have bug
+ // types explicitly reference such exploit categories (when applicable).
+ if (!BT)
+ BT = new BuiltinBug("Return of pointer value outside of expected range",
+ "Returned pointer value points outside the original object "
+ "(potential buffer overflow)");
+
+ // FIXME: It would be nice to eventually make this diagnostic more clear,
+ // e.g., by referencing the original declaration or by saying *why* this
+ // reference is outside the range.
+
+ // Generate a report for this bug.
+ RangedBugReport *report =
+ new RangedBugReport(*BT, BT->getDescription(), N);
+
+ report->addRange(RetE->getSourceRange());
+
+ C.EmitReport(report);
+ }
+}
diff --git a/lib/Analysis/ReturnStackAddressChecker.cpp b/lib/Analysis/ReturnStackAddressChecker.cpp
new file mode 100644
index 0000000..e4be871
--- /dev/null
+++ b/lib/Analysis/ReturnStackAddressChecker.cpp
@@ -0,0 +1,97 @@
+//== ReturnStackAddressChecker.cpp ------------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines ReturnStackAddressChecker, which is a path-sensitive
+// check which looks for the addresses of stack variables being returned to
+// callers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "llvm/ADT/SmallString.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN ReturnStackAddressChecker :
+ public CheckerVisitor<ReturnStackAddressChecker> {
+ BuiltinBug *BT;
+public:
+ ReturnStackAddressChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
+};
+}
+
+void clang::RegisterReturnStackAddressChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new ReturnStackAddressChecker());
+}
+
+void *ReturnStackAddressChecker::getTag() {
+ static int x = 0; return &x;
+}
+
+void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
+ const ReturnStmt *RS) {
+
+ const Expr *RetE = RS->getRetValue();
+ if (!RetE)
+ return;
+
+ SVal V = C.getState()->getSVal(RetE);
+ const MemRegion *R = V.getAsRegion();
+
+ if (!R || !R->hasStackStorage())
+ return;
+
+ ExplodedNode *N = C.GenerateNode(RS, C.getState(), true);
+
+ if (!N)
+ return;
+
+ if (!BT)
+ BT = new BuiltinBug("Return of address to stack-allocated memory");
+
+ // Generate a report for this bug.
+ llvm::SmallString<100> buf;
+ llvm::raw_svector_ostream os(buf);
+ SourceRange range;
+
+ // Check if the region is a compound literal.
+ if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
+ const CompoundLiteralExpr* CL = CR->getLiteralExpr();
+ os << "Address of stack memory associated with a compound literal "
+ "declared on line "
+ << C.getSourceManager().getInstantiationLineNumber(CL->getLocStart())
+ << " returned to caller";
+ range = CL->getSourceRange();
+ }
+ else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
+ const Expr* ARE = AR->getExpr();
+ SourceLocation L = ARE->getLocStart();
+ range = ARE->getSourceRange();
+ os << "Address of stack memory allocated by call to alloca() on line "
+ << C.getSourceManager().getInstantiationLineNumber(L)
+ << " returned to caller";
+ }
+ else {
+ os << "Address of stack memory associated with local variable '"
+ << R->getString() << "' returned.";
+ }
+
+ RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
+ report->addRange(RS->getSourceRange());
+ if (range.isValid())
+ report->addRange(range);
+
+ C.EmitReport(report);
+}
diff --git a/lib/Analysis/ReturnUndefChecker.cpp b/lib/Analysis/ReturnUndefChecker.cpp
new file mode 100644
index 0000000..796c760
--- /dev/null
+++ b/lib/Analysis/ReturnUndefChecker.cpp
@@ -0,0 +1,68 @@
+//== ReturnUndefChecker.cpp -------------------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines ReturnUndefChecker, which is a path-sensitive
+// check which looks for undefined or garbage values being returned to the
+// caller.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "llvm/ADT/SmallString.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN ReturnUndefChecker :
+ public CheckerVisitor<ReturnUndefChecker> {
+ BuiltinBug *BT;
+public:
+ ReturnUndefChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
+};
+}
+
+void clang::RegisterReturnUndefChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new ReturnUndefChecker());
+}
+
+void *ReturnUndefChecker::getTag() {
+ static int x = 0; return &x;
+}
+
+void ReturnUndefChecker::PreVisitReturnStmt(CheckerContext &C,
+ const ReturnStmt *RS) {
+
+ const Expr *RetE = RS->getRetValue();
+ if (!RetE)
+ return;
+
+ if (!C.getState()->getSVal(RetE).isUndef())
+ return;
+
+ ExplodedNode *N = C.GenerateNode(RS, C.getState(), true);
+
+ if (!N)
+ return;
+
+ if (!BT)
+ BT = new BuiltinBug("Garbage return value",
+ "Undefined or garbage value returned to caller");
+
+ EnhancedBugReport *report =
+ new EnhancedBugReport(*BT, BT->getDescription(), N);
+
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, RetE);
+
+ C.EmitReport(report);
+}
diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp
index 688b7ff..d5d36e3 100644
--- a/lib/Analysis/SVals.cpp
+++ b/lib/Analysis/SVals.cpp
@@ -63,7 +63,7 @@ const FunctionDecl *SVal::getAsFunctionDecl() const {
// FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
SymbolRef SVal::getAsLocSymbol() const {
if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this)) {
- const MemRegion *R = X->getBaseRegion();
+ const MemRegion *R = X->StripCasts();
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
return SymR->getSymbol();
}
@@ -100,9 +100,9 @@ const MemRegion *SVal::getAsRegion() const {
return 0;
}
-const MemRegion *loc::MemRegionVal::getBaseRegion() const {
+const MemRegion *loc::MemRegionVal::StripCasts() const {
const MemRegion *R = getRegion();
- return R ? R->getBaseRegion() : NULL;
+ return R ? R->StripCasts() : NULL;
}
bool SVal::symbol_iterator::operator==(const symbol_iterator &X) const {
@@ -173,6 +173,10 @@ nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const {
// Useful predicates.
//===----------------------------------------------------------------------===//
+bool SVal::isConstant() const {
+ return isa<nonloc::ConcreteInt>(this) || isa<loc::ConcreteInt>(this);
+}
+
bool SVal::isZeroConstant() const {
if (isa<loc::ConcreteInt>(*this))
return cast<loc::ConcreteInt>(*this).getValue() == 0;
diff --git a/lib/Analysis/SValuator.cpp b/lib/Analysis/SValuator.cpp
index 573cac3..ac727b0 100644
--- a/lib/Analysis/SValuator.cpp
+++ b/lib/Analysis/SValuator.cpp
@@ -62,8 +62,7 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
ASTContext &C = ValMgr.getContext();
// For const casts, just propagate the value.
- if (C.getCanonicalType(castTy).getUnqualifiedType() ==
- C.getCanonicalType(originalTy).getUnqualifiedType())
+ if (C.hasSameUnqualifiedType(castTy, originalTy))
return CastResult(state, val);
// Check for casts from pointers to integers.
diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp
index 4b4ae65..2fd72ac 100644
--- a/lib/Analysis/Store.cpp
+++ b/lib/Analysis/Store.cpp
@@ -21,7 +21,7 @@ StoreManager::StoreManager(GRStateManager &stateMgr)
MRMgr(ValMgr.getRegionManager()) {}
const MemRegion *StoreManager::MakeElementRegion(const MemRegion *Base,
- QualType EleTy, uint64_t index) {
+ QualType EleTy, uint64_t index) {
SVal idx = ValMgr.makeArrayIndex(index);
return MRMgr.getElementRegion(EleTy, idx, Base, ValMgr.getContext());
}
@@ -43,7 +43,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
// Handle casts to Objective-C objects.
if (CastToTy->isObjCObjectPointerType())
- return R->getBaseRegion();
+ return R->StripCasts();
if (CastToTy->isBlockPointerType()) {
// FIXME: We may need different solutions, depending on the symbol
@@ -64,7 +64,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy);
// Handle casts to void*. We just pass the region through.
- if (CanonPointeeTy.getUnqualifiedType() == Ctx.VoidTy)
+ if (CanonPointeeTy.getLocalUnqualifiedType() == Ctx.VoidTy)
return R;
// Handle casts from compatible types.
@@ -192,14 +192,14 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
/// implicit casts that arise from loads from regions that are reinterpreted
/// as another region.
-SValuator::CastResult StoreManager::CastRetrievedVal(SVal V,
- const GRState *state,
- const TypedRegion *R,
- QualType castTy) {
- if (castTy.isNull())
- return SValuator::CastResult(state, V);
-
+SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
+ QualType castTy) {
ASTContext &Ctx = ValMgr.getContext();
- return ValMgr.getSValuator().EvalCast(V, state, castTy, R->getValueType(Ctx));
+
+ if (castTy.isNull())
+ return V;
+
+ assert(Ctx.hasSameUnqualifiedType(castTy, R->getValueType(Ctx)));
+ return V;
}
diff --git a/lib/Analysis/UndefinedArgChecker.cpp b/lib/Analysis/UndefinedArgChecker.cpp
index a229f55..923a7e1 100644
--- a/lib/Analysis/UndefinedArgChecker.cpp
+++ b/lib/Analysis/UndefinedArgChecker.cpp
@@ -12,14 +12,28 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "GRExprEngineInternalChecks.h"
using namespace clang;
-void *UndefinedArgChecker::getTag() {
- static int x = 0;
- return &x;
+namespace {
+class VISIBILITY_HIDDEN UndefinedArgChecker
+ : public CheckerVisitor<UndefinedArgChecker> {
+ BugType *BT;
+public:
+ UndefinedArgChecker() : BT(0) {}
+ static void *getTag() {
+ static int x = 0;
+ return &x;
+ }
+ void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+} // end anonymous namespace
+
+void clang::RegisterUndefinedArgChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new UndefinedArgChecker());
}
void UndefinedArgChecker::PreVisitCallExpr(CheckerContext &C,
@@ -29,11 +43,10 @@ void UndefinedArgChecker::PreVisitCallExpr(CheckerContext &C,
if (C.getState()->getSVal(*I).isUndef()) {
if (ExplodedNode *N = C.GenerateNode(CE, true)) {
if (!BT)
- BT = new BugType("Pass-by-value argument in function call is "
- "undefined", "Logic error");
+ BT = new BuiltinBug("Pass-by-value argument in function call is "
+ "undefined");
// Generate a report for this bug.
- EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName().c_str(),
- N);
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
R->addRange((*I)->getSourceRange());
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
C.EmitReport(R);
diff --git a/lib/Analysis/UndefinedArraySubscriptChecker.cpp b/lib/Analysis/UndefinedArraySubscriptChecker.cpp
new file mode 100644
index 0000000..887c775
--- /dev/null
+++ b/lib/Analysis/UndefinedArraySubscriptChecker.cpp
@@ -0,0 +1,56 @@
+//===--- UndefinedArraySubscriptChecker.h ----------------------*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines UndefinedArraySubscriptChecker, a builtin check in GRExprEngine
+// that performs checks for undefined array subscripts.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "GRExprEngineInternalChecks.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN UndefinedArraySubscriptChecker
+ : public CheckerVisitor<UndefinedArraySubscriptChecker> {
+ BugType *BT;
+public:
+ UndefinedArraySubscriptChecker() : BT(0) {}
+ static void *getTag() {
+ static int x = 0;
+ return &x;
+ }
+ void PreVisitArraySubscriptExpr(CheckerContext &C,
+ const ArraySubscriptExpr *A);
+};
+} // end anonymous namespace
+
+void clang::RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new UndefinedArraySubscriptChecker());
+}
+
+void
+UndefinedArraySubscriptChecker::PreVisitArraySubscriptExpr(CheckerContext &C,
+ const ArraySubscriptExpr *A) {
+ if (C.getState()->getSVal(A->getIdx()).isUndef()) {
+ if (ExplodedNode *N = C.GenerateNode(A, true)) {
+ if (!BT)
+ BT = new BuiltinBug("Array subscript is undefined");
+
+ // Generate a report for this bug.
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
+ R->addRange(A->getIdx()->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ A->getIdx());
+ C.EmitReport(R);
+ }
+ }
+}
diff --git a/lib/Analysis/UndefinedAssignmentChecker.cpp b/lib/Analysis/UndefinedAssignmentChecker.cpp
index 2e3ac34..b8062f3 100644
--- a/lib/Analysis/UndefinedAssignmentChecker.cpp
+++ b/lib/Analysis/UndefinedAssignmentChecker.cpp
@@ -36,11 +36,10 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C,
return;
if (!BT)
- BT = new BugType("Assigned value is garbage or undefined",
- "Logic error");
+ BT = new BuiltinBug("Assigned value is garbage or undefined");
// Generate a report for this bug.
- EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName().c_str(), N);
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
if (AssignE) {
const Expr *ex = 0;
diff --git a/lib/Analysis/VLASizeChecker.cpp b/lib/Analysis/VLASizeChecker.cpp
index 0e73190..799a73e 100644
--- a/lib/Analysis/VLASizeChecker.cpp
+++ b/lib/Analysis/VLASizeChecker.cpp
@@ -7,96 +7,91 @@
//
//===----------------------------------------------------------------------===//
//
-// This defines two VLASizeCheckers, a builtin check in GRExprEngine that
+// This defines VLASizeChecker, a builtin check in GRExprEngine that
// performs checks for declaration of VLA of undefined or zero size.
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/Checkers/VLASizeChecker.h"
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
using namespace clang;
-void *UndefSizedVLAChecker::getTag() {
- static int x = 0;
- return &x;
+namespace {
+class VISIBILITY_HIDDEN VLASizeChecker : public CheckerVisitor<VLASizeChecker> {
+ BugType *BT_zero;
+ BugType *BT_undef;
+
+public:
+ VLASizeChecker() : BT_zero(0), BT_undef(0) {}
+ static void *getTag() { static int tag = 0; return &tag; }
+ void PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS);
+};
+} // end anonymous namespace
+
+void clang::RegisterVLASizeChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new VLASizeChecker());
}
-ExplodedNode *UndefSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred,
- const GRState *state,
- Stmt *S, GRExprEngine &Eng) {
- GRStmtNodeBuilder &Builder = Eng.getBuilder();
- BugReporter &BR = Eng.getBugReporter();
-
- if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) {
- // FIXME: Handle multi-dimensional VLAs.
- Expr* SE = VLA->getSizeExpr();
- SVal Size_untested = state->getSVal(SE);
-
- if (Size_untested.isUndef()) {
- if (ExplodedNode* N = Builder.generateNode(S, state, Pred)) {
- N->markAsSink();
- if (!BT)
- BT = new BugType("Declared variable-length array (VLA) uses a garbage"
- " value as its size", "Logic error");
-
- EnhancedBugReport *R =
- new EnhancedBugReport(*BT, BT->getName().c_str(), N);
- R->addRange(SE->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
- BR.EmitReport(R);
- }
- return 0;
- }
+void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
+ if (!DS->isSingleDecl())
+ return;
+
+ const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
+ if (!VD)
+ return;
+
+ const VariableArrayType *VLA
+ = C.getASTContext().getAsVariableArrayType(VD->getType());
+ if (!VLA)
+ return;
+
+ // FIXME: Handle multi-dimensional VLAs.
+ const Expr* SE = VLA->getSizeExpr();
+ const GRState *state = C.getState();
+ SVal sizeV = state->getSVal(SE);
+
+ if (sizeV.isUndef()) {
+ // Generate an error node.
+ ExplodedNode *N = C.GenerateNode(DS, true);
+ if (!N)
+ return;
+
+ if (!BT_undef)
+ BT_undef = new BuiltinBug("Declared variable-length array (VLA) uses a "
+ "garbage value as its size");
+
+ EnhancedBugReport *report =
+ new EnhancedBugReport(*BT_undef, BT_undef->getName(), N);
+ report->addRange(SE->getSourceRange());
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
+ C.EmitReport(report);
+ return;
}
- return Pred;
-}
-
-void *ZeroSizedVLAChecker::getTag() {
- static int x;
- return &x;
-}
-
-ExplodedNode *ZeroSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred,
- const GRState *state, Stmt *S,
- GRExprEngine &Eng) {
- GRStmtNodeBuilder &Builder = Eng.getBuilder();
- BugReporter &BR = Eng.getBugReporter();
-
- if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) {
- // FIXME: Handle multi-dimensional VLAs.
- Expr* SE = VLA->getSizeExpr();
- SVal Size_untested = state->getSVal(SE);
-
- DefinedOrUnknownSVal *Size = dyn_cast<DefinedOrUnknownSVal>(&Size_untested);
- // Undefined size is checked in another checker.
- if (!Size)
- return Pred;
-
- const GRState *zeroState = state->Assume(*Size, false);
- state = state->Assume(*Size, true);
-
- if (zeroState && !state) {
- if (ExplodedNode* N = Builder.generateNode(S, zeroState, Pred)) {
- N->markAsSink();
- if (!BT)
- BT = new BugType("Declared variable-length array (VLA) has zero size",
- "Logic error");
-
- EnhancedBugReport *R =
- new EnhancedBugReport(*BT, BT->getName().c_str(), N);
- R->addRange(SE->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
- BR.EmitReport(R);
- }
- }
- if (!state)
- return 0;
-
- return Builder.generateNode(S, state, Pred);
+
+ // Check if the size is zero.
+ DefinedOrUnknownSVal sizeD = cast<DefinedOrUnknownSVal>(sizeV);
+
+ const GRState *stateNotZero, *stateZero;
+ llvm::tie(stateNotZero, stateZero) = state->Assume(sizeD);
+
+ if (stateZero && !stateNotZero) {
+ ExplodedNode* N = C.GenerateNode(DS, stateZero, true);
+ if (!BT_zero)
+ BT_zero = new BuiltinBug("Declared variable-length array (VLA) has zero "
+ "size");
+
+ EnhancedBugReport *report =
+ new EnhancedBugReport(*BT_zero, BT_zero->getName(), N);
+ report->addRange(SE->getSourceRange());
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
+ C.EmitReport(report);
+ return;
}
- else
- return Pred;
+
+ // From this point on, assume that the size is not zero.
+ if (state != stateNotZero)
+ C.addTransition(C.GenerateNode(DS, stateNotZero));
}
-
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 962cb4c..a85bef0 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -715,8 +715,8 @@ unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc) const {
-static void ComputeLineNumbers(ContentCache* FI,
- llvm::BumpPtrAllocator &Alloc) DISABLE_INLINE;
+static DISABLE_INLINE void ComputeLineNumbers(ContentCache* FI,
+ llvm::BumpPtrAllocator &Alloc);
static void ComputeLineNumbers(ContentCache* FI, llvm::BumpPtrAllocator &Alloc){
// Note that calling 'getBuffer()' may lazily page in the file.
const MemoryBuffer *Buffer = FI->getBuffer();
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index 12caf0c..b6c4df8 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include <cstdlib>
@@ -24,9 +25,6 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
// These should be overridden by concrete targets as needed.
TLSSupported = true;
PointerWidth = PointerAlign = 32;
- WCharWidth = WCharAlign = 32;
- Char16Width = Char16Align = 16;
- Char32Width = Char32Align = 32;
IntWidth = IntAlign = 32;
LongWidth = LongAlign = 32;
LongLongWidth = LongLongAlign = 64;
@@ -36,7 +34,6 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
DoubleAlign = 64;
LongDoubleWidth = 64;
LongDoubleAlign = 64;
- IntMaxTWidth = 64;
SizeType = UnsignedLong;
PtrDiffType = SignedLong;
IntMaxType = SignedLongLong;
@@ -51,7 +48,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
DoubleFormat = &llvm::APFloat::IEEEdouble;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64";
+ "i64:64:64-f32:32:32-f64:64:64-n32";
UserLabelPrefix = "_";
}
@@ -95,17 +92,33 @@ const char *TargetInfo::getTypeConstantSuffix(IntType T) {
unsigned TargetInfo::getTypeWidth(IntType T) const {
switch (T) {
default: assert(0 && "not an integer!");
- case SignedShort: return getShortWidth();
+ case SignedShort:
case UnsignedShort: return getShortWidth();
- case SignedInt: return getIntWidth();
+ case SignedInt:
case UnsignedInt: return getIntWidth();
- case SignedLong: return getLongWidth();
+ case SignedLong:
case UnsignedLong: return getLongWidth();
- case SignedLongLong: return getLongLongWidth();
+ case SignedLongLong:
case UnsignedLongLong: return getLongLongWidth();
};
}
+/// getTypeAlign - Return the alignment (in bits) of the specified integer type
+/// enum. For example, SignedInt -> getIntAlign().
+unsigned TargetInfo::getTypeAlign(IntType T) const {
+ switch (T) {
+ default: assert(0 && "not an integer!");
+ case SignedShort:
+ case UnsignedShort: return getShortAlign();
+ case SignedInt:
+ case UnsignedInt: return getIntAlign();
+ case SignedLong:
+ case UnsignedLong: return getLongAlign();
+ case SignedLongLong:
+ case UnsignedLongLong: return getLongLongAlign();
+ };
+}
+
/// isTypeSigned - Return whether an integer types is signed. Returns true if
/// the type is signed; false otherwise.
bool TargetInfo::isTypeSigned(IntType T) const {
@@ -124,6 +137,14 @@ bool TargetInfo::isTypeSigned(IntType T) const {
};
}
+/// setForcedLangOptions - Set forced language options.
+/// Apply changes to the target information with respect to certain
+/// language options which change the target configuration.
+void TargetInfo::setForcedLangOptions(LangOptions &Opts) {
+ if (Opts.ShortWChar) {
+ WCharType = UnsignedShort;
+ }
+}
//===----------------------------------------------------------------------===//
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index f418c5a..07c2bb9 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -12,14 +12,18 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/Builtins.h"
-#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "clang/Basic/TargetOptions.h"
#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/MC/MCSectionMachO.h"
using namespace clang;
@@ -151,29 +155,6 @@ static void getDarwinIPhoneOSDefines(std::vector<char> &Defs,
iPhoneOSStr);
}
-/// GetDarwinLanguageOptions - Set the default language options for darwin.
-static void GetDarwinLanguageOptions(LangOptions &Opts,
- const llvm::Triple &Triple) {
- Opts.NeXTRuntime = true;
-
- if (Triple.getOS() != llvm::Triple::Darwin)
- return;
-
- unsigned MajorVersion = Triple.getDarwinMajorNumber();
-
- // Blocks and stack protectors default to on for 10.6 (darwin10) and beyond.
- if (MajorVersion > 9) {
- Opts.Blocks = 1;
- Opts.setStackProtectorMode(LangOptions::SSPOn);
- }
-
- // Non-fragile ABI (in 64-bit mode) default to on for 10.5 (darwin9) and
- // beyond.
- if (MajorVersion >= 9 && Opts.ObjC1 &&
- Triple.getArch() == llvm::Triple::x86_64)
- Opts.ObjCNonFragileABI = 1;
-}
-
namespace {
template<typename Target>
class DarwinTargetInfo : public OSTargetInfo<Target> {
@@ -184,13 +165,6 @@ protected:
getDarwinOSXDefines(Defines, Triple);
}
- /// getDefaultLangOptions - Allow the target to specify default settings for
- /// various language options. These may be overridden by command line
- /// options.
- virtual void getDefaultLangOptions(LangOptions &Opts) {
- TargetInfo::getDefaultLangOptions(Opts);
- GetDarwinLanguageOptions(Opts, TargetInfo::getTriple());
- }
public:
DarwinTargetInfo(const std::string& triple) :
OSTargetInfo<Target>(triple) {
@@ -320,6 +294,25 @@ public:
: OSTargetInfo<Target>(triple) {}
};
+// PSP Target
+template<typename Target>
+class PSPTargetInfo : public OSTargetInfo<Target> {
+protected:
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ std::vector<char> &Defs) const {
+ // PSP defines; list based on the output of the pspdev gcc toolchain.
+ Define(Defs, "PSP", "1");
+ Define(Defs, "_PSP", "1");
+ Define(Defs, "__psp__", "1");
+ Define(Defs, "__ELF__", "1");
+ }
+public:
+ PSPTargetInfo(const std::string& triple)
+ : OSTargetInfo<Target>(triple) {
+ this->UserLabelPrefix = "";
+ }
+};
+
// AuroraUX target
template<typename Target>
class AuroraUXTargetInfo : public OSTargetInfo<Target> {
@@ -413,10 +406,6 @@ public:
return true;
}
}
- virtual void getDefaultLangOptions(LangOptions &Opts) {
- TargetInfo::getDefaultLangOptions(Opts);
- Opts.CharIsSigned = false;
- }
virtual const char *getClobbers() const {
return "";
}
@@ -568,7 +557,7 @@ class PPC32TargetInfo : public PPCTargetInfo {
public:
PPC32TargetInfo(const std::string& triple) : PPCTargetInfo(triple) {
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v128:128:128";
+ "i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32";
}
};
} // end anonymous namespace.
@@ -582,7 +571,7 @@ public:
UIntMaxType = UnsignedLong;
Int64Type = SignedLong;
DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v128:128:128";
+ "i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32:64";
}
};
} // end anonymous namespace.
@@ -655,7 +644,7 @@ public:
bool Enabled) const;
virtual void getDefaultFeatures(const std::string &CPU,
llvm::StringMap<bool> &Features) const;
- virtual void HandleTargetFeatures(const llvm::StringMap<bool> &Features);
+ virtual void HandleTargetFeatures(const std::vector<std::string> &Features);
};
void X86TargetInfo::getDefaultFeatures(const std::string &CPU,
@@ -772,21 +761,25 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
/// HandleTargetOptions - Perform initialization based on the user
/// configured set of features.
-void X86TargetInfo::HandleTargetFeatures(const llvm::StringMap<bool>&Features) {
- if (Features.lookup("sse42"))
- SSELevel = SSE42;
- else if (Features.lookup("sse41"))
- SSELevel = SSE41;
- else if (Features.lookup("ssse3"))
- SSELevel = SSSE3;
- else if (Features.lookup("sse3"))
- SSELevel = SSE3;
- else if (Features.lookup("sse2"))
- SSELevel = SSE2;
- else if (Features.lookup("sse"))
- SSELevel = SSE1;
- else if (Features.lookup("mmx"))
- SSELevel = MMX;
+void
+X86TargetInfo::HandleTargetFeatures(const std::vector<std::string> &Features) {
+ // Remember the maximum enabled sselevel.
+ for (unsigned i = 0, e = Features.size(); i !=e; ++i) {
+ // Ignore disabled features.
+ if (Features[i][0] == '-')
+ continue;
+
+ assert(Features[i][0] == '+' && "Invalid target feature!");
+ X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Features[i].substr(1))
+ .Case("sse42", SSE42)
+ .Case("sse41", SSE41)
+ .Case("ssse3", SSSE3)
+ .Case("sse2", SSE2)
+ .Case("sse", SSE1)
+ .Case("mmx", MMX)
+ .Default(NoMMXSSE);
+ SSELevel = std::max(SSELevel, Level);
+ }
}
/// X86TargetInfo::getTargetDefines - Return a set of the X86-specific #defines
@@ -902,7 +895,7 @@ public:
LongDoubleAlign = 32;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-"
- "a0:0:64-f80:32:32";
+ "a0:0:64-f80:32:32-n8:16:32";
SizeType = UnsignedInt;
PtrDiffType = SignedInt;
IntPtrType = SignedInt;
@@ -943,7 +936,7 @@ public:
IntPtrType = SignedLong;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-"
- "a0:0:64-f80:128:128";
+ "a0:0:64-f80:128:128-n8:16:32";
}
};
@@ -957,11 +950,10 @@ public:
: X86_32TargetInfo(triple) {
TLSSupported = false;
WCharType = UnsignedShort;
- WCharWidth = WCharAlign = 16;
DoubleAlign = LongLongAlign = 64;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
- "a0:0:64-f80:32:32";
+ "a0:0:64-f80:32:32-n8:16:32";
}
virtual void getTargetDefines(const LangOptions &Opts,
std::vector<char> &Defines) const {
@@ -977,11 +969,6 @@ public:
namespace {
-/// GetWindowsVisualStudioLanguageOptions - Set the default language options for Windows.
-static void GetWindowsVisualStudioLanguageOptions(LangOptions &Opts) {
- Opts.Microsoft = true;
-}
-
// x86-32 Windows Visual Studio target
class VisualStudioWindowsX86_32TargetInfo : public WindowsX86_32TargetInfo {
public:
@@ -996,10 +983,6 @@ public:
// We lost the original triple, so we use the default.
Define(Defines, "_M_IX86", "600");
}
- virtual void getDefaultLangOptions(LangOptions &Opts) {
- WindowsX86_32TargetInfo::getDefaultLangOptions(Opts);
- GetWindowsVisualStudioLanguageOptions(Opts);
- }
};
} // end anonymous namespace
@@ -1028,11 +1011,10 @@ public:
: X86_32TargetInfo(triple) {
TLSSupported = false;
WCharType = UnsignedShort;
- WCharWidth = WCharAlign = 16;
DoubleAlign = LongLongAlign = 64;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
- "a0:0:64-f80:32:32";
+ "a0:0:64-f80:32:32-n8:16:32";
}
virtual void getTargetDefines(const LangOptions &Opts,
std::vector<char> &Defines) const {
@@ -1059,7 +1041,7 @@ public:
DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
- "a0:0:64-s0:64:64-f80:128:128";
+ "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64";
}
virtual const char *getVAListDeclaration() const {
return "typedef struct __va_list_tag {"
@@ -1087,7 +1069,6 @@ public:
: X86_64TargetInfo(triple) {
TLSSupported = false;
WCharType = UnsignedShort;
- WCharWidth = WCharAlign = 16;
LongWidth = LongAlign = 32;
DoubleAlign = LongLongAlign = 64;
}
@@ -1208,11 +1189,11 @@ public:
if (IsThumb) {
DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-"
- "v64:64:64-v128:128:128-a0:0:32");
+ "v64:64:64-v128:128:128-a0:0:32-n32");
} else {
DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-"
- "v64:64:64-v128:128:128-a0:0:64");
+ "v64:64:64-v128:128:128-a0:0:64-n32");
}
}
virtual const char *getABI() const { return ABI.c_str(); }
@@ -1230,11 +1211,11 @@ public:
if (IsThumb) {
DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-"
"i64:32:32-f32:32:32-f64:32:32-"
- "v64:64:64-v128:128:128-a0:0:32");
+ "v64:64:64-v128:128:128-a0:0:32-n32");
} else {
DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:32:32-f32:32:32-f64:32:32-"
- "v64:64:64-v128:128:128-a0:0:64");
+ "v64:64:64-v128:128:128-a0:0:64-n32");
}
// FIXME: Override "preferred align" for double and long long.
@@ -1391,7 +1372,7 @@ public:
SparcV8TargetInfo(const std::string& triple) : TargetInfo(triple) {
// FIXME: Support Sparc quad-precision long double?
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v64:64:64";
+ "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
}
virtual void getTargetDefines(const LangOptions &Opts,
std::vector<char> &Defines) const {
@@ -1502,7 +1483,6 @@ namespace {
TLSSupported = false;
IntWidth = 16;
LongWidth = LongLongWidth = 32;
- IntMaxTWidth = 32;
PointerWidth = 16;
IntAlign = 8;
LongAlign = LongLongAlign = 8;
@@ -1521,7 +1501,7 @@ namespace {
FloatFormat = &llvm::APFloat::IEEEsingle;
DoubleFormat = &llvm::APFloat::IEEEsingle;
LongDoubleFormat = &llvm::APFloat::IEEEsingle;
- DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-f32:32:32";
+ DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-f32:32:32-n8";
}
virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { return 16; }
@@ -1570,7 +1550,6 @@ namespace {
TLSSupported = false;
IntWidth = 16;
LongWidth = LongLongWidth = 32;
- IntMaxTWidth = 32;
PointerWidth = 16;
IntAlign = 8;
LongAlign = LongLongAlign = 8;
@@ -1580,7 +1559,7 @@ namespace {
UIntMaxType = UnsignedLong;
IntPtrType = SignedShort;
PtrDiffType = SignedInt;
- DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8";
+ DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-n8:16";
}
virtual void getTargetDefines(const LangOptions &Opts,
std::vector<char> &Defines) const {
@@ -1639,7 +1618,8 @@ namespace {
IntWidth = IntAlign = 32;
LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64;
PointerWidth = PointerAlign = 64;
- DescriptionString = "E-p:64:64:64-i8:8:16-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:128:128-a0:16:16";
+ DescriptionString = "E-p:64:64:64-i8:8:16-i16:16:16-i32:32:32-"
+ "i64:64:64-f32:32:32-f64:64:64-f128:128:128-a0:16:16-n32:64";
}
virtual void getTargetDefines(const LangOptions &Opts,
std::vector<char> &Defines) const {
@@ -1653,11 +1633,6 @@ namespace {
NumRecords = 0;
}
- virtual void getDefaultLangOptions(LangOptions &Opts) {
- TargetInfo::getDefaultLangOptions(Opts);
- Opts.CharIsSigned = false;
- }
-
virtual void getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const;
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
@@ -1702,7 +1677,7 @@ namespace {
DoubleAlign = 32;
LongLongAlign = 32;
LongDoubleAlign = 32;
- DescriptionString = "e-p:32:32-i64:32-f64:32";
+ DescriptionString = "e-p:32:32-i64:32-f64:32-n32";
}
virtual void getTargetDefines(const LangOptions &Opts,
@@ -1783,7 +1758,6 @@ namespace {
TLSSupported = false;
IntWidth = 32;
LongWidth = LongLongWidth = 32;
- IntMaxTWidth = 32;
PointerWidth = 32;
IntAlign = 32;
LongAlign = LongLongAlign = 32;
@@ -1804,7 +1778,7 @@ namespace {
LongDoubleFormat = &llvm::APFloat::IEEEsingle;
DescriptionString = "E-p:32:32:32-a0:32:32"
"-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64"
- "-f32:32:32-f64:32:64";
+ "-f32:32:32-f64:32:64-n32";
}
virtual void getTargetDefines(const LangOptions &Opts,
@@ -1832,13 +1806,141 @@ namespace {
};
}
+namespace {
+class MipsTargetInfo : public TargetInfo {
+ static const TargetInfo::GCCRegAlias GCCRegAliases[];
+ static const char * const GCCRegNames[];
+public:
+ MipsTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
+ "i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ DefineStd(Defines, "mips", Opts);
+ Define(Defines, "_mips");
+ DefineStd(Defines, "MIPSEB", Opts);
+ Define(Defines, "_MIPSEB");
+ Define(Defines, "__REGISTER_PREFIX__", "");
+ }
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ // FIXME: Implement!
+ }
+ virtual const char *getVAListDeclaration() const {
+ return "typedef void* __builtin_va_list;";
+ }
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const;
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const;
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const {
+ switch (*Name) {
+ default:
+ case 'r': // CPU registers.
+ case 'd': // Equivalent to "r" unless generating MIPS16 code.
+ case 'y': // Equivalent to "r", backwards compatibility only.
+ case 'f': // floating-point registers.
+ Info.setAllowsRegister();
+ return true;
+ }
+ return false;
+ }
+
+ virtual const char *getClobbers() const {
+ // FIXME: Implement!
+ return "";
+ }
+};
+
+const char * const MipsTargetInfo::GCCRegNames[] = {
+ "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
+ "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
+ "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
+ "$24", "$25", "$26", "$27", "$28", "$sp", "$fp", "$31",
+ "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
+ "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
+ "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
+ "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
+ "hi", "lo", "", "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4",
+ "$fcc5","$fcc6","$fcc7"
+};
+
+void MipsTargetInfo::getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+}
+
+const TargetInfo::GCCRegAlias MipsTargetInfo::GCCRegAliases[] = {
+ { { "at" }, "$1" },
+ { { "v0" }, "$2" },
+ { { "v1" }, "$3" },
+ { { "a0" }, "$4" },
+ { { "a1" }, "$5" },
+ { { "a2" }, "$6" },
+ { { "a3" }, "$7" },
+ { { "t0" }, "$8" },
+ { { "t1" }, "$9" },
+ { { "t2" }, "$10" },
+ { { "t3" }, "$11" },
+ { { "t4" }, "$12" },
+ { { "t5" }, "$13" },
+ { { "t6" }, "$14" },
+ { { "t7" }, "$15" },
+ { { "s0" }, "$16" },
+ { { "s1" }, "$17" },
+ { { "s2" }, "$18" },
+ { { "s3" }, "$19" },
+ { { "s4" }, "$20" },
+ { { "s5" }, "$21" },
+ { { "s6" }, "$22" },
+ { { "s7" }, "$23" },
+ { { "t8" }, "$24" },
+ { { "t9" }, "$25" },
+ { { "k0" }, "$26" },
+ { { "k1" }, "$27" },
+ { { "gp" }, "$28" },
+ { { "sp" }, "$29" },
+ { { "fp" }, "$30" },
+ { { "ra" }, "$31" }
+};
+
+void MipsTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ Aliases = GCCRegAliases;
+ NumAliases = llvm::array_lengthof(GCCRegAliases);
+}
+} // end anonymous namespace.
+
+namespace {
+class MipselTargetInfo : public MipsTargetInfo {
+public:
+ MipselTargetInfo(const std::string& triple) : MipsTargetInfo(triple) {
+ DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
+ "i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32";
+ }
+
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const;
+};
+
+void MipselTargetInfo::getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ DefineStd(Defines, "mips", Opts);
+ Define(Defines, "_mips");
+ DefineStd(Defines, "MIPSEL", Opts);
+ Define(Defines, "_MIPSEL");
+ Define(Defines, "__REGISTER_PREFIX__", "");
+}
+} // end anonymous namespace.
+
//===----------------------------------------------------------------------===//
// Driver code
//===----------------------------------------------------------------------===//
-/// CreateTargetInfo - Return the target info object for the specified target
-/// triple.
-TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) {
+static TargetInfo *AllocateTarget(const std::string &T) {
llvm::Triple Triple(T);
llvm::Triple::OSType os = Triple.getOS();
@@ -1863,6 +1965,20 @@ TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) {
case llvm::Triple::msp430:
return new MSP430TargetInfo(T);
+ case llvm::Triple::mips:
+ if (os == llvm::Triple::Psp)
+ return new PSPTargetInfo<MipsTargetInfo>(T);
+ if (os == llvm::Triple::Linux)
+ return new LinuxTargetInfo<MipsTargetInfo>(T);
+ return new MipsTargetInfo(T);
+
+ case llvm::Triple::mipsel:
+ if (os == llvm::Triple::Psp)
+ return new PSPTargetInfo<MipselTargetInfo>(T);
+ if (os == llvm::Triple::Linux)
+ return new LinuxTargetInfo<MipselTargetInfo>(T);
+ return new MipselTargetInfo(T);
+
case llvm::Triple::pic16:
return new PIC16TargetInfo(T);
@@ -1942,3 +2058,53 @@ TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) {
}
}
}
+
+/// CreateTargetInfo - Return the target info object for the specified target
+/// triple.
+TargetInfo *TargetInfo::CreateTargetInfo(Diagnostic &Diags,
+ const TargetOptions &Opts) {
+ llvm::Triple Triple(Opts.Triple);
+
+ // Construct the target
+ llvm::OwningPtr<TargetInfo> Target(AllocateTarget(Triple.str()));
+ if (!Target) {
+ Diags.Report(diag::err_target_unknown_triple) << Triple.str();
+ return 0;
+ }
+
+ // Set the target ABI if specified.
+ if (!Opts.ABI.empty() && !Target->setABI(Opts.ABI)) {
+ Diags.Report(diag::err_target_unknown_abi) << Opts.ABI;
+ return 0;
+ }
+
+ // Compute the default target features, we need the target to handle this
+ // because features may have dependencies on one another.
+ llvm::StringMap<bool> Features;
+ Target->getDefaultFeatures(Opts.CPU, Features);
+
+ // Apply the user specified deltas.
+ for (std::vector<std::string>::const_iterator it = Opts.Features.begin(),
+ ie = Opts.Features.end(); it != ie; ++it) {
+ const char *Name = it->c_str();
+
+ // Apply the feature via the target.
+ if ((Name[0] != '-' && Name[0] != '+') ||
+ !Target->setFeatureEnabled(Features, Name + 1, (Name[0] == '+'))) {
+ Diags.Report(diag::err_target_invalid_feature) << Name;
+ return 0;
+ }
+ }
+
+ // Add the features to the compile options.
+ //
+ // FIXME: If we are completely confident that we have the right set, we only
+ // need to pass the minuses.
+ std::vector<std::string> StrFeatures;
+ for (llvm::StringMap<bool>::const_iterator it = Features.begin(),
+ ie = Features.end(); it != ie; ++it)
+ StrFeatures.push_back(std::string(it->second ? "+" : "-") + it->first());
+ Target->HandleTargetFeatures(StrFeatures);
+
+ return Target.take();
+}
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index 30383f6..ba31544 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -26,6 +26,10 @@ const char *getClangSubversionPath() {
if (End)
*End = 0;
+ End = strstr(URL, "/clang/tools/clang");
+ if (End)
+ *End = 0;
+
char *Begin = strstr(URL, "cfe/");
if (Begin) {
Path = Begin + 4;
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 682cf5d..bc9eb67 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -146,7 +146,23 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
if (0 && CanBlockBeGlobal(Info))
return CGM.GetAddrOfGlobalBlock(BE, Name.c_str());
- std::vector<llvm::Constant*> Elts(5);
+ size_t BlockFields = 5;
+
+ bool hasIntrospection = CGM.getContext().getLangOptions().BlockIntrospection;
+
+ if (hasIntrospection) {
+ BlockFields++;
+ }
+ std::vector<llvm::Constant*> Elts(BlockFields);
+
+ if (hasIntrospection) {
+ std::string BlockTypeEncoding;
+ CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding);
+
+ Elts[5] = llvm::ConstantExpr::getBitCast(
+ CGM.GetAddrOfConstantCString(BlockTypeEncoding), PtrToInt8Ty);
+ }
+
llvm::Constant *C;
llvm::Value *V;
@@ -154,6 +170,9 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
// C = BuildBlockStructInitlist();
unsigned int flags = BLOCK_HAS_DESCRIPTOR;
+ if (hasIntrospection)
+ flags |= BLOCK_HAS_OBJC_TYPE;
+
// We run this first so that we set BlockHasCopyDispose from the entire
// block literal.
// __invoke
@@ -211,19 +230,21 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
return C;
}
- std::vector<const llvm::Type *> Types(5+subBlockDeclRefDecls.size());
+ std::vector<const llvm::Type *> Types(BlockFields+subBlockDeclRefDecls.size());
for (int i=0; i<4; ++i)
Types[i] = Elts[i]->getType();
Types[4] = PtrToInt8Ty;
+ if (hasIntrospection)
+ Types[5] = PtrToInt8Ty;
for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) {
const Expr *E = subBlockDeclRefDecls[i];
const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
QualType Ty = E->getType();
if (BDRE && BDRE->isByRef()) {
- Types[i+5] = llvm::PointerType::get(BuildByRefType(BDRE->getDecl()), 0);
+ Types[i+BlockFields] = llvm::PointerType::get(BuildByRefType(BDRE->getDecl()), 0);
} else
- Types[i+5] = ConvertType(Ty);
+ Types[i+BlockFields] = ConvertType(Ty);
}
llvm::StructType *Ty = llvm::StructType::get(VMContext, Types, true);
@@ -237,6 +258,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
for (unsigned i=0; i<4; ++i)
Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp"));
+ if (hasIntrospection)
+ Builder.CreateStore(Elts[5], Builder.CreateStructGEP(V, 5, "block.tmp"));
for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i)
{
@@ -252,7 +275,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
VD = BDRE->getDecl();
- llvm::Value* Addr = Builder.CreateStructGEP(V, i+5, "tmp");
+ llvm::Value* Addr = Builder.CreateStructGEP(V, i+BlockFields, "tmp");
NoteForHelper[helpersize].index = i+5;
NoteForHelper[helpersize].RequiresCopying
= BlockRequiresCopying(VD->getType());
@@ -291,7 +314,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
RValue r = EmitAnyExpr(E, Addr, false);
if (r.isScalar()) {
llvm::Value *Loc = r.getScalarVal();
- const llvm::Type *Ty = Types[i+5];
+ const llvm::Type *Ty = Types[i+BlockFields];
if (BDRE->isByRef()) {
// E is now the address of the value field, instead, we want the
// address of the actual ByRef struct. We optimize this slightly
@@ -375,8 +398,20 @@ const llvm::Type *BlockModule::getGenericBlockLiteralType() {
// int __reserved;
// void (*__invoke)(void *);
// struct __block_descriptor *__descriptor;
+ // // GNU runtime only:
+ // const char *types;
// };
- GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(),
+ if (CGM.getContext().getLangOptions().BlockIntrospection)
+ GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(),
+ PtrToInt8Ty,
+ IntTy,
+ IntTy,
+ PtrToInt8Ty,
+ BlockDescPtrTy,
+ PtrToInt8Ty,
+ NULL);
+ else
+ GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(),
PtrToInt8Ty,
IntTy,
IntTy,
@@ -571,8 +606,12 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
llvm::GlobalVariable::InternalLinkage,
DescriptorStruct, "__block_descriptor_global");
+ int FieldCount = 5;
// Generate the constants for the block literal.
- llvm::Constant *LiteralFields[5];
+ if (CGM.getContext().getLangOptions().BlockIntrospection)
+ FieldCount = 6;
+
+ std::vector<llvm::Constant*> LiteralFields(FieldCount);
CodeGenFunction::BlockInfo Info(0, n);
uint64_t subBlockSize, subBlockAlign;
@@ -592,7 +631,9 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
LiteralFields[0] = getNSConcreteGlobalBlock();
// Flags
- LiteralFields[1] =
+ LiteralFields[1] = CGM.getContext().getLangOptions().BlockIntrospection ?
+ llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL | BLOCK_HAS_DESCRIPTOR |
+ BLOCK_HAS_OBJC_TYPE) :
llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL | BLOCK_HAS_DESCRIPTOR);
// Reserved
@@ -603,9 +644,17 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
// Descriptor
LiteralFields[4] = Descriptor;
+
+ // Type encoding
+ if (CGM.getContext().getLangOptions().BlockIntrospection) {
+ std::string BlockTypeEncoding;
+ CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding);
+
+ LiteralFields[5] = CGM.GetAddrOfConstantCString(BlockTypeEncoding);
+ }
llvm::Constant *BlockLiteralStruct =
- llvm::ConstantStruct::get(VMContext, &LiteralFields[0], 5, false);
+ llvm::ConstantStruct::get(VMContext, LiteralFields, false);
llvm::GlobalVariable *BlockLiteral =
new llvm::GlobalVariable(getModule(), BlockLiteralStruct->getType(), true,
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 3ab4efb..38e02a7 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -55,7 +55,8 @@ public:
BLOCK_HAS_CXX_OBJ = (1 << 26),
BLOCK_IS_GC = (1 << 27),
BLOCK_IS_GLOBAL = (1 << 28),
- BLOCK_HAS_DESCRIPTOR = (1 << 29)
+ BLOCK_HAS_DESCRIPTOR = (1 << 29),
+ BLOCK_HAS_OBJC_TYPE = (1 << 30)
};
};
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index c269219..399b873 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -121,7 +121,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
const llvm::Type *ResultType = ConvertType(E->getType());
Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, "cast");
+ Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
+ "cast");
return RValue::get(Result);
}
case Builtin::BI__builtin_clz:
@@ -135,7 +136,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
const llvm::Type *ResultType = ConvertType(E->getType());
Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, "cast");
+ Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
+ "cast");
return RValue::get(Result);
}
case Builtin::BI__builtin_ffs:
@@ -154,7 +156,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero, "iszero");
Value *Result = Builder.CreateSelect(IsZero, Zero, Tmp, "ffs");
if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, "cast");
+ Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
+ "cast");
return RValue::get(Result);
}
case Builtin::BI__builtin_parity:
@@ -171,7 +174,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *Result = Builder.CreateAnd(Tmp, llvm::ConstantInt::get(ArgType, 1),
"tmp");
if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, "cast");
+ Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
+ "cast");
return RValue::get(Result);
}
case Builtin::BI__builtin_popcount:
@@ -185,7 +189,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
const llvm::Type *ResultType = ConvertType(E->getType());
Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, "cast");
+ Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
+ "cast");
return RValue::get(Result);
}
case Builtin::BI__builtin_expect:
@@ -199,8 +204,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Builder.CreateCall(F, ArgValue, "tmp"));
}
case Builtin::BI__builtin_object_size: {
- // FIXME: We're awaiting the llvm intrincis.
-#if 0
+#if 1
// We pass this builtin onto the optimizer so that it can
// figure out the object size in more complex cases.
const llvm::Type *ResType[] = {
@@ -211,8 +215,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
EmitScalarExpr(E->getArg(0)),
EmitScalarExpr(E->getArg(1))));
#else
- // FIXME: Implement. For now we just always fail and pretend we
- // don't know the object size.
+ // FIXME: Remove after testing.
llvm::APSInt TypeArg = E->getArg(1)->EvaluateAsInt(CGM.getContext());
const llvm::Type *ResType = ConvertType(E->getType());
// bool UseSubObject = TypeArg.getZExtValue() & 1;
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index cf172b1..8f5cff4 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -27,7 +27,7 @@ using namespace clang;
using namespace CodeGen;
void
-CodeGenFunction::EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor,
+CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
llvm::Constant *DeclPtr) {
const llvm::Type *Int8PtrTy =
llvm::Type::getInt8Ty(VMContext)->getPointerTo();
@@ -55,9 +55,6 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor,
llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy,
"__dso_handle");
-
- llvm::Constant *DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete);
-
llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy),
llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy),
llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) };
@@ -82,11 +79,29 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile);
} else {
EmitAggExpr(Init, DeclPtr, isVolatile);
-
+ // Avoid generating destructor(s) for initialized objects.
+ if (!isa<CXXConstructExpr>(Init))
+ return;
+ const ConstantArrayType *Array = getContext().getAsConstantArrayType(T);
+ if (Array)
+ T = getContext().getBaseElementType(Array);
+
if (const RecordType *RT = T->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (!RD->hasTrivialDestructor())
- EmitCXXGlobalDtorRegistration(RD->getDestructor(getContext()), DeclPtr);
+ if (!RD->hasTrivialDestructor()) {
+ llvm::Constant *DtorFn;
+ if (Array) {
+ DtorFn = CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper(
+ RD->getDestructor(getContext()),
+ Array, DeclPtr);
+ DeclPtr =
+ llvm::Constant::getNullValue(llvm::Type::getInt8PtrTy(VMContext));
+ }
+ else
+ DtorFn = CGM.GetAddrOfCXXDestructor(RD->getDestructor(getContext()),
+ Dtor_Complete);
+ EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr);
+ }
}
}
}
@@ -267,14 +282,20 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) {
// We also don't emit a virtual call if the base expression has a record type
// because then we know what the type is.
llvm::Value *Callee;
- if (MD->isVirtual() && !ME->hasQualifier() &&
- !canDevirtualizeMemberFunctionCalls(ME->getBase()))
- Callee = BuildVirtualCall(MD, This, Ty);
- else if (const CXXDestructorDecl *Destructor
- = dyn_cast<CXXDestructorDecl>(MD))
- Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty);
- else
+ if (const CXXDestructorDecl *Destructor
+ = dyn_cast<CXXDestructorDecl>(MD)) {
+ if (MD->isVirtual() && !ME->hasQualifier() &&
+ !canDevirtualizeMemberFunctionCalls(ME->getBase())) {
+ Callee = BuildVirtualCall(Destructor, Dtor_Complete, This, Ty);
+ } else {
+ Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty);
+ }
+ } else if (MD->isVirtual() && !ME->hasQualifier() &&
+ !canDevirtualizeMemberFunctionCalls(ME->getBase())) {
+ Callee = BuildVirtualCall(MD, This, Ty);
+ } else {
Callee = CGM.GetAddrOfFunction(MD, Ty);
+ }
return EmitCXXMemberCall(MD, Callee, This,
CE->arg_begin(), CE->arg_end());
@@ -410,10 +431,15 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
const llvm::Type *Ty =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
FPT->isVariadic());
- llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, Ty);
llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
+ llvm::Value *Callee;
+ if (MD->isVirtual() && !canDevirtualizeMemberFunctionCalls(E->getArg(0)))
+ Callee = BuildVirtualCall(MD, This, Ty);
+ else
+ Callee = CGM.GetAddrOfFunction(MD, Ty);
+
return EmitCXXMemberCall(MD, Callee, This,
E->arg_begin() + 1, E->arg_end());
}
@@ -506,16 +532,25 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
llvm::Value *This) {
const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
assert(CA && "Do we support VLA for destruction ?");
+ uint64_t ElementCount = getContext().getConstantArrayElementCount(CA);
+ llvm::Value* ElementCountPtr =
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), ElementCount);
+ EmitCXXAggrDestructorCall(D, ElementCountPtr, This);
+}
+
+/// EmitCXXAggrDestructorCall - calls the default destructor on array
+/// elements in reverse order of construction.
+void
+CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
+ llvm::Value *UpperCount,
+ llvm::Value *This) {
llvm::Value *One = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
1);
- uint64_t ElementCount = getContext().getConstantArrayElementCount(CA);
// Create a temporary for the loop index and initialize it with count of
// array elements.
llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
"loop.index");
// Index = ElementCount;
- llvm::Value* UpperCount =
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), ElementCount);
Builder.CreateStore(UpperCount, IndexPtr, false);
// Start the loop with a block that tests the condition.
@@ -543,7 +578,16 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
Counter = Builder.CreateLoad(IndexPtr);
Counter = Builder.CreateSub(Counter, One);
llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx");
- EmitCXXDestructorCall(D, Dtor_Complete, Address);
+ if (D->isVirtual()) {
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(D),
+ /*isVariadic=*/false);
+
+ llvm::Value *Callee = BuildVirtualCall(D, Dtor_Deleting, Address, Ty);
+ EmitCXXMemberCall(D, Callee, Address, 0, 0);
+ }
+ else
+ EmitCXXDestructorCall(D, Dtor_Complete, Address);
EmitBlock(ContinueBlock);
@@ -559,6 +603,50 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
EmitBlock(AfterFor, true);
}
+/// GenerateCXXAggrDestructorHelper - Generates a helper function which when invoked,
+/// calls the default destructor on array elements in reverse order of
+/// construction.
+llvm::Constant *
+CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
+ const ArrayType *Array,
+ llvm::Value *This) {
+ static int UniqueCount;
+ FunctionArgList Args;
+ ImplicitParamDecl *Dst =
+ ImplicitParamDecl::Create(getContext(), 0,
+ SourceLocation(), 0,
+ getContext().getPointerType(getContext().VoidTy));
+ Args.push_back(std::make_pair(Dst, Dst->getType()));
+
+ llvm::SmallString<16> Name;
+ llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueCount);
+ QualType R = getContext().VoidTy;
+ const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args);
+ const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
+ llvm::Function *Fn =
+ llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
+ Name.c_str(),
+ &CGM.getModule());
+ IdentifierInfo *II
+ = &CGM.getContext().Idents.get(Name.c_str());
+ FunctionDecl *FD = FunctionDecl::Create(getContext(),
+ getContext().getTranslationUnitDecl(),
+ SourceLocation(), II, R, 0,
+ FunctionDecl::Static,
+ false, true);
+ StartFunction(FD, R, Fn, Args, SourceLocation());
+ QualType BaseElementTy = getContext().getBaseElementType(Array);
+ const llvm::Type *BasePtr = ConvertType(BaseElementTy);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr = Builder.CreateBitCast(This, BasePtr);
+ EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
+ FinishFunction();
+ llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),
+ 0);
+ llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
+ return m;
+}
+
void
CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
CXXCtorType Type,
@@ -612,8 +700,13 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
// Code gen optimization to eliminate copy constructor and return
// its first argument instead.
if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
- CXXConstructExpr::const_arg_iterator i = E->arg_begin();
- EmitAggExpr((*i), Dest, false);
+ const Expr *Arg = E->getArg(0);
+
+ if (const CXXBindTemporaryExpr *BindExpr =
+ dyn_cast<CXXBindTemporaryExpr>(Arg))
+ Arg = BindExpr->getSubExpr();
+
+ EmitAggExpr(Arg, Dest, false);
return;
}
if (Array) {
@@ -649,8 +742,10 @@ void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D,
llvm::Function *
CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
CXXCtorType Type) {
+ const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>();
const llvm::FunctionType *FTy =
- getTypes().GetFunctionType(getTypes().getFunctionInfo(D), false);
+ getTypes().GetFunctionType(getTypes().getFunctionInfo(D),
+ FPT->isVariadic());
const char *Name = getMangledCXXCtorName(D, Type);
return cast<llvm::Function>(
@@ -668,6 +763,8 @@ const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D,
}
void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) {
+ if (D->isVirtual())
+ EmitCXXDestructor(D, Dtor_Deleting);
EmitCXXDestructor(D, Dtor_Complete);
EmitCXXDestructor(D, Dtor_Base);
}
@@ -919,20 +1016,35 @@ CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This,
return VBaseOffset;
}
+static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, int64_t VtableIndex,
+ llvm::Value *This, const llvm::Type *Ty) {
+ Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo();
+
+ llvm::Value *Vtable = CGF.Builder.CreateBitCast(This, Ty);
+ Vtable = CGF.Builder.CreateLoad(Vtable);
+
+ llvm::Value *VFuncPtr =
+ CGF.Builder.CreateConstInBoundsGEP1_64(Vtable, VtableIndex, "vfn");
+ return CGF.Builder.CreateLoad(VFuncPtr);
+}
+
llvm::Value *
-CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *&This,
+CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
const llvm::Type *Ty) {
- int64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD);
+ MD = MD->getCanonicalDecl();
+ int64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(MD);
- Ty = llvm::PointerType::get(Ty, 0);
- Ty = llvm::PointerType::get(Ty, 0);
- Ty = llvm::PointerType::get(Ty, 0);
- llvm::Value *vtbl = Builder.CreateBitCast(This, Ty);
- vtbl = Builder.CreateLoad(vtbl);
- llvm::Value *vfn = Builder.CreateConstInBoundsGEP1_64(vtbl,
- Index, "vfn");
- vfn = Builder.CreateLoad(vfn);
- return vfn;
+ return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
+}
+
+llvm::Value *
+CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
+ llvm::Value *&This, const llvm::Type *Ty) {
+ DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl());
+ int64_t VtableIndex =
+ CGM.getVtableInfo().getMethodVtableIndex(GlobalDecl(DD, Type));
+
+ return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
}
/// EmitClassAggrMemberwiseCopy - This routine generates code to copy a class
@@ -1269,8 +1381,16 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
// Do a built-in assignment of scalar data members.
LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
- RValue RVRHS = EmitLoadOfLValue(RHS, FieldType);
- EmitStoreThroughLValue(RVRHS, LHS, FieldType);
+ if (!hasAggregateLLVMType(Field->getType())) {
+ RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType());
+ EmitStoreThroughLValue(RVRHS, LHS, Field->getType());
+ } else if (Field->getType()->isAnyComplexType()) {
+ ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(),
+ RHS.isVolatileQualified());
+ StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified());
+ } else {
+ EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType());
+ }
}
FinishFunction();
}
@@ -1366,12 +1486,122 @@ void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD,
FinishFunction();
}
+static void EmitBaseInitializer(CodeGenFunction &CGF,
+ const CXXRecordDecl *ClassDecl,
+ CXXBaseOrMemberInitializer *BaseInit,
+ CXXCtorType CtorType) {
+ assert(BaseInit->isBaseInitializer() &&
+ "Must have base initializer!");
+
+ llvm::Value *ThisPtr = CGF.LoadCXXThis();
+
+ const Type *BaseType = BaseInit->getBaseClass();
+ CXXRecordDecl *BaseClassDecl =
+ cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
+ llvm::Value *V = CGF.GetAddressCXXOfBaseClass(ThisPtr, ClassDecl,
+ BaseClassDecl,
+ /*NullCheckValue=*/false);
+ CGF.EmitCXXConstructorCall(BaseInit->getConstructor(),
+ CtorType, V,
+ BaseInit->const_arg_begin(),
+ BaseInit->const_arg_end());
+}
+
+static void EmitMemberInitializer(CodeGenFunction &CGF,
+ const CXXRecordDecl *ClassDecl,
+ CXXBaseOrMemberInitializer *MemberInit) {
+ assert(MemberInit->isMemberInitializer() &&
+ "Must have member initializer!");
+
+ // non-static data member initializers.
+ FieldDecl *Field = MemberInit->getMember();
+ QualType FieldType = CGF.getContext().getCanonicalType(Field->getType());
+
+ llvm::Value *ThisPtr = CGF.LoadCXXThis();
+ LValue LHS;
+ if (FieldType->isReferenceType()) {
+ // FIXME: This is really ugly; should be refactored somehow
+ unsigned idx = CGF.CGM.getTypes().getLLVMFieldNo(Field);
+ llvm::Value *V = CGF.Builder.CreateStructGEP(ThisPtr, idx, "tmp");
+ assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs");
+ LHS = LValue::MakeAddr(V, CGF.MakeQualifiers(FieldType));
+ } else {
+ LHS = CGF.EmitLValueForField(ThisPtr, Field, ClassDecl->isUnion(), 0);
+ }
+
+ // If we are initializing an anonymous union field, drill down to the field.
+ if (MemberInit->getAnonUnionMember()) {
+ Field = MemberInit->getAnonUnionMember();
+ LHS = CGF.EmitLValueForField(LHS.getAddress(), Field,
+ /*IsUnion=*/true, 0);
+ FieldType = Field->getType();
+ }
+
+ // If the field is an array, branch based on the element type.
+ const ConstantArrayType *Array =
+ CGF.getContext().getAsConstantArrayType(FieldType);
+ if (Array)
+ FieldType = CGF.getContext().getBaseElementType(FieldType);
+
+ // We lose the constructor for anonymous union members, so handle them
+ // explicitly.
+ // FIXME: This is somwhat ugly.
+ if (MemberInit->getAnonUnionMember() && FieldType->getAs<RecordType>()) {
+ if (MemberInit->getNumArgs())
+ CGF.EmitAggExpr(*MemberInit->arg_begin(), LHS.getAddress(),
+ LHS.isVolatileQualified());
+ else
+ CGF.EmitAggregateClear(LHS.getAddress(), Field->getType());
+ return;
+ }
+
+ if (FieldType->getAs<RecordType>()) {
+ assert(MemberInit->getConstructor() &&
+ "EmitCtorPrologue - no constructor to initialize member");
+ if (Array) {
+ const llvm::Type *BasePtr = CGF.ConvertType(FieldType);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr);
+ CGF.EmitCXXAggrConstructorCall(MemberInit->getConstructor(),
+ Array, BaseAddrPtr);
+ }
+ else
+ CGF.EmitCXXConstructorCall(MemberInit->getConstructor(),
+ Ctor_Complete, LHS.getAddress(),
+ MemberInit->const_arg_begin(),
+ MemberInit->const_arg_end());
+ return;
+ }
+
+ assert(MemberInit->getNumArgs() == 1 && "Initializer count must be 1 only");
+ Expr *RhsExpr = *MemberInit->arg_begin();
+ RValue RHS;
+ if (FieldType->isReferenceType()) {
+ RHS = CGF.EmitReferenceBindingToExpr(RhsExpr, FieldType,
+ /*IsInitializer=*/true);
+ CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
+ } else if (Array) {
+ CGF.EmitMemSetToZero(LHS.getAddress(), Field->getType());
+ } else if (!CGF.hasAggregateLLVMType(RhsExpr->getType())) {
+ RHS = RValue::get(CGF.EmitScalarExpr(RhsExpr, true));
+ CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
+ } else if (RhsExpr->getType()->isAnyComplexType()) {
+ CGF.EmitComplexExprIntoAddr(RhsExpr, LHS.getAddress(),
+ LHS.isVolatileQualified());
+ } else {
+ // Handle member function pointers; other aggregates shouldn't get this far.
+ CGF.EmitAggExpr(RhsExpr, LHS.getAddress(), LHS.isVolatileQualified());
+ }
+}
+
/// EmitCtorPrologue - This routine generates necessary code to initialize
/// base classes and non-static data members belonging to this constructor.
/// FIXME: This needs to take a CXXCtorType.
void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
CXXCtorType CtorType) {
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext());
+ const CXXRecordDecl *ClassDecl = CD->getParent();
+
// FIXME: Add vbase initialization
llvm::Value *LoadOfThis = 0;
@@ -1379,136 +1609,18 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
E = CD->init_end();
B != E; ++B) {
CXXBaseOrMemberInitializer *Member = (*B);
- if (Member->isBaseInitializer()) {
- LoadOfThis = LoadCXXThis();
- Type *BaseType = Member->getBaseClass();
- CXXRecordDecl *BaseClassDecl =
- cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
- llvm::Value *V = GetAddressCXXOfBaseClass(LoadOfThis, ClassDecl,
- BaseClassDecl,
- /*NullCheckValue=*/false);
- EmitCXXConstructorCall(Member->getConstructor(),
- CtorType, V,
- Member->const_arg_begin(),
- Member->const_arg_end());
- } else {
- // non-static data member initilaizers.
- FieldDecl *Field = Member->getMember();
- QualType FieldType = getContext().getCanonicalType((Field)->getType());
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(FieldType);
+
+ assert(LiveTemporaries.empty() &&
+ "Should not have any live temporaries at initializer start!");
- LoadOfThis = LoadCXXThis();
- LValue LHS;
- if (FieldType->isReferenceType()) {
- // FIXME: This is really ugly; should be refactored somehow
- unsigned idx = CGM.getTypes().getLLVMFieldNo(Field);
- llvm::Value *V = Builder.CreateStructGEP(LoadOfThis, idx, "tmp");
- assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs");
- LHS = LValue::MakeAddr(V, MakeQualifiers(FieldType));
- } else {
- LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
- }
- if (FieldType->getAs<RecordType>()) {
- if (!Field->isAnonymousStructOrUnion()) {
- assert(Member->getConstructor() &&
- "EmitCtorPrologue - no constructor to initialize member");
- if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- EmitCXXAggrConstructorCall(Member->getConstructor(),
- Array, BaseAddrPtr);
- }
- else
- EmitCXXConstructorCall(Member->getConstructor(),
- Ctor_Complete, LHS.getAddress(),
- Member->const_arg_begin(),
- Member->const_arg_end());
- continue;
- }
- else {
- // Initializing an anonymous union data member.
- FieldDecl *anonMember = Member->getAnonUnionMember();
- LHS = EmitLValueForField(LHS.getAddress(), anonMember,
- /*IsUnion=*/true, 0);
- FieldType = anonMember->getType();
- }
- }
+ if (Member->isBaseInitializer())
+ EmitBaseInitializer(*this, ClassDecl, Member, CtorType);
+ else
+ EmitMemberInitializer(*this, ClassDecl, Member);
- assert(Member->getNumArgs() == 1 && "Initializer count must be 1 only");
- Expr *RhsExpr = *Member->arg_begin();
- RValue RHS;
- if (FieldType->isReferenceType())
- RHS = EmitReferenceBindingToExpr(RhsExpr, FieldType,
- /*IsInitializer=*/true);
- else if (FieldType->isMemberFunctionPointerType())
- RHS = RValue::get(CGM.EmitConstantExpr(RhsExpr, FieldType, this));
- else
- RHS = RValue::get(EmitScalarExpr(RhsExpr, true));
- EmitStoreThroughLValue(RHS, LHS, FieldType);
- }
- }
-
- if (!CD->getNumBaseOrMemberInitializers() && !CD->isTrivial()) {
- // Nontrivial default constructor with no initializer list. It may still
- // have bases classes and/or contain non-static data members which require
- // construction.
- for (CXXRecordDecl::base_class_const_iterator Base =
- ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- // FIXME. copy assignment of virtual base NYI
- if (Base->isVirtual())
- continue;
-
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (BaseClassDecl->hasTrivialConstructor())
- continue;
- if (CXXConstructorDecl *BaseCX =
- BaseClassDecl->getDefaultConstructor(getContext())) {
- LoadOfThis = LoadCXXThis();
- llvm::Value *V = GetAddressCXXOfBaseClass(LoadOfThis, ClassDecl,
- BaseClassDecl,
- /*NullCheckValue=*/false);
- EmitCXXConstructorCall(BaseCX, Ctor_Complete, V, 0, 0);
- }
- }
-
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = getContext().getCanonicalType((*Field)->getType());
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(FieldType);
- if (!FieldType->getAs<RecordType>() || Field->isAnonymousStructOrUnion())
- continue;
- const RecordType *ClassRec = FieldType->getAs<RecordType>();
- CXXRecordDecl *MemberClassDecl =
- dyn_cast<CXXRecordDecl>(ClassRec->getDecl());
- if (!MemberClassDecl || MemberClassDecl->hasTrivialConstructor())
- continue;
- if (CXXConstructorDecl *MamberCX =
- MemberClassDecl->getDefaultConstructor(getContext())) {
- LoadOfThis = LoadCXXThis();
- LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
- if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- EmitCXXAggrConstructorCall(MamberCX, Array, BaseAddrPtr);
- }
- else
- EmitCXXConstructorCall(MamberCX, Ctor_Complete, LHS.getAddress(),
- 0, 0);
- }
- }
+ // Pop any live temporaries that the initializers might have pushed.
+ while (!LiveTemporaries.empty())
+ PopCXXTemporary();
}
// Initialize the vtable pointer
@@ -1520,7 +1632,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
PtrPtr8Ty = llvm::PointerType::get(Ptr8Ty, 0);
VtableField = Builder.CreateBitCast(LoadOfThis, PtrPtr8Ty);
- llvm::Value *vtable = GenerateVtable(ClassDecl);
+ llvm::Value *vtable = CGM.getVtableInfo().getVtable(ClassDecl);
Builder.CreateStore(vtable, VtableField);
}
}
@@ -1531,138 +1643,117 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
/// FIXME: This needs to take a CXXDtorType.
void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
CXXDtorType DtorType) {
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(DD->getDeclContext());
- assert(!ClassDecl->getNumVBases() &&
- "FIXME: Destruction of virtual bases not supported");
- (void)ClassDecl; // prevent warning.
-
- for (CXXDestructorDecl::destr_const_iterator *B = DD->destr_begin(),
- *E = DD->destr_end(); B != E; ++B) {
- uintptr_t BaseOrMember = (*B);
- if (DD->isMemberToDestroy(BaseOrMember)) {
- FieldDecl *FD = DD->getMemberToDestroy(BaseOrMember);
- QualType FieldType = getContext().getCanonicalType((FD)->getType());
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(FieldType);
- const RecordType *RT = FieldType->getAs<RecordType>();
- CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (FieldClassDecl->hasTrivialDestructor())
- continue;
- llvm::Value *LoadOfThis = LoadCXXThis();
- LValue LHS = EmitLValueForField(LoadOfThis, FD, false, 0);
- if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()),
- Array, BaseAddrPtr);
- }
- else
- EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()),
- Dtor_Complete, LHS.getAddress());
- } else {
- const RecordType *RT =
- DD->getAnyBaseClassToDestroy(BaseOrMember)->getAs<RecordType>();
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (BaseClassDecl->hasTrivialDestructor())
- continue;
- llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(),
- ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()),
- DtorType, V);
- }
- }
- if (DD->getNumBaseOrMemberDestructions() || DD->isTrivial())
- return;
- // Case of destructor synthesis with fields and base classes
- // which have non-trivial destructors. They must be destructed in
- // reverse order of their construction.
- llvm::SmallVector<FieldDecl *, 16> DestructedFields;
+ assert(!DD->isTrivial() &&
+ "Should not emit dtor epilogue for trivial dtor!");
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = getContext().getCanonicalType((*Field)->getType());
- if (getContext().getAsConstantArrayType(FieldType))
- FieldType = getContext().getBaseElementType(FieldType);
- if (const RecordType *RT = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (FieldClassDecl->hasTrivialDestructor())
+ const CXXRecordDecl *ClassDecl = DD->getParent();
+
+ // Collect the fields.
+ llvm::SmallVector<const FieldDecl *, 16> FieldDecls;
+ for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
+ E = ClassDecl->field_end(); I != E; ++I) {
+ const FieldDecl *Field = *I;
+
+ QualType FieldType = getContext().getCanonicalType(Field->getType());
+ FieldType = getContext().getBaseElementType(FieldType);
+
+ const RecordType *RT = FieldType->getAs<RecordType>();
+ if (!RT)
+ continue;
+
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (FieldClassDecl->hasTrivialDestructor())
continue;
- DestructedFields.push_back(*Field);
- }
+
+ FieldDecls.push_back(Field);
}
- if (!DestructedFields.empty())
- for (int i = DestructedFields.size() -1; i >= 0; --i) {
- FieldDecl *Field = DestructedFields[i];
- QualType FieldType = Field->getType();
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(FieldType);
- const RecordType *RT = FieldType->getAs<RecordType>();
- CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- llvm::Value *LoadOfThis = LoadCXXThis();
- LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
- if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
+
+ // Now destroy the fields.
+ for (size_t i = FieldDecls.size(); i > 0; --i) {
+ const FieldDecl *Field = FieldDecls[i - 1];
+
+ QualType FieldType = Field->getType();
+ const ConstantArrayType *Array =
+ getContext().getAsConstantArrayType(FieldType);
+ if (Array)
+ FieldType = getContext().getBaseElementType(FieldType);
+
+ const RecordType *RT = FieldType->getAs<RecordType>();
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+
+ llvm::Value *ThisPtr = LoadCXXThis();
+
+ LValue LHS = EmitLValueForField(ThisPtr, Field,
+ /*isUnion=*/false,
+ // FIXME: Qualifiers?
+ /*CVRQualifiers=*/0);
+ if (Array) {
+ const llvm::Type *BasePtr = ConvertType(FieldType);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()),
- Array, BaseAddrPtr);
- }
- else
- EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()),
- Dtor_Complete, LHS.getAddress());
- }
+ EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()),
+ Array, BaseAddrPtr);
+ } else
+ EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()),
+ Dtor_Complete, LHS.getAddress());
+ }
- llvm::SmallVector<CXXRecordDecl*, 4> DestructedBases;
- for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- // FIXME. copy assignment of virtual base NYI
- if (Base->isVirtual())
+ // Destroy non-virtual bases.
+ for (CXXRecordDecl::reverse_base_class_const_iterator I =
+ ClassDecl->bases_rbegin(), E = ClassDecl->bases_rend(); I != E; ++I) {
+ const CXXBaseSpecifier &Base = *I;
+
+ // Ignore virtual bases.
+ if (Base.isVirtual())
continue;
-
+
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore trivial destructors.
if (BaseClassDecl->hasTrivialDestructor())
continue;
- DestructedBases.push_back(BaseClassDecl);
- }
- if (DestructedBases.empty())
- return;
- for (int i = DestructedBases.size() -1; i >= 0; --i) {
- CXXRecordDecl *BaseClassDecl = DestructedBases[i];
+
llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(),
- ClassDecl,BaseClassDecl,
+ ClassDecl, BaseClassDecl,
/*NullCheckValue=*/false);
EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()),
- Dtor_Complete, V);
+ Dtor_Base, V);
}
+
+ // If we're emitting a base destructor, we don't want to emit calls to the
+ // virtual bases.
+ if (DtorType == Dtor_Base)
+ return;
+
+ // FIXME: Handle virtual bases.
+ for (CXXRecordDecl::reverse_base_class_const_iterator I =
+ ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); I != E; ++I) {
+ assert(false && "FIXME: Handle virtual bases.");
+ }
+
+ // If we have a deleting destructor, emit a call to the delete operator.
+ if (DtorType == Dtor_Deleting)
+ EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(),
+ getContext().getTagDeclType(ClassDecl));
}
void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor,
CXXDtorType DtorType,
llvm::Function *Fn,
const FunctionArgList &Args) {
-
- const CXXRecordDecl *ClassDecl = Dtor->getParent();
- assert(!ClassDecl->hasUserDeclaredDestructor() &&
+ assert(!Dtor->getParent()->hasUserDeclaredDestructor() &&
"SynthesizeDefaultDestructor - destructor has user declaration");
- (void) ClassDecl;
StartFunction(GlobalDecl(Dtor, DtorType), Dtor->getResultType(), Fn, Args,
SourceLocation());
+
EmitDtorEpilogue(Dtor, DtorType);
FinishFunction();
}
-// FIXME: Move this to CGCXXStmt.cpp
+// FIXME: Move this to CGStmtCXX.cpp
void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
// FIXME: We need to do more here.
EmitStmt(S.getTryBlock());
diff --git a/lib/CodeGen/CGCXXClass.cpp b/lib/CodeGen/CGCXXClass.cpp
index 56a28fc..533aabc 100644
--- a/lib/CodeGen/CGCXXClass.cpp
+++ b/lib/CodeGen/CGCXXClass.cpp
@@ -31,6 +31,9 @@ ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths,
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class);
const CXXBaseSpecifier *BS = Element.Base;
+ // FIXME: enable test3 from virt.cc to not abort.
+ if (BS->isVirtual())
+ return 0;
assert(!BS->isVirtual() && "Should not see virtual bases here!");
const CXXRecordDecl *Base =
diff --git a/lib/CodeGen/CGCXXExpr.cpp b/lib/CodeGen/CGCXXExpr.cpp
index 2d62df6..cd7d21b 100644
--- a/lib/CodeGen/CGCXXExpr.cpp
+++ b/lib/CodeGen/CGCXXExpr.cpp
@@ -218,6 +218,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
if (NullCheckResult) {
Builder.CreateBr(NewEnd);
+ NewNotNull = Builder.GetInsertBlock();
EmitBlock(NewNull);
Builder.CreateBr(NewEnd);
EmitBlock(NewEnd);
@@ -233,12 +234,35 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
return NewPtr;
}
-void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
- if (E->isArrayForm()) {
- ErrorUnsupported(E, "delete[] expression");
- return;
- };
+void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
+ llvm::Value *Ptr,
+ QualType DeleteTy) {
+ const FunctionProtoType *DeleteFTy =
+ DeleteFD->getType()->getAs<FunctionProtoType>();
+
+ CallArgList DeleteArgs;
+
+ QualType ArgTy = DeleteFTy->getArgType(0);
+ llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy));
+ DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy));
+
+ if (DeleteFTy->getNumArgs() == 2) {
+ QualType SizeTy = DeleteFTy->getArgType(1);
+ uint64_t SizeVal = getContext().getTypeSize(DeleteTy) / 8;
+ llvm::Constant *Size = llvm::ConstantInt::get(ConvertType(SizeTy),
+ SizeVal);
+ DeleteArgs.push_back(std::make_pair(RValue::get(Size), SizeTy));
+ }
+
+ // Emit the call to delete.
+ EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(),
+ DeleteArgs),
+ CGM.GetAddrOfFunction(DeleteFD),
+ DeleteArgs, DeleteFD);
+}
+void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
+
// Get at the argument before we performed the implicit conversion
// to void*.
const Expr *Arg = E->getArgument();
@@ -264,41 +288,237 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull);
EmitBlock(DeleteNotNull);
-
+
+ bool ShouldCallDelete = true;
+
// Call the destructor if necessary.
if (const RecordType *RT = DeleteTy->getAs<RecordType>()) {
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
if (!RD->hasTrivialDestructor()) {
const CXXDestructorDecl *Dtor = RD->getDestructor(getContext());
- if (Dtor->isVirtual()) {
+ if (E->isArrayForm()) {
+ QualType SizeTy = getContext().getSizeType();
+ uint64_t CookiePadding = std::max(getContext().getTypeSize(SizeTy),
+ static_cast<uint64_t>(getContext().getTypeAlign(DeleteTy))) / 8;
+ if (CookiePadding) {
+ llvm::Type *Ptr8Ty =
+ llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
+ uint64_t CookieOffset =
+ CookiePadding - getContext().getTypeSize(SizeTy) / 8;
+ llvm::Value *AllocatedObjectPtr =
+ Builder.CreateConstInBoundsGEP1_64(
+ Builder.CreateBitCast(Ptr, Ptr8Ty), -CookiePadding);
+ llvm::Value *NumElementsPtr =
+ Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr,
+ CookieOffset);
+ NumElementsPtr = Builder.CreateBitCast(NumElementsPtr,
+ ConvertType(SizeTy)->getPointerTo());
+
+ llvm::Value *NumElements =
+ Builder.CreateLoad(NumElementsPtr);
+ NumElements =
+ Builder.CreateIntCast(NumElements,
+ llvm::Type::getInt64Ty(VMContext), false,
+ "count.tmp");
+ EmitCXXAggrDestructorCall(Dtor, NumElements, Ptr);
+ Ptr = AllocatedObjectPtr;
+ }
+ }
+ else if (Dtor->isVirtual()) {
const llvm::Type *Ty =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(Dtor),
/*isVariadic=*/false);
- llvm::Value *Callee = BuildVirtualCall(Dtor, Ptr, Ty);
+ llvm::Value *Callee = BuildVirtualCall(Dtor, Dtor_Deleting, Ptr, Ty);
EmitCXXMemberCall(Dtor, Callee, Ptr, 0, 0);
+
+ // The dtor took care of deleting the object.
+ ShouldCallDelete = false;
} else
EmitCXXDestructorCall(Dtor, Dtor_Complete, Ptr);
}
}
}
- // Call delete.
- FunctionDecl *DeleteFD = E->getOperatorDelete();
- const FunctionProtoType *DeleteFTy =
- DeleteFD->getType()->getAs<FunctionProtoType>();
+ if (ShouldCallDelete)
+ EmitDeleteCall(E->getOperatorDelete(), Ptr, DeleteTy);
- CallArgList DeleteArgs;
+ EmitBlock(DeleteEnd);
+}
- QualType ArgTy = DeleteFTy->getArgType(0);
- llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy));
- DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy));
+llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
+ QualType Ty = E->getType();
+ const llvm::Type *LTy = ConvertType(Ty)->getPointerTo();
+ if (E->isTypeOperand()) {
+ Ty = E->getTypeOperand();
+ CanQualType CanTy = CGM.getContext().getCanonicalType(Ty);
+ Ty = CanTy.getUnqualifiedType().getNonReferenceType();
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (RD->isPolymorphic())
+ return Builder.CreateBitCast(CGM.GenerateRttiRef(RD), LTy);
+ return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy);
+ }
+ return Builder.CreateBitCast(CGM.GenerateRttiNonClass(Ty), LTy);
+ }
+ Expr *subE = E->getExprOperand();
+ Ty = subE->getType();
+ CanQualType CanTy = CGM.getContext().getCanonicalType(Ty);
+ Ty = CanTy.getUnqualifiedType().getNonReferenceType();
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (RD->isPolymorphic()) {
+ // FIXME: if subE is an lvalue do
+ LValue Obj = EmitLValue(subE);
+ llvm::Value *This = Obj.getAddress();
+ LTy = LTy->getPointerTo()->getPointerTo();
+ llvm::Value *V = Builder.CreateBitCast(This, LTy);
+ // We need to do a zero check for *p, unless it has NonNullAttr.
+ // FIXME: PointerType->hasAttr<NonNullAttr>()
+ bool CanBeZero = false;
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(subE->IgnoreParens()))
+ if (UO->getOpcode() == UnaryOperator::Deref)
+ CanBeZero = true;
+ if (CanBeZero) {
+ llvm::BasicBlock *NonZeroBlock = createBasicBlock();
+ llvm::BasicBlock *ZeroBlock = createBasicBlock();
+
+ llvm::Value *Zero = llvm::Constant::getNullValue(LTy);
+ Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero),
+ NonZeroBlock, ZeroBlock);
+ EmitBlock(ZeroBlock);
+ /// Call __cxa_bad_typeid
+ const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext);
+ const llvm::FunctionType *FTy;
+ FTy = llvm::FunctionType::get(ResultType, false);
+ llvm::Value *F = CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid");
+ Builder.CreateCall(F)->setDoesNotReturn();
+ Builder.CreateUnreachable();
+ EmitBlock(NonZeroBlock);
+ }
+ V = Builder.CreateLoad(V, "vtable");
+ V = Builder.CreateConstInBoundsGEP1_64(V, -1ULL);
+ V = Builder.CreateLoad(V);
+ return V;
+ }
+ return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy);
+ }
+ return Builder.CreateBitCast(CGM.GenerateRttiNonClass(Ty), LTy);
+}
- // Emit the call to delete.
- EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(),
- DeleteArgs),
- CGM.GetAddrOfFunction(DeleteFD),
- DeleteArgs, DeleteFD);
+llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V,
+ const CXXDynamicCastExpr *DCE) {
+ QualType CastTy = DCE->getTypeAsWritten();
+ QualType InnerType = CastTy->getPointeeType();
+ QualType ArgTy = DCE->getSubExpr()->getType();
+ const llvm::Type *LArgTy = ConvertType(ArgTy);
+ const llvm::Type *LTy = ConvertType(DCE->getType());
+
+ bool CanBeZero = false;
+ bool ToVoid = false;
+ bool ThrowOnBad = false;
+ if (CastTy->isPointerType()) {
+ // FIXME: if PointerType->hasAttr<NonNullAttr>(), we don't set this
+ CanBeZero = true;
+ if (InnerType->isVoidType())
+ ToVoid = true;
+ } else {
+ LTy = LTy->getPointerTo();
+ ThrowOnBad = true;
+ }
- EmitBlock(DeleteEnd);
+ CXXRecordDecl *SrcTy;
+ QualType Ty = ArgTy;
+ if (ArgTy.getTypePtr()->isPointerType()
+ || ArgTy.getTypePtr()->isReferenceType())
+ Ty = Ty.getTypePtr()->getPointeeType();
+ CanQualType CanTy = CGM.getContext().getCanonicalType(Ty);
+ Ty = CanTy.getUnqualifiedType();
+ SrcTy = cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl());
+
+ llvm::BasicBlock *ContBlock = createBasicBlock();
+ llvm::BasicBlock *NullBlock = 0;
+ llvm::BasicBlock *NonZeroBlock = 0;
+ if (CanBeZero) {
+ NonZeroBlock = createBasicBlock();
+ NullBlock = createBasicBlock();
+ llvm::Value *Zero = llvm::Constant::getNullValue(LArgTy);
+ Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero),
+ NonZeroBlock, NullBlock);
+ EmitBlock(NonZeroBlock);
+ }
+
+ llvm::BasicBlock *BadCastBlock = 0;
+
+ const llvm::Type *PtrDiffTy = ConvertType(getContext().getSizeType());
+
+ // See if this is a dynamic_cast(void*)
+ if (ToVoid) {
+ llvm::Value *This = V;
+ V = Builder.CreateBitCast(This, PtrDiffTy->getPointerTo()->getPointerTo());
+ V = Builder.CreateLoad(V, "vtable");
+ V = Builder.CreateConstInBoundsGEP1_64(V, -2ULL);
+ V = Builder.CreateLoad(V, "offset to top");
+ This = Builder.CreateBitCast(This, llvm::Type::getInt8PtrTy(VMContext));
+ V = Builder.CreateInBoundsGEP(This, V);
+ V = Builder.CreateBitCast(V, LTy);
+ } else {
+ /// Call __dynamic_cast
+ const llvm::Type *ResultType = llvm::Type::getInt8PtrTy(VMContext);
+ const llvm::FunctionType *FTy;
+ std::vector<const llvm::Type*> ArgTys;
+ const llvm::Type *PtrToInt8Ty
+ = llvm::Type::getInt8Ty(VMContext)->getPointerTo();
+ ArgTys.push_back(PtrToInt8Ty);
+ ArgTys.push_back(PtrToInt8Ty);
+ ArgTys.push_back(PtrToInt8Ty);
+ ArgTys.push_back(PtrDiffTy);
+ FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
+ CXXRecordDecl *DstTy;
+ Ty = CastTy.getTypePtr()->getPointeeType();
+ CanTy = CGM.getContext().getCanonicalType(Ty);
+ Ty = CanTy.getUnqualifiedType();
+ DstTy = cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl());
+
+ // FIXME: Calculate better hint.
+ llvm::Value *hint = llvm::ConstantInt::get(PtrDiffTy, -1ULL);
+ llvm::Value *SrcArg = CGM.GenerateRttiRef(SrcTy);
+ llvm::Value *DstArg = CGM.GenerateRttiRef(DstTy);
+ V = Builder.CreateBitCast(V, PtrToInt8Ty);
+ V = Builder.CreateCall4(CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"),
+ V, SrcArg, DstArg, hint);
+ V = Builder.CreateBitCast(V, LTy);
+
+ if (ThrowOnBad) {
+ BadCastBlock = createBasicBlock();
+
+ llvm::Value *Zero = llvm::Constant::getNullValue(LTy);
+ Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero),
+ ContBlock, BadCastBlock);
+ EmitBlock(BadCastBlock);
+ /// Call __cxa_bad_cast
+ ResultType = llvm::Type::getVoidTy(VMContext);
+ const llvm::FunctionType *FBadTy;
+ FBadTy = llvm::FunctionType::get(ResultType, false);
+ llvm::Value *F = CGM.CreateRuntimeFunction(FBadTy, "__cxa_bad_cast");
+ Builder.CreateCall(F)->setDoesNotReturn();
+ Builder.CreateUnreachable();
+ }
+ }
+
+ if (CanBeZero) {
+ Builder.CreateBr(ContBlock);
+ EmitBlock(NullBlock);
+ Builder.CreateBr(ContBlock);
+ }
+ EmitBlock(ContBlock);
+ if (CanBeZero) {
+ llvm::PHINode *PHI = Builder.CreatePHI(LTy);
+ PHI->reserveOperandSpace(2);
+ PHI->addIncoming(V, NonZeroBlock);
+ PHI->addIncoming(llvm::Constant::getNullValue(LTy), NullBlock);
+ V = PHI;
+ }
+
+ return V;
}
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 06cd05c..d0c7d03 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -19,7 +19,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
-#include "clang/Frontend/CompileOptions.h"
+#include "clang/CodeGen/CodeGenOptions.h"
#include "llvm/Attributes.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Target/TargetData.h"
@@ -441,18 +441,13 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
RetAttrs |= llvm::Attribute::NoAlias;
}
- if (CompileOpts.OptimizeSize)
+ if (CodeGenOpts.OptimizeSize)
FuncAttrs |= llvm::Attribute::OptimizeForSize;
- if (CompileOpts.DisableRedZone)
+ if (CodeGenOpts.DisableRedZone)
FuncAttrs |= llvm::Attribute::NoRedZone;
- if (CompileOpts.NoImplicitFloat)
+ if (CodeGenOpts.NoImplicitFloat)
FuncAttrs |= llvm::Attribute::NoImplicitFloat;
- if (Features.getStackProtectorMode() == LangOptions::SSPOn)
- FuncAttrs |= llvm::Attribute::StackProtect;
- else if (Features.getStackProtectorMode() == LangOptions::SSPReq)
- FuncAttrs |= llvm::Attribute::StackProtectReq;
-
QualType RetTy = FI.getReturnType();
unsigned Index = 1;
const ABIArgInfo &RetAI = FI.getReturnInfo();
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 1b01e15..0551667 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -21,7 +21,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Version.h"
-#include "clang/Frontend/CompileOptions.h"
+#include "clang/CodeGen/CodeGenOptions.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
@@ -57,7 +57,7 @@ llvm::DIDescriptor CGDebugInfo::getContext(const VarDecl *Decl,
if (Decl->getDeclContext()->isFunctionOrMethod()) {
// Find the last subprogram in region stack.
for (unsigned RI = RegionStack.size(), RE = 0; RI != RE; --RI) {
- llvm::DIDescriptor R = RegionStack[RI - 1];
+ llvm::DIDescriptor R(RegionStack[RI - 1]);
if (R.isSubprogram())
return R;
}
@@ -136,10 +136,11 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
RuntimeVers = LO.ObjCNonFragileABI ? 2 : 1;
// Create new compile unit.
- return Unit = DebugFactory.CreateCompileUnit(LangTag, AbsFileName.getLast(),
- AbsFileName.getDirname(),
- Producer, isMain, isOptimized,
- Flags, RuntimeVers);
+ return Unit = DebugFactory.CreateCompileUnit(LangTag,
+ AbsFileName.getLast().c_str(),
+ AbsFileName.getDirname().c_str(),
+ Producer.c_str(), isMain,
+ isOptimized, Flags, RuntimeVers);
}
/// CreateType - Get the Basic type from the cache or create a new
@@ -178,8 +179,6 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT,
BT->getName(M->getContext().getLangOptions()),
Unit, 0, Size, Align,
Offset, /*flags*/ 0, Encoding);
-
- TypeCache[QualType(BT, 0).getAsOpaquePtr()] = DbgTy.getNode();
return DbgTy;
}
@@ -198,7 +197,6 @@ llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty,
DebugFactory.CreateBasicType(Unit, "complex",
Unit, 0, Size, Align,
Offset, /*flags*/ 0, Encoding);
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode();
return DbgTy;
}
@@ -236,38 +234,41 @@ llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DICompileUnit U
llvm::DIType DbgTy =
DebugFactory.CreateDerivedType(Tag, Unit, "", llvm::DICompileUnit(),
0, 0, 0, 0, 0, FromTy);
- TypeCache[Ty.getAsOpaquePtr()] = DbgTy.getNode();
return DbgTy;
}
llvm::DIType CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty,
llvm::DICompileUnit Unit) {
- llvm::DIType EltTy = getOrCreateType(Ty->getPointeeType(), Unit);
-
- // Bit size, align and offset of the type.
- uint64_t Size = M->getContext().getTypeSize(Ty);
- uint64_t Align = M->getContext().getTypeAlign(Ty);
-
llvm::DIType DbgTy =
- DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit,
- "", llvm::DICompileUnit(),
- 0, Size, Align, 0, 0, EltTy);
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode();
+ CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
+ Ty->getPointeeType(), Unit);
return DbgTy;
}
llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty,
llvm::DICompileUnit Unit) {
- llvm::DIType EltTy = getOrCreateType(Ty->getPointeeType(), Unit);
+ return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
+ Ty->getPointeeType(), Unit);
+}
+
+llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
+ const Type *Ty,
+ QualType PointeeTy,
+ llvm::DICompileUnit Unit) {
+ llvm::DIType EltTy = getOrCreateType(PointeeTy, Unit);
// Bit size, align and offset of the type.
- uint64_t Size = M->getContext().getTypeSize(Ty);
+
+ // Size is always the size of a pointer. We can't use getTypeSize here
+ // because that does not return the correct value for references.
+ uint64_t Size =
+ M->getContext().Target.getPointerWidth(PointeeTy.getAddressSpace());
uint64_t Align = M->getContext().getTypeAlign(Ty);
return
- DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit,
- "", llvm::DICompileUnit(),
+ DebugFactory.CreateDerivedType(Tag, Unit, "", llvm::DICompileUnit(),
0, Size, Align, 0, 0, EltTy);
+
}
llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
@@ -407,7 +408,6 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
// We don't set size information, but do specify where the typedef was
// declared.
- std::string TyName = Ty->getDecl()->getNameAsString();
SourceLocation DefLoc = Ty->getDecl()->getLocation();
llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc);
@@ -417,8 +417,8 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
llvm::DIType DbgTy =
DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_typedef, Unit,
- TyName, DefUnit, Line, 0, 0, 0, 0, Src);
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode();
+ Ty->getDecl()->getNameAsCString(),
+ DefUnit, Line, 0, 0, 0, 0, Src);
return DbgTy;
}
@@ -446,7 +446,6 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
Unit, "", llvm::DICompileUnit(),
0, 0, 0, 0, 0,
llvm::DIType(), EltTypeArray);
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode();
return DbgTy;
}
@@ -468,8 +467,6 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
SourceManager &SM = M->getContext().getSourceManager();
// Get overall information about the record type for the debug info.
- std::string Name = Decl->getNameAsString();
-
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
llvm::DICompileUnit DefUnit;
unsigned Line = 0;
@@ -485,13 +482,15 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
// may refer to the forward decl if the struct is recursive) and replace all
// uses of the forward declaration with the final definition.
llvm::DICompositeType FwdDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, 0, 0, 0, 0,
+ DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsString().data(),
+ DefUnit, Line, 0, 0, 0, 0,
llvm::DIType(), llvm::DIArray());
// If this is just a forward declaration, return it.
if (!Decl->getDefinition(M->getContext()))
return FwdDecl;
+ llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode();
// Otherwise, insert it into the TypeCache so that recursive uses will find
// it.
TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode();
@@ -508,10 +507,10 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
FieldDecl *Field = *I;
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
- std::string FieldName = Field->getNameAsString();
+ const char *FieldName = Field->getNameAsCString();
// Ignore unnamed fields.
- if (FieldName.empty())
+ if (!FieldName)
continue;
// Get the location for the field.
@@ -559,15 +558,13 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
uint64_t Align = M->getContext().getTypeAlign(Ty);
llvm::DICompositeType RealDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, Size,
- Align, 0, 0, llvm::DIType(), Elements);
-
- // Update TypeCache.
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl.getNode();
+ DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsString().data(),
+ DefUnit, Line, Size, Align, 0, 0,
+ llvm::DIType(), Elements);
// Now that we have a real decl for the struct, replace anything using the
// old decl with the new one. This will recursively update the debug info.
- FwdDecl.replaceAllUsesWith(RealDecl);
+ llvm::DIDerivedType(FwdDeclNode).replaceAllUsesWith(RealDecl);
return RealDecl;
}
@@ -581,8 +578,6 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
SourceManager &SM = M->getContext().getSourceManager();
// Get overall information about the record type for the debug info.
- std::string Name = Decl->getNameAsString();
-
llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(Decl->getLocation());
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine();
@@ -597,7 +592,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// may refer to the forward decl if the struct is recursive) and replace all
// uses of the forward declaration with the final definition.
llvm::DICompositeType FwdDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, 0, 0, 0, 0,
+ DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsCString(),
+ DefUnit, Line, 0, 0, 0, 0,
llvm::DIType(), llvm::DIArray(),
RuntimeLang);
@@ -605,6 +601,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
if (Decl->isForwardDecl())
return FwdDecl;
+ llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode();
// Otherwise, insert it into the TypeCache so that recursive uses will find
// it.
TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode();
@@ -631,10 +628,10 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
ObjCIvarDecl *Field = *I;
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
- std::string FieldName = Field->getNameAsString();
+ const char *FieldName = Field->getNameAsCString();
// Ignore unnamed fields.
- if (FieldName.empty())
+ if (!FieldName)
continue;
// Get the location for the field.
@@ -685,16 +682,13 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
uint64_t Align = M->getContext().getTypeAlign(Ty);
llvm::DICompositeType RealDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, Size,
- Align, 0, 0, llvm::DIType(), Elements,
- RuntimeLang);
-
- // Update TypeCache.
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl.getNode();
+ DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsCString(), DefUnit,
+ Line, Size, Align, 0, 0, llvm::DIType(),
+ Elements, RuntimeLang);
// Now that we have a real decl for the struct, replace anything using the
// old decl with the new one. This will recursively update the debug info.
- FwdDecl.replaceAllUsesWith(RealDecl);
+ llvm::DIDerivedType(FwdDeclNode).replaceAllUsesWith(RealDecl);
return RealDecl;
}
@@ -709,7 +703,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
for (EnumDecl::enumerator_iterator
Enum = Decl->enumerator_begin(), EnumEnd = Decl->enumerator_end();
Enum != EnumEnd; ++Enum) {
- Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getNameAsString(),
+ Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getNameAsCString(),
Enum->getInitVal().getZExtValue()));
}
@@ -717,7 +711,6 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
llvm::DIArray EltArray =
DebugFactory.GetOrCreateArray(Enumerators.data(), Enumerators.size());
- std::string EnumName = Decl->getNameAsString();
SourceLocation DefLoc = Decl->getLocation();
llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc);
SourceManager &SM = M->getContext().getSourceManager();
@@ -735,11 +728,9 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
llvm::DIType DbgTy =
DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_enumeration_type,
- Unit, EnumName, DefUnit, Line,
+ Unit, Decl->getNameAsCString(), DefUnit, Line,
Size, Align, 0, 0,
llvm::DIType(), EltArray);
-
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode();
return DbgTy;
}
@@ -797,11 +788,37 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
0, Size, Align, 0, 0,
getOrCreateType(EltTy, Unit),
SubscriptArray);
-
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode();
return DbgTy;
}
+llvm::DIType CGDebugInfo::CreateType(const LValueReferenceType *Ty,
+ llvm::DICompileUnit Unit) {
+ return CreatePointerLikeType(llvm::dwarf::DW_TAG_reference_type,
+ Ty, Ty->getPointeeType(), Unit);
+}
+
+static QualType CanonicalizeTypeForDebugInfo(QualType T) {
+ switch (T->getTypeClass()) {
+ default:
+ return T;
+ case Type::TemplateSpecialization:
+ return cast<TemplateSpecializationType>(T)->desugar();
+ case Type::TypeOfExpr: {
+ TypeOfExprType *Ty = cast<TypeOfExprType>(T);
+ return CanonicalizeTypeForDebugInfo(Ty->getUnderlyingExpr()->getType());
+ }
+ case Type::TypeOf:
+ return cast<TypeOfType>(T)->getUnderlyingType();
+ case Type::Decltype:
+ return cast<DecltypeType>(T)->getUnderlyingType();
+ case Type::QualifiedName:
+ return cast<QualifiedNameType>(T)->getNamedType();
+ case Type::SubstTemplateTypeParm:
+ return cast<SubstTemplateTypeParmType>(T)->getReplacementType();
+ case Type::Elaborated:
+ return cast<ElaboratedType>(T)->getUnderlyingType();
+ }
+}
/// getOrCreateType - Get the type from the cache or create a new
/// one if necessary.
@@ -810,6 +827,9 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
if (Ty.isNull())
return llvm::DIType();
+ // Canonicalize the type.
+ Ty = CanonicalizeTypeForDebugInfo(Ty);
+
// Check for existing entry.
std::map<void *, llvm::WeakVH>::iterator it =
TypeCache.find(Ty.getAsOpaquePtr());
@@ -821,15 +841,17 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
// Otherwise create the type.
llvm::DIType Res = CreateTypeNode(Ty, Unit);
+
+ // And update the type cache.
+ TypeCache[Ty.getAsOpaquePtr()] = Res.getNode();
return Res;
}
-/// getOrCreateTypeNode - Get the type metadata node from the cache or create a
-/// new one if necessary.
+/// CreateTypeNode - Create a new debug type node.
llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
llvm::DICompileUnit Unit) {
// Handle qualifiers, which recursively handles what they refer to.
- if (Ty.hasQualifiers())
+ if (Ty.hasLocalQualifiers())
return CreateQualifiedType(Ty, Unit);
// Work out details of type.
@@ -841,16 +863,13 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
#include "clang/AST/TypeNodes.def"
assert(false && "Dependent types cannot show up in debug information");
- default:
- case Type::LValueReference:
- case Type::RValueReference:
- case Type::Vector:
+ // FIXME: Handle these.
case Type::ExtVector:
+ case Type::Vector:
case Type::FixedWidthInt:
- case Type::MemberPointer:
- case Type::TemplateSpecialization:
- case Type::QualifiedName:
- // Unsupported types
+ return llvm::DIType();
+ default:
+ assert(false && "Unhandled type class!");
return llvm::DIType();
case Type::ObjCObjectPointer:
return CreateType(cast<ObjCObjectPointerType>(Ty), Unit);
@@ -868,21 +887,14 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
case Type::FunctionProto:
case Type::FunctionNoProto:
return CreateType(cast<FunctionType>(Ty), Unit);
- case Type::Elaborated:
- return getOrCreateType(cast<ElaboratedType>(Ty)->getUnderlyingType(),
- Unit);
-
case Type::ConstantArray:
case Type::VariableArray:
case Type::IncompleteArray:
return CreateType(cast<ArrayType>(Ty), Unit);
- case Type::TypeOfExpr:
- return getOrCreateType(cast<TypeOfExprType>(Ty)->getUnderlyingExpr()
- ->getType(), Unit);
- case Type::TypeOf:
- return getOrCreateType(cast<TypeOfType>(Ty)->getUnderlyingType(), Unit);
- case Type::Decltype:
- return getOrCreateType(cast<DecltypeType>(Ty)->getUnderlyingType(), Unit);
+
+ case Type::LValueReference:
+ return CreateType(cast<LValueReferenceType>(Ty), Unit);
+
}
}
@@ -909,12 +921,8 @@ void CGDebugInfo::EmitFunctionStart(const char *Name, QualType FnType,
getOrCreateType(FnType, Unit),
Fn->hasInternalLinkage(), true/*definition*/);
-#ifndef ATTACH_DEBUG_INFO_TO_AN_INSN
- DebugFactory.InsertSubprogramStart(SP, Builder.GetInsertBlock());
-#endif
-
// Push function on region stack.
- RegionStack.push_back(SP);
+ RegionStack.push_back(SP.getNode());
}
@@ -936,31 +944,23 @@ void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) {
llvm::DICompileUnit Unit = getOrCreateCompileUnit(CurLoc);
PresumedLoc PLoc = SM.getPresumedLoc(CurLoc);
-#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN
- llvm::DIDescriptor DR = RegionStack.back();
+ llvm::DIDescriptor DR(RegionStack.back());
llvm::DIScope DS = llvm::DIScope(DR.getNode());
llvm::DILocation DO(NULL);
llvm::DILocation DL =
DebugFactory.CreateLocation(PLoc.getLine(), PLoc.getColumn(),
DS, DO);
Builder.SetCurrentDebugLocation(DL.getNode());
-#else
- DebugFactory.InsertStopPoint(Unit, PLoc.getLine(), PLoc.getColumn(),
- Builder.GetInsertBlock());
-#endif
}
/// EmitRegionStart- Constructs the debug code for entering a declarative
/// region - "llvm.dbg.region.start.".
void CGDebugInfo::EmitRegionStart(llvm::Function *Fn, CGBuilderTy &Builder) {
- llvm::DIDescriptor D;
- if (!RegionStack.empty())
- D = RegionStack.back();
- D = DebugFactory.CreateLexicalBlock(D);
- RegionStack.push_back(D);
-#ifndef ATTACH_DEBUG_INFO_TO_AN_INSN
- DebugFactory.InsertRegionStart(D, Builder.GetInsertBlock());
-#endif
+ llvm::DIDescriptor D =
+ DebugFactory.CreateLexicalBlock(RegionStack.empty() ?
+ llvm::DIDescriptor() :
+ llvm::DIDescriptor(RegionStack.back()));
+ RegionStack.push_back(D.getNode());
}
/// EmitRegionEnd - Constructs the debug code for exiting a declarative
@@ -971,9 +971,6 @@ void CGDebugInfo::EmitRegionEnd(llvm::Function *Fn, CGBuilderTy &Builder) {
// Provide an region stop point.
EmitStopPoint(Fn, Builder);
-#ifndef ATTACH_DEBUG_INFO_TO_AN_INSN
- DebugFactory.InsertRegionEnd(RegionStack.back(), Builder.GetInsertBlock());
-#endif
RegionStack.pop_back();
}
@@ -985,8 +982,8 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
// Do not emit variable debug information while generating optimized code.
// The llvm optimizer and code generator are not yet ready to support
// optimized code debugging.
- const CompileOptions &CO = M->getCompileOpts();
- if (CO.OptimizationLevel)
+ const CodeGenOptions &CGO = M->getCodeGenOpts();
+ if (CGO.OptimizationLevel)
return;
llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
@@ -1105,10 +1102,9 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = M->getContext().getTypeSize(FType);
FieldAlign = Align*8;
- std::string Name = Decl->getNameAsString();
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- Name, DefUnit,
+ Decl->getNameAsCString(), DefUnit,
0, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
@@ -1128,18 +1124,28 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
SourceManager &SM = M->getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
unsigned Line = 0;
- if (!PLoc.isInvalid())
+ unsigned Column = 0;
+ if (!PLoc.isInvalid()) {
Line = PLoc.getLine();
- else
+ Column = PLoc.getColumn();
+ } else {
Unit = llvm::DICompileUnit();
-
+ }
// Create the descriptor for the variable.
llvm::DIVariable D =
- DebugFactory.CreateVariable(Tag, RegionStack.back(),Decl->getNameAsString(),
+ DebugFactory.CreateVariable(Tag, llvm::DIDescriptor(RegionStack.back()),
+ Decl->getNameAsCString(),
Unit, Line, Ty);
// Insert an llvm.dbg.declare into the current block.
- DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock());
+ llvm::Instruction *Call =
+ DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock());
+
+ llvm::DIScope DS(RegionStack.back());
+ llvm::DILocation DO(NULL);
+ llvm::DILocation DL =
+ DebugFactory.CreateLocation(Line, Column, DS, DO);
+ Builder.SetDebugLocation(Call, DL.getNode());
}
/// EmitDeclare - Emit local variable declaration debug info.
@@ -1152,8 +1158,8 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
// Do not emit variable debug information while generating optimized code.
// The llvm optimizer and code generator are not yet ready to support
// optimized code debugging.
- const CompileOptions &CO = M->getCompileOpts();
- if (CO.OptimizationLevel || Builder.GetInsertBlock() == 0)
+ const CodeGenOptions &CGO = M->getCodeGenOpts();
+ if (CGO.OptimizationLevel || Builder.GetInsertBlock() == 0)
return;
uint64_t XOffset = 0;
@@ -1273,11 +1279,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = M->getContext().getTypeSize(FType);
FieldAlign = Align*8;
- std::string Name = Decl->getNameAsString();
XOffset = FieldOffset;
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- Name, DefUnit,
+ Decl->getNameAsCString(), DefUnit,
0, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
@@ -1330,11 +1335,18 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
// Create the descriptor for the variable.
llvm::DIVariable D =
- DebugFactory.CreateComplexVariable(Tag, RegionStack.back(),
- Decl->getNameAsString(), Unit, Line, Ty,
+ DebugFactory.CreateComplexVariable(Tag, llvm::DIDescriptor(RegionStack.back()),
+ Decl->getNameAsCString(), Unit, Line, Ty,
addr);
// Insert an llvm.dbg.declare into the current block.
- DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertPoint());
+ llvm::Instruction *Call =
+ DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertPoint());
+
+ llvm::DIScope DS(RegionStack.back());
+ llvm::DILocation DO(NULL);
+ llvm::DILocation DL =
+ DebugFactory.CreateLocation(Line, PLoc.getColumn(), DS, DO);
+ Builder.SetDebugLocation(Call, DL.getNode());
}
void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *Decl,
@@ -1362,21 +1374,12 @@ void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI,
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
const VarDecl *Decl) {
- // Do not emit variable debug information while generating optimized code.
- // The llvm optimizer and code generator are not yet ready to support
- // optimized code debugging.
- const CompileOptions &CO = M->getCompileOpts();
- if (CO.OptimizationLevel)
- return;
-
// Create global variable debug descriptor.
llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
SourceManager &SM = M->getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
- std::string Name = Var->getName();
-
QualType T = Decl->getType();
if (T->isIncompleteArrayType()) {
@@ -1389,9 +1392,9 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
T = M->getContext().getConstantArrayType(ET, ConstVal,
ArrayType::Normal, 0);
}
-
- DebugFactory.CreateGlobalVariable(getContext(Decl, Unit),
- Name, Name, Name, Unit, LineNo,
+ const char *DeclName = Decl->getNameAsCString();
+ DebugFactory.CreateGlobalVariable(getContext(Decl, Unit), DeclName, DeclName,
+ NULL, Unit, LineNo,
getOrCreateType(T, Unit),
Var->hasInternalLinkage(),
true/*definition*/, Var);
@@ -1406,7 +1409,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
- std::string Name = Decl->getNameAsString();
+ const char *Name = Decl->getNameAsCString();
QualType T = M->getContext().getObjCInterfaceType(Decl);
if (T->isIncompleteArrayType()) {
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 2e44e09..af86e2b 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -56,7 +56,7 @@ class CGDebugInfo {
bool BlockLiteralGenericSet;
llvm::DIType BlockLiteralGeneric;
- std::vector<llvm::DIDescriptor> RegionStack;
+ std::vector<llvm::TrackingVH<llvm::MDNode> > RegionStack;
/// Helper functions for getOrCreateType.
llvm::DIType CreateType(const BuiltinType *Ty, llvm::DICompileUnit U);
@@ -73,7 +73,11 @@ class CGDebugInfo {
llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DICompileUnit U);
llvm::DIType CreateType(const EnumType *Ty, llvm::DICompileUnit U);
llvm::DIType CreateType(const ArrayType *Ty, llvm::DICompileUnit U);
+ llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DICompileUnit U);
+ llvm::DIType CreatePointerLikeType(unsigned Tag,
+ const Type *Ty, QualType PointeeTy,
+ llvm::DICompileUnit U);
public:
CGDebugInfo(CodeGenModule *m);
~CGDebugInfo();
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 2021ced..1d2040b 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -19,7 +19,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Frontend/CompileOptions.h"
+#include "clang/CodeGen/CodeGenOptions.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Intrinsics.h"
#include "llvm/Target/TargetData.h"
@@ -320,7 +320,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
// All constant structs and arrays should be global if
// their initializer is constant and if the element type is POD.
- if (CGM.getCompileOpts().MergeAllConstants) {
+ if (CGM.getCodeGenOpts().MergeAllConstants) {
if (Ty.isConstant(getContext())
&& (Ty->isArrayType() || Ty->isRecordType())
&& (D.getInit()
@@ -507,7 +507,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
// Handle CXX destruction of variables.
QualType DtorTy(Ty);
- if (const ArrayType *Array = DtorTy->getAs<ArrayType>())
+ while (const ArrayType *Array = getContext().getAsArrayType(DtorTy))
DtorTy = getContext().getBaseElementType(Array);
if (const RecordType *RT = DtorTy->getAs<RecordType>())
if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index d9dd70a..2a544c5 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -267,6 +267,12 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitCXXBindTemporaryLValue(cast<CXXBindTemporaryExpr>(E));
case Expr::CXXExprWithTemporariesClass:
return EmitCXXExprWithTemporariesLValue(cast<CXXExprWithTemporaries>(E));
+ case Expr::CXXZeroInitValueExprClass:
+ return EmitNullInitializationLValue(cast<CXXZeroInitValueExpr>(E));
+ case Expr::CXXDefaultArgExprClass:
+ return EmitLValue(cast<CXXDefaultArgExpr>(E)->getExpr());
+ case Expr::CXXTypeidExprClass:
+ return EmitCXXTypeidLValue(cast<CXXTypeidExpr>(E));
case Expr::ObjCMessageExprClass:
return EmitObjCMessageExprLValue(cast<ObjCMessageExpr>(E));
@@ -303,8 +309,6 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::CXXReinterpretCastExprClass:
case Expr::CXXConstCastExprClass:
return EmitCastLValue(cast<CastExpr>(E));
- case Expr::CXXZeroInitValueExprClass:
- return EmitNullInitializationLValue(cast<CXXZeroInitValueExpr>(E));
}
}
@@ -813,53 +817,53 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
}
}
+static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
+ const Expr *E, const VarDecl *VD) {
+ assert((VD->hasExternalStorage() || VD->isFileVarDecl()) &&
+ "Var decl must have external storage or be a file var decl!");
+
+ llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD);
+ if (VD->getType()->isReferenceType())
+ V = CGF.Builder.CreateLoad(V, "tmp");
+ LValue LV = LValue::MakeAddr(V, CGF.MakeQualifiers(E->getType()));
+ setObjCGCLValueClass(CGF.getContext(), E, LV);
+ return LV;
+}
+
LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
- const VarDecl *VD = dyn_cast<VarDecl>(E->getDecl());
-
- if (VD && (VD->isBlockVarDecl() || isa<ParmVarDecl>(VD) ||
- isa<ImplicitParamDecl>(VD))) {
- LValue LV;
- bool NonGCable = VD->hasLocalStorage() &&
- !VD->hasAttr<BlocksAttr>();
- if (VD->hasExternalStorage()) {
- llvm::Value *V = CGM.GetAddrOfGlobalVar(VD);
- if (VD->getType()->isReferenceType())
- V = Builder.CreateLoad(V, "tmp");
- LV = LValue::MakeAddr(V, MakeQualifiers(E->getType()));
- } else {
- llvm::Value *V = LocalDeclMap[VD];
- assert(V && "DeclRefExpr not entered in LocalDeclMap?");
-
- Qualifiers Quals = MakeQualifiers(E->getType());
- // local variables do not get their gc attribute set.
- // local static?
- if (NonGCable) Quals.removeObjCGCAttr();
-
- if (VD->hasAttr<BlocksAttr>()) {
- V = Builder.CreateStructGEP(V, 1, "forwarding");
- V = Builder.CreateLoad(V, false);
- V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD),
- VD->getNameAsString());
- }
- if (VD->getType()->isReferenceType())
- V = Builder.CreateLoad(V, "tmp");
- LV = LValue::MakeAddr(V, Quals);
+ const NamedDecl *ND = E->getDecl();
+
+ if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
+
+ // Check if this is a global variable.
+ if (VD->hasExternalStorage() || VD->isFileVarDecl())
+ return EmitGlobalVarDeclLValue(*this, E, VD);
+
+ bool NonGCable = VD->hasLocalStorage() && !VD->hasAttr<BlocksAttr>();
+
+ llvm::Value *V = LocalDeclMap[VD];
+ assert(V && "DeclRefExpr not entered in LocalDeclMap?");
+
+ Qualifiers Quals = MakeQualifiers(E->getType());
+ // local variables do not get their gc attribute set.
+ // local static?
+ if (NonGCable) Quals.removeObjCGCAttr();
+
+ if (VD->hasAttr<BlocksAttr>()) {
+ V = Builder.CreateStructGEP(V, 1, "forwarding");
+ V = Builder.CreateLoad(V, false);
+ V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD),
+ VD->getNameAsString());
}
- LValue::SetObjCNonGC(LV, NonGCable);
- setObjCGCLValueClass(getContext(), E, LV);
- return LV;
- }
-
- if (VD && VD->isFileVarDecl()) {
- llvm::Value *V = CGM.GetAddrOfGlobalVar(VD);
if (VD->getType()->isReferenceType())
V = Builder.CreateLoad(V, "tmp");
- LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType()));
+ LValue LV = LValue::MakeAddr(V, Quals);
+ LValue::SetObjCNonGC(LV, NonGCable);
setObjCGCLValueClass(getContext(), E, LV);
return LV;
}
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(E->getDecl())) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
llvm::Value* V = CGM.GetAddrOfFunction(FD);
if (!FD->hasPrototype()) {
if (const FunctionProtoType *Proto =
@@ -876,20 +880,15 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
return LValue::MakeAddr(V, MakeQualifiers(E->getType()));
}
- if (const ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(E->getDecl())){
- llvm::Value *V = LocalDeclMap[IPD];
- assert(V && "BlockVarDecl not entered in LocalDeclMap?");
- return LValue::MakeAddr(V, MakeQualifiers(E->getType()));
- }
-
if (E->getQualifier()) {
// FIXME: the qualifier check does not seem sufficient here
- return EmitPointerToDataMemberLValue(E);
+ return EmitPointerToDataMemberLValue(cast<FieldDecl>(ND));
}
- assert(0 && "Unimp declref");
- //an invalid LValue, but the assert will
- //ensure that this point is never reached.
+ assert(false && "Unhandled DeclRefExpr");
+
+ // an invalid LValue, but the assert will
+ // ensure that this point is never reached.
return LValue();
}
@@ -924,13 +923,17 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
return LV;
}
case UnaryOperator::Real:
- case UnaryOperator::Imag:
+ case UnaryOperator::Imag: {
LValue LV = EmitLValue(E->getSubExpr());
unsigned Idx = E->getOpcode() == UnaryOperator::Imag;
return LValue::MakeAddr(Builder.CreateStructGEP(LV.getAddress(),
Idx, "idx"),
MakeQualifiers(ExprTy));
}
+ case UnaryOperator::PreInc:
+ case UnaryOperator::PreDec:
+ return EmitUnsupportedLValue(E, "pre-inc/dec expression");
+ }
}
LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) {
@@ -1151,18 +1154,24 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
BaseQuals = BaseTy.getQualifiers();
}
- FieldDecl *Field = dyn_cast<FieldDecl>(E->getMemberDecl());
- // FIXME: Handle non-field member expressions
- assert(Field && "No code generation for non-field member references");
- LValue MemExpLV = EmitLValueForField(BaseValue, Field, isUnion,
- BaseQuals.getCVRQualifiers());
- LValue::SetObjCNonGC(MemExpLV, isNonGC);
- setObjCGCLValueClass(getContext(), E, MemExpLV);
- return MemExpLV;
+ NamedDecl *ND = E->getMemberDecl();
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(ND)) {
+ LValue LV = EmitLValueForField(BaseValue, Field, isUnion,
+ BaseQuals.getCVRQualifiers());
+ LValue::SetObjCNonGC(LV, isNonGC);
+ setObjCGCLValueClass(getContext(), E, LV);
+ return LV;
+ }
+
+ if (VarDecl *VD = dyn_cast<VarDecl>(ND))
+ return EmitGlobalVarDeclLValue(*this, E, VD);
+
+ assert(false && "Unhandled member declaration!");
+ return LValue();
}
LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue,
- FieldDecl* Field,
+ const FieldDecl* Field,
unsigned CVRQualifiers) {
CodeGenTypes::BitFieldInfo Info = CGM.getTypes().getBitFieldInfo(Field);
@@ -1187,7 +1196,7 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue,
}
LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue,
- FieldDecl* Field,
+ const FieldDecl* Field,
bool isUnion,
unsigned CVRQualifiers) {
if (Field->isBitField())
@@ -1281,22 +1290,26 @@ CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) {
return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
}
-/// EmitCastLValue - Casts are never lvalues. If a cast is needed by the code
-/// generator in an lvalue context, then it must mean that we need the address
-/// of an aggregate in order to access one of its fields. This can happen for
-/// all the reasons that casts are permitted with aggregate result, including
-/// noop aggregate casts, and cast from scalar to union.
+/// EmitCastLValue - Casts are never lvalues unless that cast is a dynamic_cast.
+/// If the cast is a dynamic_cast, we can have the usual lvalue result,
+/// otherwise if a cast is needed by the code generator in an lvalue context,
+/// then it must mean that we need the address of an aggregate in order to
+/// access one of its fields. This can happen for all the reasons that casts
+/// are permitted with aggregate result, including noop aggregate casts, and
+/// cast from scalar to union.
LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
switch (E->getCastKind()) {
default:
- // If this is an lvalue cast, treat it as a no-op.
- // FIXME: We shouldn't need to check for this explicitly!
- if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
- if (ICE->isLvalueCast())
- return EmitLValue(E->getSubExpr());
-
- assert(0 && "Unhandled cast!");
-
+ return EmitUnsupportedLValue(E, "unexpected cast lvalue");
+
+ case CastExpr::CK_Dynamic: {
+ LValue LV = EmitLValue(E->getSubExpr());
+ llvm::Value *V = LV.getAddress();
+ const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(E);
+ return LValue::MakeAddr(EmitDynamicCast(V, DCE),
+ MakeQualifiers(E->getType()));
+ }
+
case CastExpr::CK_NoOp:
case CastExpr::CK_ConstructorConversion:
case CastExpr::CK_UserDefinedConversion:
@@ -1320,13 +1333,24 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
return LValue::MakeAddr(Base, MakeQualifiers(E->getType()));
}
-
case CastExpr::CK_ToUnion: {
llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType()));
EmitAnyExpr(E->getSubExpr(), Temp, false);
return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
- }
+ }
+ case CastExpr::CK_BaseToDerived: {
+ return EmitUnsupportedLValue(E, "base-to-derived cast lvalue");
+ }
+ case CastExpr::CK_BitCast: {
+ // This must be a reinterpret_cast (or c-style equivalent).
+ const ExplicitCastExpr *CE = cast<ExplicitCastExpr>(E);
+
+ LValue LV = EmitLValue(E->getSubExpr());
+ llvm::Value *V = Builder.CreateBitCast(LV.getAddress(),
+ ConvertType(CE->getTypeAsWritten()));
+ return LValue::MakeAddr(V, MakeQualifiers(E->getType()));
+ }
}
}
@@ -1449,6 +1473,12 @@ LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) {
}
LValue
+CodeGenFunction::EmitCXXTypeidLValue(const CXXTypeidExpr *E) {
+ llvm::Value *Temp = EmitCXXTypeidExpr(E);
+ return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
+}
+
+LValue
CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) {
LValue LV = EmitLValue(E->getSubExpr());
PushCXXTemporary(E->getTemporary(), LV.getAddress());
@@ -1526,19 +1556,18 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) {
}
-LValue CodeGenFunction::EmitPointerToDataMemberLValue(const DeclRefExpr *E) {
- const FieldDecl *Field = cast<FieldDecl>(E->getDecl());
+LValue CodeGenFunction::EmitPointerToDataMemberLValue(const FieldDecl *Field) {
const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Field->getDeclContext());
QualType NNSpecTy =
getContext().getCanonicalType(
getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(ClassDecl)));
NNSpecTy = getContext().getPointerType(NNSpecTy);
llvm::Value *V = llvm::Constant::getNullValue(ConvertType(NNSpecTy));
- LValue MemExpLV = EmitLValueForField(V, const_cast<FieldDecl*>(Field),
- /*isUnion*/false, /*Qualifiers*/0);
+ LValue MemExpLV = EmitLValueForField(V, Field, /*isUnion=*/false,
+ /*Qualifiers=*/0);
const llvm::Type *ResultType = ConvertType(getContext().getPointerDiffType());
V = Builder.CreatePtrToInt(MemExpLV.getAddress(), ResultType, "datamember");
- return LValue::MakeAddr(V, MakeQualifiers(E->getType()));
+ return LValue::MakeAddr(V, MakeQualifiers(Field->getType()));
}
RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType,
@@ -1571,16 +1600,14 @@ RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType,
LValue CodeGenFunction::
EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) {
- llvm::Value *BaseV = EmitLValue(E->getLHS()).getAddress();
+ llvm::Value *BaseV;
if (E->getOpcode() == BinaryOperator::PtrMemI)
- BaseV = Builder.CreateLoad(BaseV, "indir.ptr");
+ BaseV = EmitScalarExpr(E->getLHS());
+ else
+ BaseV = EmitLValue(E->getLHS()).getAddress();
const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(getLLVMContext());
BaseV = Builder.CreateBitCast(BaseV, i8Ty);
- LValue RHSLV = EmitLValue(E->getRHS());
- llvm::Value *OffsetV =
- EmitLoadOfLValue(RHSLV, E->getRHS()->getType()).getScalarVal();
- const llvm::Type* ResultType = ConvertType(getContext().getPointerDiffType());
- OffsetV = Builder.CreateBitCast(OffsetV, ResultType);
+ llvm::Value *OffsetV = EmitScalarExpr(E->getRHS());
llvm::Value *AddV = Builder.CreateInBoundsGEP(BaseV, OffsetV, "add.ptr");
QualType Ty = E->getRHS()->getType();
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 901f867..0e10368 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -114,6 +114,7 @@ public:
void VisitCXXConstructExpr(const CXXConstructExpr *E);
void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E);
void VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E);
+ void VisitCXXTypeidExpr(CXXTypeidExpr *E) { EmitAggLoadOfLValue(E); }
void VisitVAArgExpr(VAArgExpr *E);
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 9145d92..40b845d 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -262,7 +262,7 @@ class VISIBILITY_HIDDEN ConstStructBuilder {
uint64_t NumBytes =
AlignedElementOffsetInBytes - ElementOffsetInBytes;
- const llvm::Type *Ty = llvm::Type::getInt8Ty(CGF->getLLVMContext());
+ const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
if (NumBytes > 1)
Ty = llvm::ArrayType::get(Ty, NumBytes);
@@ -766,27 +766,21 @@ public:
return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType()));
}
case Expr::PredefinedExprClass: {
- // __func__/__FUNCTION__ -> "". __PRETTY_FUNCTION__ -> "top level".
- std::string Str;
- if (cast<PredefinedExpr>(E)->getIdentType() ==
- PredefinedExpr::PrettyFunction)
- Str = "top level";
+ unsigned Type = cast<PredefinedExpr>(E)->getIdentType();
+ if (CGF) {
+ LValue Res = CGF->EmitPredefinedFunctionName(Type);
+ return cast<llvm::Constant>(Res.getAddress());
+ } else if (Type == PredefinedExpr::PrettyFunction) {
+ return CGM.GetAddrOfConstantCString("top level", ".tmp");
+ }
- return CGM.GetAddrOfConstantCString(Str, ".tmp");
+ return CGM.GetAddrOfConstantCString("", ".tmp");
}
case Expr::AddrLabelExprClass: {
assert(CGF && "Invalid address of label expression outside function.");
-#ifndef USEINDIRECTBRANCH
- unsigned id =
- CGF->GetIDForAddrOfLabel(cast<AddrLabelExpr>(E)->getLabel());
- llvm::Constant *C =
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), id);
- return llvm::ConstantExpr::getIntToPtr(C, ConvertType(E->getType()));
-#else
llvm::Constant *Ptr =
CGF->GetAddrOfLabel(cast<AddrLabelExpr>(E)->getLabel());
return llvm::ConstantExpr::getBitCast(Ptr, ConvertType(E->getType()));
-#endif
}
case Expr::CallExprClass: {
CallExpr* CE = cast<CallExpr>(E);
@@ -827,9 +821,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
else
Success = E->Evaluate(Result, Context);
- if (Success) {
- assert(!Result.HasSideEffects &&
- "Constant expr should not have any side effects!");
+ if (Success && !Result.HasSideEffects) {
switch (Result.Val.getKind()) {
case APValue::Uninitialized:
assert(0 && "Constant expressions should be initialized.");
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 96b58d8..e9bbf35 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -135,16 +135,8 @@ public:
}
Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E);
Value *VisitAddrLabelExpr(const AddrLabelExpr *E) {
-#ifndef USEINDIRECTBRANCH
- llvm::Value *V =
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()),
- CGF.GetIDForAddrOfLabel(E->getLabel()));
-
- return Builder.CreateIntToPtr(V, ConvertType(E->getType()));
-#else
llvm::Value *V = CGF.GetAddrOfLabel(E->getLabel());
return Builder.CreateBitCast(V, ConvertType(E->getType()));
-#endif
}
// l-values.
@@ -356,6 +348,9 @@ public:
Value *VisitBinLOr (const BinaryOperator *E);
Value *VisitBinComma (const BinaryOperator *E);
+ Value *VisitBinPtrMemD(const Expr *E) { return EmitLoadOfLValue(E); }
+ Value *VisitBinPtrMemI(const Expr *E) { return EmitLoadOfLValue(E); }
+
// Other Operators.
Value *VisitBlockExpr(const BlockExpr *BE);
Value *VisitConditionalOperator(const ConditionalOperator *CO);
@@ -547,13 +542,6 @@ EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src,
//===----------------------------------------------------------------------===//
Value *ScalarExprEmitter::VisitExpr(Expr *E) {
- if (const BinaryOperator *BExpr = dyn_cast<BinaryOperator>(E))
- if (BExpr->getOpcode() == BinaryOperator::PtrMemD) {
- LValue LV = CGF.EmitPointerToDataMemberBinaryExpr(BExpr);
- Value *InVal = CGF.EmitLoadOfLValue(LV, E->getType()).getScalarVal();
- return InVal;
- }
-
CGF.ErrorUnsupported(E, "scalar expression");
if (E->getType()->isVoidType())
return 0;
@@ -773,49 +761,20 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
switch (Kind) {
default:
- // FIXME: Assert here.
- // assert(0 && "Unhandled cast kind!");
+ //return CGF.ErrorUnsupported(E, "type of cast");
break;
+
case CastExpr::CK_Unknown:
- // FIXME: We should really assert here - Unknown casts should never get
- // as far as to codegen.
+ //assert(0 && "Unknown cast kind!");
break;
+
case CastExpr::CK_BitCast: {
Value *Src = Visit(const_cast<Expr*>(E));
return Builder.CreateBitCast(Src, ConvertType(DestTy));
}
- case CastExpr::CK_ArrayToPointerDecay: {
- assert(E->getType()->isArrayType() &&
- "Array to pointer decay must have array source type!");
-
- Value *V = EmitLValue(E).getAddress(); // Bitfields can't be arrays.
+ case CastExpr::CK_NoOp:
+ return Visit(const_cast<Expr*>(E));
- // Note that VLA pointers are always decayed, so we don't need to do
- // anything here.
- if (!E->getType()->isVariableArrayType()) {
- assert(isa<llvm::PointerType>(V->getType()) && "Expected pointer");
- assert(isa<llvm::ArrayType>(cast<llvm::PointerType>(V->getType())
- ->getElementType()) &&
- "Expected pointer to array");
- V = Builder.CreateStructGEP(V, 0, "arraydecay");
- }
-
- // The resultant pointer type can be implicitly casted to other pointer
- // types as well (e.g. void*) and can be implicitly converted to integer.
- const llvm::Type *DestLTy = ConvertType(DestTy);
- if (V->getType() != DestLTy) {
- if (isa<llvm::PointerType>(DestLTy))
- V = Builder.CreateBitCast(V, DestLTy, "ptrconv");
- else {
- assert(isa<llvm::IntegerType>(DestLTy) && "Unknown array decay");
- V = Builder.CreatePtrToInt(V, DestLTy, "ptrconv");
- }
- }
- return V;
- }
- case CastExpr::CK_NullToMemberPointer:
- return CGF.CGM.EmitNullConstant(DestTy);
-
case CastExpr::CK_DerivedToBase: {
const RecordType *DerivedClassTy =
E->getType()->getAs<PointerType>()->getPointeeType()->getAs<RecordType>();
@@ -841,6 +800,33 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
return CGF.GetAddressCXXOfBaseClass(Src, DerivedClassDecl, BaseClassDecl,
NullCheckValue);
}
+ case CastExpr::CK_ToUnion: {
+ assert(0 && "Should be unreachable!");
+ break;
+ }
+ case CastExpr::CK_ArrayToPointerDecay: {
+ assert(E->getType()->isArrayType() &&
+ "Array to pointer decay must have array source type!");
+
+ Value *V = EmitLValue(E).getAddress(); // Bitfields can't be arrays.
+
+ // Note that VLA pointers are always decayed, so we don't need to do
+ // anything here.
+ if (!E->getType()->isVariableArrayType()) {
+ assert(isa<llvm::PointerType>(V->getType()) && "Expected pointer");
+ assert(isa<llvm::ArrayType>(cast<llvm::PointerType>(V->getType())
+ ->getElementType()) &&
+ "Expected pointer to array");
+ V = Builder.CreateStructGEP(V, 0, "arraydecay");
+ }
+
+ return V;
+ }
+ case CastExpr::CK_FunctionToPointerDecay:
+ return EmitLValue(E).getAddress();
+
+ case CastExpr::CK_NullToMemberPointer:
+ return CGF.CGM.EmitNullConstant(DestTy);
case CastExpr::CK_IntegralToPointer: {
Value *Src = Visit(const_cast<Expr*>(E));
@@ -860,7 +846,40 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
Value *Src = Visit(const_cast<Expr*>(E));
return Builder.CreatePtrToInt(Src, ConvertType(DestTy));
}
-
+
+ case CastExpr::CK_ToVoid: {
+ CGF.EmitAnyExpr(E, 0, false, true);
+ return 0;
+ }
+
+ case CastExpr::CK_Dynamic: {
+ Value *V = Visit(const_cast<Expr*>(E));
+ const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(CE);
+ return CGF.EmitDynamicCast(V, DCE);
+ }
+
+ case CastExpr::CK_VectorSplat: {
+ const llvm::Type *DstTy = ConvertType(DestTy);
+ Value *Elt = Visit(const_cast<Expr*>(E));
+
+ // Insert the element in element zero of an undef vector
+ llvm::Value *UnV = llvm::UndefValue::get(DstTy);
+ llvm::Value *Idx =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0);
+ UnV = Builder.CreateInsertElement(UnV, Elt, Idx, "tmp");
+
+ // Splat the element across to all elements
+ llvm::SmallVector<llvm::Constant*, 16> Args;
+ unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
+ for (unsigned i = 0; i < NumElements; i++)
+ Args.push_back(llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), 0));
+
+ llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], NumElements);
+ llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat");
+ return Yay;
+ }
+
}
// Handle cases where the source is an non-complex type.
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index f348bff..b431daa 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -608,6 +608,8 @@ llvm::Constant *CGObjCGNU::GenerateIvarList(
const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames,
const llvm::SmallVectorImpl<llvm::Constant *> &IvarTypes,
const llvm::SmallVectorImpl<llvm::Constant *> &IvarOffsets) {
+ if (IvarNames.size() == 0)
+ return NULLPtr;
// Get the method structure type.
llvm::StructType *ObjCIvarTy = llvm::StructType::get(VMContext,
PtrToInt8Ty,
@@ -1189,8 +1191,8 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
Context.getObjCEncodingForType((*iter)->getType(), TypeStr);
IvarTypes.push_back(MakeConstantString(TypeStr));
// Get the offset
- uint64_t Offset = 0;
uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter);
+ uint64_t Offset = BaseOffset;
if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
Offset = BaseOffset - superInstanceSize;
}
@@ -1301,7 +1303,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
}
//Generate metaclass for class methods
llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr,
- NULLPtr, 0x12L, /*name*/"", 0, Zeros[0], GenerateIvarList(
+ NULLPtr, 0x12L, ClassName.c_str(), 0, Zeros[0], GenerateIvarList(
empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr);
// Generate the class structure
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 9b2f4a1..4355e66 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -991,6 +991,9 @@ private:
/// for the given class.
llvm::Value *EmitClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
+
+ /// EmitSuperClassRef - Emits reference to class's main metadata class.
+ llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID);
CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
@@ -1167,6 +1170,9 @@ private:
/// legacy messaging dispatch.
llvm::DenseSet<Selector> NonLegacyDispatchMethods;
+ /// DefinedMetaClasses - List of defined meta-classes.
+ std::vector<llvm::GlobalValue*> DefinedMetaClasses;
+
/// LegacyDispatchedSelector - Returns true if SEL is not in the list of
/// NonLegacyDispatchMethods; false otherwise.
bool LegacyDispatchedSelector(Selector Sel);
@@ -1485,8 +1491,13 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
llvm::Value *Super = CGF.Builder.CreateLoad(SuperPtr);
Target = Super;
}
- } else {
+ }
+ else if (isCategoryImpl)
Target = EmitClassRef(CGF.Builder, Class->getSuperClass());
+ else {
+ llvm::Value *ClassPtr = EmitSuperClassRef(Class);
+ ClassPtr = CGF.Builder.CreateStructGEP(ClassPtr, 1);
+ Target = CGF.Builder.CreateLoad(ClassPtr);
}
// FIXME: We shouldn't need to do this cast, rectify the ASTContext and
// ObjCTypes types.
@@ -2051,11 +2062,22 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
Values[11] = EmitClassExtension(ID);
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy,
Values);
-
- llvm::GlobalVariable *GV =
- CreateMetadataVar("\01L_OBJC_CLASS_" + ClassName, Init,
- "__OBJC,__class,regular,no_dead_strip",
- 4, true);
+ std::string Name("\01L_OBJC_CLASS_");
+ Name += ClassName;
+ const char *Section = "__OBJC,__class,regular,no_dead_strip";
+ // Check for a forward reference.
+ llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
+ if (GV) {
+ assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
+ "Forward metaclass reference has incorrect type.");
+ GV->setLinkage(llvm::GlobalValue::InternalLinkage);
+ GV->setInitializer(Init);
+ GV->setSection(Section);
+ GV->setAlignment(4);
+ CGM.AddUsedGlobal(GV);
+ }
+ else
+ GV = CreateMetadataVar(Name, Init, Section, 4, true);
DefinedClasses.push_back(GV);
}
@@ -2154,6 +2176,22 @@ llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) {
}
}
+llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) {
+ std::string Name = "\01L_OBJC_CLASS_" + ID->getNameAsString();
+
+ if (llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name,
+ true)) {
+ assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
+ "Forward class metadata reference has incorrect type.");
+ return GV;
+ } else {
+ return new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0,
+ Name);
+ }
+}
+
/*
struct objc_class_ext {
uint32_t size;
@@ -4095,6 +4133,25 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
AddModuleClassList(DefinedClasses,
"\01L_OBJC_LABEL_CLASS_$",
"__DATA, __objc_classlist, regular, no_dead_strip");
+
+ bool hasWeakImport = false;
+ for (unsigned i = 0; i < DefinedClasses.size(); i++) {
+ llvm::GlobalValue *IMPLGV = DefinedClasses[i];
+ if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage)
+ continue;
+ IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage);
+ hasWeakImport = true;
+ }
+
+ if (hasWeakImport) {
+ for (unsigned i = 0; i < DefinedMetaClasses.size(); i++) {
+ llvm::GlobalValue *IMPLGV = DefinedMetaClasses[i];
+ if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage)
+ continue;
+ IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage);
+ }
+ }
+
AddModuleClassList(DefinedNonLazyClasses,
"\01L_OBJC_LABEL_NONLAZY_CLASS_$",
"__DATA, __objc_nlclslist, regular, no_dead_strip");
@@ -4384,6 +4441,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
std::string SuperClassName =
ObjCMetaClassName + ID->getClassInterface()->getSuperClass()->getNameAsString();
SuperClassGV = GetClassGlobal(SuperClassName);
+ if (ID->getClassInterface()->getSuperClass()->hasAttr<WeakImportAttr>())
+ SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
}
llvm::GlobalVariable *CLASS_RO_GV = BuildClassRoTInitializer(flags,
InstanceStart,
@@ -4392,6 +4451,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
llvm::GlobalVariable *MetaTClass =
BuildClassMetaData(TClassName, IsAGV, SuperClassGV, CLASS_RO_GV,
classIsHidden);
+ DefinedMetaClasses.push_back(MetaTClass);
// Metadata for the class
flags = CLS;
@@ -4409,6 +4469,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
std::string RootClassName =
ID->getClassInterface()->getSuperClass()->getNameAsString();
SuperClassGV = GetClassGlobal(ObjCClassName + RootClassName);
+ if (ID->getClassInterface()->getSuperClass()->hasAttr<WeakImportAttr>())
+ SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
}
GetClassSizeInfo(ID, InstanceStart, InstanceSize);
CLASS_RO_GV = BuildClassRoTInitializer(flags,
@@ -4489,6 +4551,9 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
Values[0] = GetClassName(OCD->getIdentifier());
// meta-class entry symbol
llvm::GlobalVariable *ClassGV = GetClassGlobal(ExtClassName);
+ if (Interface->hasAttr<WeakImportAttr>())
+ ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
+
Values[1] = ClassGV;
std::vector<llvm::Constant*> Methods;
std::string MethodListName(Prefix);
@@ -5178,6 +5243,12 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
/// decl.
llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
+ if (ID->hasAttr<WeakImportAttr>()) {
+ std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
+ llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName);
+ ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
+ }
+
return EmitClassRef(Builder, ID);
}
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 7baf69d..8e0864b 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -208,7 +208,11 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
Align = 1;
}
}
-
+ if (!Align) {
+ assert((D->field_begin() == D->field_end()) && "LayoutUnion - Align 0");
+ Align = 1;
+ }
+
// Append tail padding.
if (Layout.getSize() / 8 > Size)
AppendPadding(Layout.getSize() / 8, Align);
diff --git a/lib/CodeGen/CGRtti.cpp b/lib/CodeGen/CGRtti.cpp
index 7af15f0..e18843d 100644
--- a/lib/CodeGen/CGRtti.cpp
+++ b/lib/CodeGen/CGRtti.cpp
@@ -11,36 +11,378 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/Type.h"
+#include "clang/AST/RecordLayout.h"
#include "CodeGenModule.h"
using namespace clang;
using namespace CodeGen;
+class RttiBuilder {
+ CodeGenModule &CGM; // Per-module state.
+ llvm::LLVMContext &VMContext;
+ const llvm::Type *Int8PtrTy;
+ llvm::SmallSet<const CXXRecordDecl *, 16> SeenVBase;
+ llvm::SmallSet<const CXXRecordDecl *, 32> SeenBase;
+public:
+ RttiBuilder(CodeGenModule &cgm)
+ : CGM(cgm), VMContext(cgm.getModule().getContext()),
+ Int8PtrTy(llvm::Type::getInt8PtrTy(VMContext)) { }
+
+ /// BuildVtableRef - Build a reference to a vtable.
+ llvm::Constant *BuildVtableRef(const char *Name) {
+ // Build a descriptor for Name
+ llvm::Constant *GV = CGM.getModule().getGlobalVariable(Name);
+ if (GV)
+ GV = llvm::ConstantExpr::getBitCast(GV,
+ llvm::PointerType::get(Int8PtrTy, 0));
+ else {
+ llvm::GlobalVariable::LinkageTypes linktype;
+ linktype = llvm::GlobalValue::ExternalLinkage;
+ GV = new llvm::GlobalVariable(CGM.getModule(), Int8PtrTy,
+ true, linktype, 0, Name);
+ }
+ llvm::Constant *C;
+ C = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 2);
+ C = llvm::ConstantExpr::getInBoundsGetElementPtr(GV, &C, 1);
+ return llvm::ConstantExpr::getBitCast(C, Int8PtrTy);
+ }
+
+ llvm::Constant *BuildName(QualType Ty, bool Hidden) {
+ llvm::SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ mangleCXXRttiName(CGM.getMangleContext(), Ty, Out);
+
+ llvm::GlobalVariable::LinkageTypes linktype;
+ linktype = llvm::GlobalValue::LinkOnceODRLinkage;
+
+ llvm::Constant *C;
+ C = llvm::ConstantArray::get(VMContext, Out.str().substr(4));
+
+ llvm::GlobalVariable * GV = new llvm::GlobalVariable(CGM.getModule(),
+ C->getType(),
+ true, linktype, C,
+ Out.str());
+ if (Hidden)
+ GV->setVisibility(llvm::GlobalVariable::HiddenVisibility);
+ return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+ };
+
+ /// - BuildFlags - Build a psABI __flags value for __vmi_class_type_info.
+ llvm::Constant *BuildFlags(int f) {
+ return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), f);
+ }
+
+ /// BuildBaseCount - Build a psABI __base_count value for
+ /// __vmi_class_type_info.
+ llvm::Constant *BuildBaseCount(unsigned c) {
+ return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), c);
+ }
+
+ llvm::Constant *BuildTypeRef(QualType Ty) {
+ llvm::Constant *C;
+
+ if (!CGM.getContext().getLangOptions().Rtti)
+ return llvm::Constant::getNullValue(Int8PtrTy);
+
+ llvm::SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ mangleCXXRtti(CGM.getMangleContext(), Ty, Out);
+
+ C = CGM.getModule().getGlobalVariable(Out.str());
+ if (C)
+ return llvm::ConstantExpr::getBitCast(C, Int8PtrTy);
+
+ llvm::GlobalVariable::LinkageTypes linktype;
+ linktype = llvm::GlobalValue::ExternalLinkage;;
+
+ C = new llvm::GlobalVariable(CGM.getModule(), Int8PtrTy, true, linktype,
+ 0, Out.str());
+ return llvm::ConstantExpr::getBitCast(C, Int8PtrTy);
+ }
+
+ llvm::Constant *Buildclass_type_infoRef(const CXXRecordDecl *RD) {
+ return BuildTypeRef(CGM.getContext().getTagDeclType(RD));
+ }
+
+ /// CalculateFlags - Calculate the flags for the __vmi_class_type_info
+ /// datastructure. 1 for non-diamond repeated inheritance, 2 for a dimond
+ /// shaped class.
+ int CalculateFlags(const CXXRecordDecl*RD) {
+ int flags = 0;
+ if (SeenBase.count(RD))
+ flags |= 1;
+ else
+ SeenBase.insert(RD);
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ if (i->isVirtual()) {
+ if (SeenVBase.count(Base))
+ flags |= 2;
+ else
+ SeenVBase.insert(Base);
+ }
+ flags |= CalculateFlags(Base);
+ }
+ return flags;
+ }
+
+ bool SimpleInheritance(const CXXRecordDecl *RD) {
+ if (RD->getNumBases() != 1)
+ return false;
+ CXXRecordDecl::base_class_const_iterator i = RD->bases_begin();
+ if (i->isVirtual())
+ return false;
+ if (i->getAccessSpecifier() != AS_public)
+ return false;
+
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ if (Layout.getBaseClassOffset(Base) != 0)
+ return false;
+ return true;
+ }
+
+ llvm::Constant *finish(std::vector<llvm::Constant *> &info,
+ llvm::GlobalVariable *GV,
+ llvm::StringRef Name, bool Hidden) {
+ llvm::GlobalVariable::LinkageTypes linktype;
+ linktype = llvm::GlobalValue::LinkOnceODRLinkage;
+
+ llvm::Constant *C;
+ C = llvm::ConstantStruct::get(VMContext, &info[0], info.size(), false);
+
+ if (GV == 0)
+ GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true,
+ linktype, C, Name);
+ else {
+ llvm::GlobalVariable *OGV = GV;
+ GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true,
+ linktype, C, Name);
+ GV->takeName(OGV);
+ llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV,
+ OGV->getType());
+ OGV->replaceAllUsesWith(NewPtr);
+ OGV->eraseFromParent();
+ }
+ if (Hidden)
+ GV->setVisibility(llvm::GlobalVariable::HiddenVisibility);
+ return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+ }
+
+
+ llvm::Constant *Buildclass_type_info(const CXXRecordDecl *RD) {
+ if (!CGM.getContext().getLangOptions().Rtti)
+ return llvm::Constant::getNullValue(Int8PtrTy);
+
+ llvm::Constant *C;
+
+ llvm::SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ mangleCXXRtti(CGM.getMangleContext(), CGM.getContext().getTagDeclType(RD),
+ Out);
+
+ llvm::GlobalVariable *GV;
+ GV = CGM.getModule().getGlobalVariable(Out.str());
+ if (GV && !GV->isDeclaration())
+ return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+
+ std::vector<llvm::Constant *> info;
+
+ bool Hidden = CGM.getDeclVisibilityMode(RD) == LangOptions::Hidden;
+
+ bool simple = false;
+ if (RD->getNumBases() == 0)
+ C = BuildVtableRef("_ZTVN10__cxxabiv117__class_type_infoE");
+ else if (SimpleInheritance(RD)) {
+ simple = true;
+ C = BuildVtableRef("_ZTVN10__cxxabiv120__si_class_type_infoE");
+ } else
+ C = BuildVtableRef("_ZTVN10__cxxabiv121__vmi_class_type_infoE");
+ info.push_back(C);
+ info.push_back(BuildName(CGM.getContext().getTagDeclType(RD), Hidden));
+
+ // If we have no bases, there are no more fields.
+ if (RD->getNumBases()) {
+ if (!simple) {
+ info.push_back(BuildFlags(CalculateFlags(RD)));
+ info.push_back(BuildBaseCount(RD->getNumBases()));
+ }
+
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ info.push_back(CGM.GenerateRttiRef(Base));
+ if (simple)
+ break;
+ int64_t offset;
+ if (!i->isVirtual())
+ offset = Layout.getBaseClassOffset(Base)/8;
+ else
+ offset = CGM.getVtableInfo().getVirtualBaseOffsetIndex(RD, Base);
+ offset <<= 8;
+ // Now set the flags.
+ offset += i->isVirtual() ? 1 : 0;;
+ offset += i->getAccessSpecifier() == AS_public ? 2 : 0;
+ const llvm::Type *LongTy =
+ CGM.getTypes().ConvertType(CGM.getContext().LongTy);
+ C = llvm::ConstantInt::get(LongTy, offset);
+ info.push_back(C);
+ }
+ }
+
+ return finish(info, GV, Out.str(), Hidden);
+ }
+
+ /// - BuildFlags - Build a __flags value for __pbase_type_info.
+ llvm::Constant *BuildInt(int f) {
+ return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), f);
+ }
+
+ llvm::Constant *BuildType2(QualType Ty) {
+ if (const RecordType *RT = Ty.getTypePtr()->getAs<RecordType>())
+ if (const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()))
+ return Buildclass_type_info(RD);
+ return BuildType(Ty);
+ }
+
+ llvm::Constant *BuildPointerType(QualType Ty) {
+ llvm::Constant *C;
+
+ llvm::SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ mangleCXXRtti(CGM.getMangleContext(), Ty, Out);
+
+ llvm::GlobalVariable *GV;
+ GV = CGM.getModule().getGlobalVariable(Out.str());
+ if (GV && !GV->isDeclaration())
+ return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+
+ std::vector<llvm::Constant *> info;
+
+ // FIXME: pointer to hidden should be hidden, we should be able to
+ // grab a bit off the type for this.
+ bool Hidden = false;
+
+ QualType PTy = Ty->getPointeeType();
+ QualType BTy;
+ bool PtrMem = false;
+ if (const MemberPointerType *MPT = dyn_cast<MemberPointerType>(Ty)) {
+ PtrMem = true;
+ BTy = QualType(MPT->getClass(), 0);
+ PTy = MPT->getPointeeType();
+ }
+
+ if (PtrMem)
+ C = BuildVtableRef("_ZTVN10__cxxabiv129__pointer_to_member_type_infoE");
+ else
+ C = BuildVtableRef("_ZTVN10__cxxabiv119__pointer_type_infoE");
+ info.push_back(C);
+ info.push_back(BuildName(Ty, Hidden));
+ Qualifiers Q = PTy.getQualifiers();
+ PTy = CGM.getContext().getCanonicalType(PTy).getUnqualifiedType();
+ int flags = 0;
+ flags += Q.hasConst() ? 0x1 : 0;
+ flags += Q.hasVolatile() ? 0x2 : 0;
+ flags += Q.hasRestrict() ? 0x4 : 0;
+ flags += Ty.getTypePtr()->isIncompleteType() ? 0x8 : 0;
+ if (PtrMem && BTy.getTypePtr()->isIncompleteType())
+ flags += 0x10;
+
+ info.push_back(BuildInt(flags));
+ info.push_back(BuildInt(0));
+ info.push_back(BuildType2(PTy));
+
+ if (PtrMem)
+ info.push_back(BuildType2(BTy));
+
+ return finish(info, GV, Out.str(), true);
+ }
+
+ llvm::Constant *BuildSimpleType(QualType Ty, const char *vtbl) {
+ llvm::Constant *C;
+
+ llvm::SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ mangleCXXRtti(CGM.getMangleContext(), Ty, Out);
+
+ llvm::GlobalVariable *GV;
+ GV = CGM.getModule().getGlobalVariable(Out.str());
+ if (GV && !GV->isDeclaration())
+ return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+
+ std::vector<llvm::Constant *> info;
+
+ // FIXME: pointer to hidden should be hidden, we should be able to
+ // grab a bit off the type for this.
+ bool Hidden = false;
+
+ C = BuildVtableRef(vtbl);
+ info.push_back(C);
+ info.push_back(BuildName(Ty, Hidden));
+
+ return finish(info, GV, Out.str(), true);
+ }
+
+ llvm::Constant *BuildType(QualType Ty) {
+ const clang::Type &Type
+ = *CGM.getContext().getCanonicalType(Ty).getTypePtr();
+ switch (Type.getTypeClass()) {
+ default: {
+ assert(0 && "typeid expression");
+ return llvm::Constant::getNullValue(Int8PtrTy);
+ }
+
+ case Type::Builtin: {
+ // We expect all type_info objects for builtin types to be in the library.
+ return BuildTypeRef(Ty);
+ }
+
+ case Type::Pointer: {
+ QualType PTy = Ty->getPointeeType();
+ Qualifiers Q = PTy.getQualifiers();
+ Q.removeConst();
+ // T* and const T* for all builtin types T are expected in the library.
+ if (isa<BuiltinType>(PTy) && Q.empty())
+ return BuildTypeRef(Ty);
+
+ return BuildPointerType(Ty);
+ }
+ case Type::MemberPointer:
+ return BuildPointerType(Ty);
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ return BuildSimpleType(Ty, "_ZTVN10__cxxabiv120__function_type_infoE");
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::Vector:
+ case Type::ExtVector:
+ return BuildSimpleType(Ty, "_ZTVN10__cxxabiv117__array_type_infoE");
+ case Type::Enum:
+ return BuildSimpleType(Ty, "_ZTVN10__cxxabiv116__enum_type_infoE");
+ }
+ }
+};
+
+llvm::Constant *CodeGenModule::GenerateRttiRef(const CXXRecordDecl *RD) {
+ RttiBuilder b(*this);
+
+ return b.Buildclass_type_infoRef(RD);
+}
+
llvm::Constant *CodeGenModule::GenerateRtti(const CXXRecordDecl *RD) {
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
-
- if (!getContext().getLangOptions().Rtti)
- return llvm::Constant::getNullValue(Int8PtrTy);
-
- llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCXXRtti(getMangleContext(), Context.getTagDeclType(RD), Out);
-
- llvm::GlobalVariable::LinkageTypes linktype;
- linktype = llvm::GlobalValue::WeakAnyLinkage;
- std::vector<llvm::Constant *> info;
- // assert(0 && "FIXME: implement rtti descriptor");
- // FIXME: descriptor
- info.push_back(llvm::Constant::getNullValue(Int8PtrTy));
- // assert(0 && "FIXME: implement rtti ts");
- // FIXME: TS
- info.push_back(llvm::Constant::getNullValue(Int8PtrTy));
-
- llvm::Constant *C;
- llvm::ArrayType *type = llvm::ArrayType::get(Int8PtrTy, info.size());
- C = llvm::ConstantArray::get(type, info);
- llvm::Constant *Rtti =
- new llvm::GlobalVariable(getModule(), type, true, linktype, C,
- Out.str());
- Rtti = llvm::ConstantExpr::getBitCast(Rtti, Int8PtrTy);
- return Rtti;
+ RttiBuilder b(*this);
+
+ return b.Buildclass_type_info(RD);
+}
+
+llvm::Constant *CodeGenModule::GenerateRttiNonClass(QualType Ty) {
+ RttiBuilder b(*this);
+
+ return b.BuildType(Ty);
}
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 9126c2c..b6d7b39 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -148,13 +148,8 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
CGDebugInfo *DI = getDebugInfo();
if (DI) {
-#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN
DI->setLocation(S.getLBracLoc());
DI->EmitRegionStart(CurFn, Builder);
-#else
- EnsureInsertPoint();
- DI->setLocation(S.getLBracLoc());
-#endif
}
// Keep track of the current cleanup stack depth.
@@ -167,13 +162,8 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
EmitStmt(*I);
if (DI) {
-#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN
DI->setLocation(S.getLBracLoc());
DI->EmitRegionEnd(CurFn, Builder);
-#else
- EnsureInsertPoint();
- DI->setLocation(S.getLBracLoc());
-#endif
}
RValue RV;
@@ -284,16 +274,9 @@ void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) {
- // Emit initial switch which will be patched up later by
- // EmitIndirectSwitches(). We need a default dest, so we use the
- // current BB, but this is overwritten.
-#ifndef USEINDIRECTBRANCH
- llvm::Value *V = Builder.CreatePtrToInt(EmitScalarExpr(S.getTarget()),
- llvm::Type::getInt32Ty(VMContext),
-#else
+ // Ensure that we have an i8* for our PHI node.
llvm::Value *V = Builder.CreateBitCast(EmitScalarExpr(S.getTarget()),
llvm::Type::getInt8PtrTy(VMContext),
-#endif
"addr");
llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
@@ -491,13 +474,11 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
BreakContinueStack.push_back(BreakContinue(AfterFor, ContinueBlock));
// If the condition is true, execute the body of the for stmt.
-#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN
CGDebugInfo *DI = getDebugInfo();
if (DI) {
DI->setLocation(S.getSourceRange().getBegin());
DI->EmitRegionStart(CurFn, Builder);
}
-#endif
EmitStmt(S.getBody());
BreakContinueStack.pop_back();
@@ -510,12 +491,10 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
// Finally, branch back up to the condition for the next iteration.
EmitBranch(CondBlock);
-#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN
if (DI) {
DI->setLocation(S.getSourceRange().getEnd());
DI->EmitRegionEnd(CurFn, Builder);
}
-#endif
// Emit the fall-through block.
EmitBlock(AfterFor, true);
@@ -758,7 +737,7 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
}
static std::string
-SimplifyConstraint(const char *Constraint, TargetInfo &Target,
+SimplifyConstraint(const char *Constraint, const TargetInfo &Target,
llvm::SmallVectorImpl<TargetInfo::ConstraintInfo> *OutCons=0) {
std::string Result;
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index e2e1147..4c97a9b 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -15,6 +15,7 @@
#include "CodeGenFunction.h"
#include "clang/AST/RecordLayout.h"
+#include <cstdio>
using namespace clang;
using namespace CodeGen;
@@ -29,6 +30,11 @@ private:
llvm::Type *Ptr8Ty;
/// Class - The most derived class that this vtable is being built for.
const CXXRecordDecl *Class;
+ /// LayoutClass - The most derived class used for virtual base layout
+ /// information.
+ const CXXRecordDecl *LayoutClass;
+ /// LayoutOffset - The offset for Class in LayoutClass.
+ uint64_t LayoutOffset;
/// BLayout - Layout for the most derived class that this vtable is being
/// built for.
const ASTRecordLayout &BLayout;
@@ -39,38 +45,45 @@ private:
CodeGenModule &CGM; // Per-module state.
/// Index - Maps a method decl into a vtable index. Useful for virtual
/// dispatch codegen.
- llvm::DenseMap<const CXXMethodDecl *, Index_t> Index;
- llvm::DenseMap<const CXXMethodDecl *, Index_t> VCall;
- llvm::DenseMap<const CXXMethodDecl *, Index_t> VCallOffset;
+ llvm::DenseMap<GlobalDecl, Index_t> Index;
+ llvm::DenseMap<GlobalDecl, Index_t> VCall;
+ llvm::DenseMap<GlobalDecl, Index_t> VCallOffset;
+ // This is the offset to the nearest virtual base
+ llvm::DenseMap<GlobalDecl, Index_t> NonVirtualOffset;
llvm::DenseMap<const CXXRecordDecl *, Index_t> VBIndex;
- typedef llvm::DenseMap<const CXXMethodDecl *, int> Pures_t;
+ typedef llvm::DenseMap<GlobalDecl, int> Pures_t;
Pures_t Pures;
typedef std::pair<Index_t, Index_t> CallOffset;
- typedef llvm::DenseMap<const CXXMethodDecl *, CallOffset> Thunks_t;
+ typedef llvm::DenseMap<GlobalDecl, CallOffset> Thunks_t;
Thunks_t Thunks;
- typedef llvm::DenseMap<const CXXMethodDecl *,
+ typedef llvm::DenseMap<GlobalDecl,
std::pair<std::pair<CallOffset, CallOffset>,
CanQualType> > CovariantThunks_t;
CovariantThunks_t CovariantThunks;
std::vector<Index_t> VCalls;
+
+ typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t;
+ // CtorVtable - Used to hold the AddressPoints (offsets) into the built vtable
+ // for use in computing the initializers for the VTT.
+ llvm::DenseMap<CtorVtable_t, int64_t> &AddressPoints;
+
typedef CXXRecordDecl::method_iterator method_iter;
// FIXME: Linkage should follow vtable
const bool Extern;
const uint32_t LLVMPointerWidth;
Index_t extra;
- int CurrentVBaseOffset;
typedef std::vector<std::pair<const CXXRecordDecl *, int64_t> > Path_t;
llvm::Constant *cxa_pure;
public:
- VtableBuilder(std::vector<llvm::Constant *> &meth,
- const CXXRecordDecl *c,
- CodeGenModule &cgm)
- : methods(meth), Class(c), BLayout(cgm.getContext().getASTRecordLayout(c)),
- rtti(cgm.GenerateRtti(c)), VMContext(cgm.getModule().getContext()),
- CGM(cgm), Extern(true),
- LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)),
- CurrentVBaseOffset(0) {
+ VtableBuilder(std::vector<llvm::Constant *> &meth, const CXXRecordDecl *c,
+ const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm)
+ : methods(meth), Class(c), LayoutClass(l), LayoutOffset(lo),
+ BLayout(cgm.getContext().getASTRecordLayout(l)),
+ rtti(cgm.GenerateRttiRef(c)), VMContext(cgm.getModule().getContext()),
+ CGM(cgm), AddressPoints(*new llvm::DenseMap<CtorVtable_t, int64_t>),
+ Extern(true),
+ LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) {
Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
// Calculate pointer for ___cxa_pure_virtual.
@@ -81,10 +94,13 @@ public:
cxa_pure = wrap(CGM.CreateRuntimeFunction(FTy, "__cxa_pure_virtual"));
}
- llvm::DenseMap<const CXXMethodDecl *, Index_t> &getIndex() { return Index; }
+ llvm::DenseMap<GlobalDecl, Index_t> &getIndex() { return Index; }
llvm::DenseMap<const CXXRecordDecl *, Index_t> &getVBIndex()
{ return VBIndex; }
+ llvm::DenseMap<CtorVtable_t, int64_t> *getAddressPoints()
+ { return &AddressPoints; }
+
llvm::Constant *wrap(Index_t i) {
llvm::Constant *m;
m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i);
@@ -95,8 +111,8 @@ public:
return llvm::ConstantExpr::getBitCast(m, Ptr8Ty);
}
-#define D1(x)
-//#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0)
+//#define D1(x)
+#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0)
void GenerateVBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset,
bool updateVBIndex, Index_t current_vbindex) {
@@ -189,9 +205,11 @@ public:
return 0;
}
- bool OverrideMethod(const CXXMethodDecl *MD, llvm::Constant *m,
+ bool OverrideMethod(GlobalDecl GD, llvm::Constant *m,
bool MorallyVirtual, Index_t OverrideOffset,
- Index_t Offset) {
+ Index_t Offset, int64_t CurrentVBaseOffset) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
const bool isPure = MD->isPure();
typedef CXXMethodDecl::method_iterator meth_iter;
// FIXME: Should OverrideOffset's be Offset?
@@ -204,9 +222,16 @@ public:
for (meth_iter mi = MD->begin_overridden_methods(),
e = MD->end_overridden_methods();
mi != e; ++mi) {
+ GlobalDecl OGD;
+
const CXXMethodDecl *OMD = *mi;
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(OMD))
+ OGD = GlobalDecl(DD, GD.getDtorType());
+ else
+ OGD = OMD;
+
llvm::Constant *om;
- om = CGM.GetAddrOfFunction(OMD, Ptr8Ty);
+ om = WrapAddrOf(OGD);
om = llvm::ConstantExpr::getBitCast(om, Ptr8Ty);
for (Index_t i = 0, e = submethods.size();
@@ -229,57 +254,60 @@ public:
Index_t nv = getNVOffset(oret, ret)/8;
ReturnOffset = std::make_pair(nv, getVbaseOffset(oret, ret));
}
- Index[MD] = i;
+ Index[GD] = i;
submethods[i] = m;
if (isPure)
- Pures[MD] = 1;
- Pures.erase(OMD);
- Thunks.erase(OMD);
- if (MorallyVirtual) {
- Index_t &idx = VCall[OMD];
+ Pures[GD] = 1;
+ Pures.erase(OGD);
+ Thunks.erase(OGD);
+ if (MorallyVirtual || VCall.count(OGD)) {
+ Index_t &idx = VCall[OGD];
if (idx == 0) {
- VCallOffset[MD] = OverrideOffset/8;
+ NonVirtualOffset[GD] = -OverrideOffset/8 + CurrentVBaseOffset/8;
+ VCallOffset[GD] = OverrideOffset/8;
idx = VCalls.size()+1;
VCalls.push_back(0);
D1(printf(" vcall for %s at %d with delta %d most derived %s\n",
- MD->getNameAsCString(),
- (int)-VCalls.size()-3, (int)VCallOffset[MD],
- Class->getNameAsCString()));
+ MD->getNameAsString().c_str(), (int)-idx-3,
+ (int)VCalls[idx-1], Class->getNameAsCString()));
} else {
- VCallOffset[MD] = VCallOffset[OMD];
- VCalls[idx-1] = -VCallOffset[OMD] + OverrideOffset/8;
+ NonVirtualOffset[GD] = NonVirtualOffset[OGD];
+ VCallOffset[GD] = VCallOffset[OGD];
+ VCalls[idx-1] = -VCallOffset[OGD] + OverrideOffset/8;
D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n",
- MD->getNameAsCString(),
- (int)-VCalls.size()-3, (int)VCallOffset[MD],
- Class->getNameAsCString()));
+ MD->getNameAsString().c_str(), (int)-idx-3,
+ (int)VCalls[idx-1], Class->getNameAsCString()));
}
- VCall[MD] = idx;
- CallOffset ThisOffset;
- ThisOffset = std::make_pair(CurrentVBaseOffset/8 - Offset/8,
- -((idx+extra+2)*LLVMPointerWidth/8));
+ VCall[GD] = idx;
+ int64_t O = NonVirtualOffset[GD];
+ int v = -((idx+extra+2)*LLVMPointerWidth/8);
+ // Optimize out virtual adjustments of 0.
+ if (VCalls[idx-1] == 0)
+ v = 0;
+ CallOffset ThisOffset = std::make_pair(O, v);
// FIXME: Do we always have to build a covariant thunk to save oret,
// which is the containing virtual base class?
if (ReturnOffset.first || ReturnOffset.second)
- CovariantThunks[MD] = std::make_pair(std::make_pair(ThisOffset,
+ CovariantThunks[GD] = std::make_pair(std::make_pair(ThisOffset,
ReturnOffset),
oret);
- else if (!isPure)
- Thunks[MD] = ThisOffset;
+ else if (!isPure && (ThisOffset.first || ThisOffset.second))
+ Thunks[GD] = ThisOffset;
return true;
}
// FIXME: finish off
- int64_t O = VCallOffset[OMD] - OverrideOffset/8;
- // int64_t O = CurrentVBaseOffset/8 - OverrideOffset/8;
+ int64_t O = VCallOffset[OGD] - OverrideOffset/8;
+
if (O || ReturnOffset.first || ReturnOffset.second) {
CallOffset ThisOffset = std::make_pair(O, 0);
if (ReturnOffset.first || ReturnOffset.second)
- CovariantThunks[MD] = std::make_pair(std::make_pair(ThisOffset,
+ CovariantThunks[GD] = std::make_pair(std::make_pair(ThisOffset,
ReturnOffset),
oret);
else if (!isPure)
- Thunks[MD] = ThisOffset;
+ Thunks[GD] = ThisOffset;
}
return true;
}
@@ -291,9 +319,10 @@ public:
void InstallThunks() {
for (Thunks_t::iterator i = Thunks.begin(), e = Thunks.end();
i != e; ++i) {
- const CXXMethodDecl *MD = i->first;
+ GlobalDecl GD = i->first;
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
assert(!MD->isPure() && "Trying to thunk a pure");
- Index_t idx = Index[MD];
+ Index_t idx = Index[GD];
Index_t nv_O = i->second.first;
Index_t v_O = i->second.second;
submethods[idx] = CGM.BuildThunk(MD, Extern, nv_O, v_O);
@@ -302,10 +331,11 @@ public:
for (CovariantThunks_t::iterator i = CovariantThunks.begin(),
e = CovariantThunks.end();
i != e; ++i) {
- const CXXMethodDecl *MD = i->first;
+ GlobalDecl GD = i->first;
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
if (MD->isPure())
continue;
- Index_t idx = Index[MD];
+ Index_t idx = Index[GD];
Index_t nv_t = i->second.first.first.first;
Index_t v_t = i->second.first.first.second;
Index_t nv_r = i->second.first.second.first;
@@ -316,16 +346,18 @@ public:
CovariantThunks.clear();
for (Pures_t::iterator i = Pures.begin(), e = Pures.end();
i != e; ++i) {
- const CXXMethodDecl *MD = i->first;
- Index_t idx = Index[MD];
+ GlobalDecl GD = i->first;
+ Index_t idx = Index[GD];
submethods[idx] = cxa_pure;
}
Pures.clear();
}
- llvm::Constant *WrapAddrOf(const CXXMethodDecl *MD) {
+ llvm::Constant *WrapAddrOf(GlobalDecl GD) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD))
- return wrap(CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete));
+ return wrap(CGM.GetAddrOfCXXDestructor(Dtor, GD.getDtorType()));
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
const llvm::Type *Ty =
@@ -335,63 +367,95 @@ public:
return wrap(CGM.GetAddrOfFunction(MD, Ty));
}
- void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset) {
+ void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset,
+ int64_t CurrentVBaseOffset) {
for (Path_t::reverse_iterator i = Path->rbegin(),
e = Path->rend(); i != e; ++i) {
const CXXRecordDecl *RD = i->first;
int64_t OverrideOffset = i->second;
for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
++mi) {
- if (!mi->isVirtual())
+ const CXXMethodDecl *MD = *mi;
+
+ if (!MD->isVirtual())
continue;
- const CXXMethodDecl *MD = *mi;
- llvm::Constant *m = WrapAddrOf(MD);
- OverrideMethod(MD, m, MorallyVirtual, OverrideOffset, Offset);
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ // Override both the complete and the deleting destructor.
+ GlobalDecl CompDtor(DD, Dtor_Complete);
+ OverrideMethod(CompDtor, WrapAddrOf(CompDtor), MorallyVirtual,
+ OverrideOffset, Offset, CurrentVBaseOffset);
+
+ GlobalDecl DeletingDtor(DD, Dtor_Deleting);
+ OverrideMethod(DeletingDtor, WrapAddrOf(DeletingDtor), MorallyVirtual,
+ OverrideOffset, Offset, CurrentVBaseOffset);
+ } else {
+ OverrideMethod(MD, WrapAddrOf(MD), MorallyVirtual, OverrideOffset,
+ Offset, CurrentVBaseOffset);
+ }
}
}
}
- void AddMethod(const CXXMethodDecl *MD, bool MorallyVirtual, Index_t Offset,
- bool ForVirtualBase) {
- llvm::Constant *m = WrapAddrOf(MD);
+ void AddMethod(const GlobalDecl GD, bool MorallyVirtual, Index_t Offset,
+ bool ForVirtualBase, int64_t CurrentVBaseOffset) {
+ llvm::Constant *m = WrapAddrOf(GD);
// If we can find a previously allocated slot for this, reuse it.
- if (OverrideMethod(MD, m, MorallyVirtual, Offset, Offset))
+ if (OverrideMethod(GD, m, MorallyVirtual, Offset, Offset,
+ CurrentVBaseOffset))
return;
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
// else allocate a new slot.
- Index[MD] = submethods.size();
+ Index[GD] = submethods.size();
submethods.push_back(m);
- D1(printf(" vfn for %s at %d\n", MD->getNameAsCString(), (int)Index[MD]));
+ D1(printf(" vfn for %s at %d\n", MD->getNameAsString().c_str(),
+ (int)Index[GD]));
if (MD->isPure())
- Pures[MD] = 1;
+ Pures[GD] = 1;
if (MorallyVirtual) {
- VCallOffset[MD] = Offset/8;
- Index_t &idx = VCall[MD];
+ VCallOffset[GD] = Offset/8;
+ Index_t &idx = VCall[GD];
// Allocate the first one, after that, we reuse the previous one.
if (idx == 0) {
+ NonVirtualOffset[GD] = CurrentVBaseOffset/8 - Offset/8;
idx = VCalls.size()+1;
VCalls.push_back(0);
D1(printf(" vcall for %s at %d with delta %d\n",
- MD->getNameAsCString(), (int)-VCalls.size()-3,
- (int)VCallOffset[MD]));
+ MD->getNameAsString().c_str(), (int)-VCalls.size()-3, 0));
}
}
}
void AddMethods(const CXXRecordDecl *RD, bool MorallyVirtual,
- Index_t Offset, bool RDisVirtualBase) {
+ Index_t Offset, bool RDisVirtualBase,
+ int64_t CurrentVBaseOffset) {
for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
- ++mi)
- if (mi->isVirtual())
- AddMethod(*mi, MorallyVirtual, Offset, RDisVirtualBase);
+ ++mi) {
+ const CXXMethodDecl *MD = *mi;
+ if (!MD->isVirtual())
+ continue;
+
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ // For destructors, add both the complete and the deleting destructor
+ // to the vtable.
+ AddMethod(GlobalDecl(DD, Dtor_Complete), MorallyVirtual, Offset,
+ RDisVirtualBase, CurrentVBaseOffset);
+ AddMethod(GlobalDecl(DD, Dtor_Deleting), MorallyVirtual, Offset,
+ RDisVirtualBase, CurrentVBaseOffset);
+ } else
+ AddMethod(MD, MorallyVirtual, Offset, RDisVirtualBase,
+ CurrentVBaseOffset);
+ }
}
void NonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout,
const CXXRecordDecl *PrimaryBase,
bool PrimaryBaseWasVirtual, bool MorallyVirtual,
- int64_t Offset, Path_t *Path) {
+ int64_t Offset, int64_t CurrentVBaseOffset,
+ Path_t *Path) {
Path->push_back(std::make_pair(RD, Offset));
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
e = RD->bases_end(); i != e; ++i) {
@@ -402,8 +466,8 @@ public:
if (Base != PrimaryBase || PrimaryBaseWasVirtual) {
uint64_t o = Offset + Layout.getBaseClassOffset(Base);
StartNewTable();
- CurrentVBaseOffset = Offset;
- GenerateVtableForBase(Base, MorallyVirtual, o, false, Path);
+ GenerateVtableForBase(Base, o, MorallyVirtual, false,
+ CurrentVBaseOffset, Path);
}
}
Path->pop_back();
@@ -424,11 +488,39 @@ public:
i != e; ++i)
methods[InsertionPoint++] = wrap((0?600:0) + *i);
VCalls.clear();
+ VCall.clear();
}
+ void AddAddressPoints(const CXXRecordDecl *RD, uint64_t Offset,
+ Index_t AddressPoint) {
+ D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n",
+ RD->getNameAsCString(), Class->getNameAsCString(),
+ LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint));
+ AddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
+
+ // Now also add the address point for all our primary bases.
+ while (1) {
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ RD = Layout.getPrimaryBase();
+ const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
+ // FIXME: Double check this.
+ if (RD == 0)
+ break;
+ if (PrimaryBaseWasVirtual &&
+ BLayout.getVBaseClassOffset(RD) != Offset)
+ break;
+ D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n",
+ RD->getNameAsCString(), Class->getNameAsCString(),
+ LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint));
+ AddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
+ }
+ }
+
+
Index_t end(const CXXRecordDecl *RD, const ASTRecordLayout &Layout,
const CXXRecordDecl *PrimaryBase, bool PrimaryBaseWasVirtual,
bool MorallyVirtual, int64_t Offset, bool ForVirtualBase,
+ int64_t CurrentVBaseOffset,
Path_t *Path) {
bool alloc = false;
if (Path == 0) {
@@ -446,7 +538,7 @@ public:
// FIXME: just for extra, or for all uses of VCalls.size post this?
extra = -VCalls.size();
- methods.push_back(wrap(-(Offset/8)));
+ methods.push_back(wrap(-((Offset-LayoutOffset)/8)));
methods.push_back(rtti);
Index_t AddressPoint = methods.size();
@@ -457,13 +549,22 @@ public:
// and then the non-virtual bases.
NonVirtualBases(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual,
- MorallyVirtual, Offset, Path);
+ MorallyVirtual, Offset, CurrentVBaseOffset, Path);
if (ForVirtualBase) {
- insertVCalls(VCallInsertionPoint);
+ // FIXME: We're adding to VCalls in callers, we need to do the overrides
+ // in the inner part, so that we know the complete set of vcalls during
+ // the build and don't have to insert into methods. Saving out the
+ // AddressPoint here, would need to be fixed, if we didn't do that. Also
+ // retroactively adding vcalls for overrides later wind up in the wrong
+ // place, the vcall slot has to be alloted during the walk of the base
+ // when the function is first introduces.
AddressPoint += VCalls.size();
+ insertVCalls(VCallInsertionPoint);
}
+ AddAddressPoints(RD, Offset, AddressPoint);
+
if (alloc) {
delete Path;
}
@@ -472,7 +573,7 @@ public:
void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset,
bool updateVBIndex, Index_t current_vbindex,
- bool RDisVirtualBase) {
+ bool RDisVirtualBase, int64_t CurrentVBaseOffset) {
if (!RD->isDynamicClass())
return;
@@ -485,21 +586,27 @@ public:
D1(printf(" doing primaries for %s most derived %s\n",
RD->getNameAsCString(), Class->getNameAsCString()));
+ int BaseCurrentVBaseOffset = CurrentVBaseOffset;
+ if (PrimaryBaseWasVirtual)
+ BaseCurrentVBaseOffset = BLayout.getVBaseClassOffset(PrimaryBase);
+
if (!PrimaryBaseWasVirtual)
Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
- updateVBIndex, current_vbindex, PrimaryBaseWasVirtual);
+ updateVBIndex, current_vbindex, PrimaryBaseWasVirtual,
+ BaseCurrentVBaseOffset);
}
D1(printf(" doing vcall entries for %s most derived %s\n",
RD->getNameAsCString(), Class->getNameAsCString()));
// And add the virtuals for the class to the primary vtable.
- AddMethods(RD, MorallyVirtual, Offset, RDisVirtualBase);
+ AddMethods(RD, MorallyVirtual, Offset, RDisVirtualBase, CurrentVBaseOffset);
}
void VBPrimaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset,
bool updateVBIndex, Index_t current_vbindex,
- bool RDisVirtualBase, bool bottom=false) {
+ bool RDisVirtualBase, int64_t CurrentVBaseOffset,
+ bool bottom=false) {
if (!RD->isDynamicClass())
return;
@@ -509,14 +616,18 @@ public:
// vtables are composed from the chain of primaries.
if (PrimaryBase) {
- if (PrimaryBaseWasVirtual)
+ int BaseCurrentVBaseOffset = CurrentVBaseOffset;
+ if (PrimaryBaseWasVirtual) {
IndirectPrimary.insert(PrimaryBase);
+ BaseCurrentVBaseOffset = BLayout.getVBaseClassOffset(PrimaryBase);
+ }
D1(printf(" doing primaries for %s most derived %s\n",
RD->getNameAsCString(), Class->getNameAsCString()));
VBPrimaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
- updateVBIndex, current_vbindex, PrimaryBaseWasVirtual);
+ updateVBIndex, current_vbindex, PrimaryBaseWasVirtual,
+ BaseCurrentVBaseOffset);
}
D1(printf(" doing vbase entries for %s most derived %s\n",
@@ -525,17 +636,23 @@ public:
if (RDisVirtualBase || bottom) {
Primaries(RD, MorallyVirtual, Offset, updateVBIndex, current_vbindex,
- RDisVirtualBase);
+ RDisVirtualBase, CurrentVBaseOffset);
}
}
- int64_t GenerateVtableForBase(const CXXRecordDecl *RD,
- bool MorallyVirtual = false, int64_t Offset = 0,
+ int64_t GenerateVtableForBase(const CXXRecordDecl *RD, int64_t Offset = 0,
+ bool MorallyVirtual = false,
bool ForVirtualBase = false,
+ int CurrentVBaseOffset = 0,
Path_t *Path = 0) {
if (!RD->isDynamicClass())
return 0;
+ // Construction vtable don't need parts that have no virtual bases and
+ // aren't morally virtual.
+ if ((LayoutClass != Class) && RD->getNumVBases() == 0 && !MorallyVirtual)
+ return 0;
+
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
@@ -548,13 +665,13 @@ public:
extra = VCalls.size();
VBPrimaries(RD, MorallyVirtual, Offset, !ForVirtualBase, 0, ForVirtualBase,
- true);
+ CurrentVBaseOffset, true);
if (Path)
- OverrideMethods(Path, MorallyVirtual, Offset);
+ OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset);
return end(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, MorallyVirtual,
- Offset, ForVirtualBase, Path);
+ Offset, ForVirtualBase, CurrentVBaseOffset, Path);
}
void GenerateVtableForVBases(const CXXRecordDecl *RD,
@@ -578,16 +695,21 @@ public:
StartNewTable();
VCall.clear();
int64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
- CurrentVBaseOffset = BaseOffset;
+ int64_t CurrentVBaseOffset = BaseOffset;
D1(printf("vtable %s virtual base %s\n",
Class->getNameAsCString(), Base->getNameAsCString()));
- GenerateVtableForBase(Base, true, BaseOffset, true, Path);
+ GenerateVtableForBase(Base, BaseOffset, true, true, CurrentVBaseOffset,
+ Path);
}
- int64_t BaseOffset = Offset;
+ int64_t BaseOffset;
if (i->isVirtual())
BaseOffset = BLayout.getVBaseClassOffset(Base);
+ else {
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ BaseOffset = Offset + Layout.getBaseClassOffset(Base);
+ }
+
if (Base->getNumVBases()) {
- CurrentVBaseOffset = BaseOffset;
GenerateVtableForVBases(Base, BaseOffset, Path);
}
}
@@ -603,19 +725,17 @@ VtableBuilder::Index_t VtableBuilder::VBlookup(CXXRecordDecl *D,
return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B);
}
-int64_t CGVtableInfo::getMethodVtableIndex(const CXXMethodDecl *MD) {
- MD = MD->getCanonicalDecl();
-
- MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(MD);
+int64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) {
+ MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(GD);
if (I != MethodVtableIndices.end())
return I->second;
- const CXXRecordDecl *RD = MD->getParent();
+ const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent();
std::vector<llvm::Constant *> methods;
// FIXME: This seems expensive. Can we do a partial job to get
// just this data.
- VtableBuilder b(methods, RD, CGM);
+ VtableBuilder b(methods, RD, RD, 0, CGM);
D1(printf("vtable %s\n", RD->getNameAsCString()));
b.GenerateVtableForBase(RD);
b.GenerateVtableForVBases(RD);
@@ -623,7 +743,7 @@ int64_t CGVtableInfo::getMethodVtableIndex(const CXXMethodDecl *MD) {
MethodVtableIndices.insert(b.getIndex().begin(),
b.getIndex().end());
- I = MethodVtableIndices.find(MD);
+ I = MethodVtableIndices.find(GD);
assert(I != MethodVtableIndices.end() && "Did not find index!");
return I->second;
}
@@ -640,7 +760,7 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
std::vector<llvm::Constant *> methods;
// FIXME: This seems expensive. Can we do a partial job to get
// just this data.
- VtableBuilder b(methods, RD, CGM);
+ VtableBuilder b(methods, RD, RD, 0, CGM);
D1(printf("vtable %s\n", RD->getNameAsCString()));
b.GenerateVtableForBase(RD);
b.GenerateVtableForVBases(RD);
@@ -659,10 +779,15 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
return I->second;
}
-llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) {
+llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass,
+ const CXXRecordDecl *RD,
+ uint64_t Offset) {
llvm::SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
- mangleCXXVtable(CGM.getMangleContext(), RD, Out);
+ if (LayoutClass != RD)
+ mangleCXXCtorVtable(getMangleContext(), LayoutClass, Offset/8, RD, Out);
+ else
+ mangleCXXVtable(getMangleContext(), RD, Out);
llvm::GlobalVariable::LinkageTypes linktype;
linktype = llvm::GlobalValue::LinkOnceODRLinkage;
@@ -670,23 +795,245 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) {
llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0);
int64_t AddressPoint;
- VtableBuilder b(methods, RD, CGM);
+ VtableBuilder b(methods, RD, LayoutClass, Offset, *this);
D1(printf("vtable %s\n", RD->getNameAsCString()));
// First comes the vtables for all the non-virtual bases...
- AddressPoint = b.GenerateVtableForBase(RD);
+ AddressPoint = b.GenerateVtableForBase(RD, Offset);
// then the vtables for all the virtual bases.
- b.GenerateVtableForVBases(RD);
+ b.GenerateVtableForVBases(RD, Offset);
+
+ CodeGenModule::AddrMap_t *&ref = AddressPoints[LayoutClass];
+ if (ref == 0)
+ ref = new CodeGenModule::AddrMap_t;
+
+ (*ref)[RD] = b.getAddressPoints();
llvm::Constant *C;
llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, methods.size());
C = llvm::ConstantArray::get(type, methods);
- llvm::Value *vtable = new llvm::GlobalVariable(CGM.getModule(), type, true,
- linktype, C, Out.str());
- vtable = Builder.CreateBitCast(vtable, Ptr8Ty);
- vtable = Builder.CreateGEP(vtable,
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- AddressPoint*LLVMPointerWidth/8));
+ llvm::GlobalVariable *GV = new llvm::GlobalVariable(getModule(), type,
+ true, linktype, C,
+ Out.str());
+ bool Hidden = getDeclVisibilityMode(RD) == LangOptions::Hidden;
+ if (Hidden)
+ GV->setVisibility(llvm::GlobalVariable::HiddenVisibility);
+ llvm::Constant *vtable = llvm::ConstantExpr::getBitCast(GV, Ptr8Ty);
+ llvm::Constant *AddressPointC;
+ uint32_t LLVMPointerWidth = getContext().Target.getPointerWidth(0);
+ AddressPointC = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ AddressPoint*LLVMPointerWidth/8);
+ vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(vtable, &AddressPointC,
+ 1);
+
return vtable;
}
+
+class VTTBuilder {
+ /// Inits - The list of values built for the VTT.
+ std::vector<llvm::Constant *> &Inits;
+ /// Class - The most derived class that this vtable is being built for.
+ const CXXRecordDecl *Class;
+ CodeGenModule &CGM; // Per-module state.
+ llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase;
+ /// BLayout - Layout for the most derived class that this vtable is being
+ /// built for.
+ const ASTRecordLayout &BLayout;
+ CodeGenModule::AddrMap_t &AddressPoints;
+ // vtbl - A pointer to the vtable for Class.
+ llvm::Constant *ClassVtbl;
+ llvm::LLVMContext &VMContext;
+
+ /// BuildVtablePtr - Build up a referene to the given secondary vtable
+ llvm::Constant *BuildVtablePtr(llvm::Constant *vtbl,
+ const CXXRecordDecl *VtblClass,
+ const CXXRecordDecl *RD,
+ uint64_t Offset) {
+ int64_t AddressPoint;
+ AddressPoint = (*AddressPoints[VtblClass])[std::make_pair(RD, Offset)];
+ // FIXME: We can never have 0 address point. Do this for now so gepping
+ // retains the same structure.
+ if (AddressPoint == 0)
+ AddressPoint = 1;
+ D1(printf("XXX address point for %s in %s layout %s at offset %d was %d\n",
+ RD->getNameAsCString(), VtblClass->getNameAsCString(),
+ Class->getNameAsCString(), (int)Offset, (int)AddressPoint));
+ uint32_t LLVMPointerWidth = CGM.getContext().Target.getPointerWidth(0);
+ llvm::Constant *init;
+ init = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ AddressPoint*LLVMPointerWidth/8);
+ init = llvm::ConstantExpr::getInBoundsGetElementPtr(vtbl, &init, 1);
+ return init;
+ }
+
+ /// Secondary - Add the secondary vtable pointers to Inits. Offset is the
+ /// current offset in bits to the object we're working on.
+ void Secondary(const CXXRecordDecl *RD, llvm::Constant *vtbl,
+ const CXXRecordDecl *VtblClass, uint64_t Offset=0,
+ bool MorallyVirtual=false) {
+ if (RD->getNumVBases() == 0 && ! MorallyVirtual)
+ return;
+
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+ const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
+ bool NonVirtualPrimaryBase;
+ NonVirtualPrimaryBase = !PrimaryBaseWasVirtual && Base == PrimaryBase;
+ bool BaseMorallyVirtual = MorallyVirtual | i->isVirtual();
+ uint64_t BaseOffset;
+ if (!i->isVirtual()) {
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ BaseOffset = Offset + Layout.getBaseClassOffset(Base);
+ } else
+ BaseOffset = BLayout.getVBaseClassOffset(Base);
+ llvm::Constant *subvtbl = vtbl;
+ const CXXRecordDecl *subVtblClass = VtblClass;
+ if ((Base->getNumVBases() || BaseMorallyVirtual)
+ && !NonVirtualPrimaryBase) {
+ // FIXME: Slightly too many of these for __ZTT8test8_B2
+ llvm::Constant *init;
+ if (BaseMorallyVirtual)
+ init = BuildVtablePtr(vtbl, VtblClass, RD, Offset);
+ else {
+ init = CGM.getVtableInfo().getCtorVtable(Class, Base, BaseOffset);
+ subvtbl = dyn_cast<llvm::Constant>(init->getOperand(0));
+ subVtblClass = Base;
+ }
+ Inits.push_back(init);
+ }
+ Secondary(Base, subvtbl, subVtblClass, BaseOffset, BaseMorallyVirtual);
+ }
+ }
+
+ /// BuiltVTT - Add the VTT to Inits. Offset is the offset in bits to the
+ /// currnet object we're working on.
+ void BuildVTT(const CXXRecordDecl *RD, uint64_t Offset, bool MorallyVirtual) {
+ if (RD->getNumVBases() == 0 && !MorallyVirtual)
+ return;
+
+ llvm::Constant *init;
+ const CXXRecordDecl *VtblClass;
+
+ // First comes the primary virtual table pointer...
+ if (MorallyVirtual) {
+ init = BuildVtablePtr(ClassVtbl, Class, RD, Offset);
+ VtblClass = Class;
+ } else {
+ init = CGM.getVtableInfo().getCtorVtable(Class, RD, Offset);
+ VtblClass = RD;
+ }
+ llvm::Constant *vtbl = dyn_cast<llvm::Constant>(init->getOperand(0));
+ Inits.push_back(init);
+
+ // then the secondary VTTs....
+ SecondaryVTTs(RD, Offset, MorallyVirtual);
+
+ // and last the secondary vtable pointers.
+ Secondary(RD, vtbl, VtblClass, Offset, MorallyVirtual);
+ }
+
+ /// SecondaryVTTs - Add the secondary VTTs to Inits. The secondary VTTs are
+ /// built from each direct non-virtual proper base that requires a VTT in
+ /// declaration order.
+ void SecondaryVTTs(const CXXRecordDecl *RD, uint64_t Offset=0,
+ bool MorallyVirtual=false) {
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ if (i->isVirtual())
+ continue;
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base);
+ BuildVTT(Base, BaseOffset, MorallyVirtual);
+ }
+ }
+
+ /// VirtualVTTs - Add the VTT for each proper virtual base in inheritance
+ /// graph preorder.
+ void VirtualVTTs(const CXXRecordDecl *RD) {
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ if (i->isVirtual() && !SeenVBase.count(Base)) {
+ SeenVBase.insert(Base);
+ uint64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
+ BuildVTT(Base, BaseOffset, true);
+ }
+ VirtualVTTs(Base);
+ }
+ }
+public:
+ VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c,
+ CodeGenModule &cgm)
+ : Inits(inits), Class(c), CGM(cgm),
+ BLayout(cgm.getContext().getASTRecordLayout(c)),
+ AddressPoints(*cgm.AddressPoints[c]),
+ VMContext(cgm.getModule().getContext()) {
+
+ // First comes the primary virtual table pointer for the complete class...
+ ClassVtbl = CGM.getVtableInfo().getVtable(Class);
+ Inits.push_back(ClassVtbl);
+ ClassVtbl = dyn_cast<llvm::Constant>(ClassVtbl->getOperand(0));
+
+ // then the secondary VTTs...
+ SecondaryVTTs(Class);
+
+ // then the secondary vtable pointers...
+ Secondary(Class, ClassVtbl, Class);
+
+ // and last, the virtual VTTs.
+ VirtualVTTs(Class);
+ }
+};
+
+llvm::Constant *CodeGenModule::GenerateVTT(const CXXRecordDecl *RD) {
+ // Only classes that have virtual bases need a VTT.
+ if (RD->getNumVBases() == 0)
+ return 0;
+
+ llvm::SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ mangleCXXVTT(getMangleContext(), RD, Out);
+
+ llvm::GlobalVariable::LinkageTypes linktype;
+ linktype = llvm::GlobalValue::LinkOnceODRLinkage;
+ std::vector<llvm::Constant *> inits;
+ llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0);
+
+ D1(printf("vtt %s\n", RD->getNameAsCString()));
+
+ VTTBuilder b(inits, RD, *this);
+
+ llvm::Constant *C;
+ llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, inits.size());
+ C = llvm::ConstantArray::get(type, inits);
+ llvm::GlobalVariable *vtt = new llvm::GlobalVariable(getModule(), type, true,
+ linktype, C, Out.str());
+ bool Hidden = getDeclVisibilityMode(RD) == LangOptions::Hidden;
+ if (Hidden)
+ vtt->setVisibility(llvm::GlobalVariable::HiddenVisibility);
+ return llvm::ConstantExpr::getBitCast(vtt, Ptr8Ty);
+}
+
+llvm::Constant *CGVtableInfo::getVtable(const CXXRecordDecl *RD) {
+ llvm::Constant *&vtbl = Vtables[RD];
+ if (vtbl)
+ return vtbl;
+ vtbl = CGM.GenerateVtable(RD, RD);
+ CGM.GenerateRtti(RD);
+ CGM.GenerateVTT(RD);
+ return vtbl;
+}
+
+llvm::Constant *CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass,
+ const CXXRecordDecl *RD,
+ uint64_t Offset) {
+ return CGM.GenerateVtable(LayoutClass, RD, Offset);
+}
diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h
index 69fb1f1..f9ddf44 100644
--- a/lib/CodeGen/CGVtable.h
+++ b/lib/CodeGen/CGVtable.h
@@ -15,6 +15,7 @@
#define CLANG_CODEGEN_CGVTABLE_H
#include "llvm/ADT/DenseMap.h"
+#include "GlobalDecl.h"
namespace clang {
class CXXMethodDecl;
@@ -28,7 +29,7 @@ class CGVtableInfo {
/// MethodVtableIndices - Contains the index (relative to the vtable address
/// point) where the function pointer for a virtual function is stored.
- typedef llvm::DenseMap<const CXXMethodDecl *, int64_t> MethodVtableIndicesTy;
+ typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVtableIndicesTy;
MethodVtableIndicesTy MethodVtableIndices;
typedef std::pair<const CXXRecordDecl *,
@@ -38,6 +39,8 @@ class CGVtableInfo {
/// offsets for virtual bases of a class are stored.
typedef llvm::DenseMap<ClassPairTy, int64_t> VirtualBaseClassIndiciesTy;
VirtualBaseClassIndiciesTy VirtualBaseClassIndicies;
+
+ llvm::DenseMap<const CXXRecordDecl *, llvm::Constant *> Vtables;
public:
CGVtableInfo(CodeGenModule &CGM)
: CGM(CGM) { }
@@ -45,7 +48,7 @@ public:
/// getMethodVtableIndex - Return the index (relative to the vtable address
/// point) where the function pointer for the given virtual function is
/// stored.
- int64_t getMethodVtableIndex(const CXXMethodDecl *MD);
+ int64_t getMethodVtableIndex(GlobalDecl GD);
/// getVirtualBaseOffsetIndex - Return the index (relative to the vtable
/// address point) where the offset of the virtual base that contains the
@@ -54,6 +57,10 @@ public:
/// base.
int64_t getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
const CXXRecordDecl *VBase);
+
+ llvm::Constant *getVtable(const CXXRecordDecl *RD);
+ llvm::Constant *getCtorVtable(const CXXRecordDecl *RD,
+ const CXXRecordDecl *Class, uint64_t Offset);
};
}
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 4be3413..475c7bf 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -27,11 +27,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
: BlockFunction(cgm, *this, Builder), CGM(cgm),
Target(CGM.getContext().Target),
Builder(cgm.getModule().getContext()),
-#ifndef USEINDIRECTBRANCH
- DebugInfo(0), IndirectGotoSwitch(0),
-#else
DebugInfo(0), IndirectBranch(0),
-#endif
SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0),
CXXThisDecl(0) {
LLVMIntTy = ConvertType(getContext().IntTy);
@@ -134,7 +130,6 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
EmitFunctionEpilog(*CurFnInfo, ReturnValue);
-#ifdef USEINDIRECTBRANCH
// If someone did an indirect goto, emit the indirect goto block at the end of
// the function.
if (IndirectBranch) {
@@ -142,13 +137,10 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
Builder.ClearInsertionPoint();
}
-
-#endif
// Remove the AllocaInsertPt instruction, which is just a convenience for us.
llvm::Instruction *Ptr = AllocaInsertPt;
AllocaInsertPt = 0;
Ptr->eraseFromParent();
-#ifdef USEINDIRECTBRANCH
// If someone took the address of a label but never did an indirect goto, we
// made a zero entry PHI node, which is illegal, zap it now.
@@ -159,8 +151,6 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
PN->eraseFromParent();
}
}
-
-#endif
}
void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
@@ -260,19 +250,21 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD,
// FIXME: Support CXXTryStmt here, too.
if (const CompoundStmt *S = FD->getCompoundBody()) {
StartFunction(GD, FD->getResultType(), Fn, Args, S->getLBracLoc());
- const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD);
- llvm::BasicBlock *DtorEpilogue = 0;
- if (DD) {
- DtorEpilogue = createBasicBlock("dtor.epilogue");
-
- PushCleanupBlock(DtorEpilogue);
- }
-
- if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
+
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
EmitCtorPrologue(CD, GD.getCtorType());
- EmitStmt(S);
+ EmitStmt(S);
+
+ // If any of the member initializers are temporaries bound to references
+ // make sure to emit their destructors.
+ EmitCleanupBlocks(0);
+
+ } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) {
+ llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue");
+ PushCleanupBlock(DtorEpilogue);
+
+ EmitStmt(S);
- if (DD) {
CleanupBlockInfo Info = PopCleanupBlock();
assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!");
@@ -283,7 +275,11 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD,
EmitBlock(Info.SwitchBlock);
if (Info.EndBlock)
EmitBlock(Info.EndBlock);
+ } else {
+ // Just a regular function, emit its body.
+ EmitStmt(S);
}
+
FinishFunction(S->getRBracLoc());
} else if (FD->isImplicit()) {
const CXXRecordDecl *ClassDecl =
@@ -493,121 +489,32 @@ void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty) {
TypeInfo.second/8));
}
-#ifndef USEINDIRECTBRANCH
-unsigned CodeGenFunction::GetIDForAddrOfLabel(const LabelStmt *L) {
- // Use LabelIDs.size()+1 as the new ID if one hasn't been assigned.
- unsigned &Entry = LabelIDs[L];
- if (Entry) return Entry;
-#else
-
llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelStmt *L) {
// Make sure that there is a block for the indirect goto.
if (IndirectBranch == 0)
GetIndirectGotoBlock();
-#endif
-#ifndef USEINDIRECTBRANCH
- Entry = LabelIDs.size();
-#else
llvm::BasicBlock *BB = getBasicBlockForLabel(L);
-#endif
-
-#ifndef USEINDIRECTBRANCH
- // If this is the first "address taken" of a label and the indirect goto has
- // already been seen, add this to it.
- if (IndirectGotoSwitch) {
- // If this is the first address-taken label, set it as the default dest.
- if (Entry == 1)
- IndirectGotoSwitch->setSuccessor(0, getBasicBlockForLabel(L));
- else {
- // Otherwise add it to the switch as a new dest.
- const llvm::IntegerType *Int32Ty = llvm::Type::getInt32Ty(VMContext);
- IndirectGotoSwitch->addCase(llvm::ConstantInt::get(Int32Ty, Entry),
- getBasicBlockForLabel(L));
- }
- }
- return Entry;
-#else
// Make sure the indirect branch includes all of the address-taken blocks.
IndirectBranch->addDestination(BB);
return llvm::BlockAddress::get(CurFn, BB);
-#endif
}
llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() {
-#ifndef USEINDIRECTBRANCH
- // If we already made the switch stmt for indirect goto, return its block.
- if (IndirectGotoSwitch) return IndirectGotoSwitch->getParent();
-#else
// If we already made the indirect branch for indirect goto, return its block.
if (IndirectBranch) return IndirectBranch->getParent();
-#endif
-#ifndef USEINDIRECTBRANCH
- EmitBlock(createBasicBlock("indirectgoto"));
-#else
CGBuilderTy TmpBuilder(createBasicBlock("indirectgoto"));
-#endif
-#ifndef USEINDIRECTBRANCH
- const llvm::IntegerType *Int32Ty = llvm::Type::getInt32Ty(VMContext);
-#else
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
-#endif
// Create the PHI node that indirect gotos will add entries to.
-#ifndef USEINDIRECTBRANCH
- llvm::Value *DestVal = Builder.CreatePHI(Int32Ty, "indirect.goto.dest");
-#else
llvm::Value *DestVal = TmpBuilder.CreatePHI(Int8PtrTy, "indirect.goto.dest");
-#endif
-
-#ifndef USEINDIRECTBRANCH
- // Create the switch instruction. For now, set the insert block to this block
- // which will be fixed as labels are added.
- IndirectGotoSwitch = Builder.CreateSwitch(DestVal, Builder.GetInsertBlock());
-
- // Clear the insertion point to indicate we are in unreachable code.
- Builder.ClearInsertionPoint();
- // If we already have labels created, add them.
- if (!LabelIDs.empty()) {
- // Invert LabelID's so that the order is determinstic.
- std::vector<const LabelStmt*> AddrTakenLabelsByID;
- AddrTakenLabelsByID.resize(LabelIDs.size());
-
- for (std::map<const LabelStmt*,unsigned>::iterator
- LI = LabelIDs.begin(), LE = LabelIDs.end(); LI != LE; ++LI) {
- assert(LI->second-1 < AddrTakenLabelsByID.size() &&
- "Numbering inconsistent");
- AddrTakenLabelsByID[LI->second-1] = LI->first;
- }
-
- // Set the default entry as the first block.
- IndirectGotoSwitch->setSuccessor(0,
- getBasicBlockForLabel(AddrTakenLabelsByID[0]));
-
- // FIXME: The iteration order of this is nondeterminstic!
- for (unsigned i = 1, e = AddrTakenLabelsByID.size(); i != e; ++i)
- IndirectGotoSwitch->addCase(llvm::ConstantInt::get(Int32Ty, i+1),
- getBasicBlockForLabel(AddrTakenLabelsByID[i]));
- } else {
- // Otherwise, create a dead block and set it as the default dest. This will
- // be removed by the optimizers after the indirect goto is set up.
- llvm::BasicBlock *Dummy = createBasicBlock("indgoto.dummy");
- EmitBlock(Dummy);
- IndirectGotoSwitch->setSuccessor(0, Dummy);
- Builder.CreateUnreachable();
- Builder.ClearInsertionPoint();
- }
-
- return IndirectGotoSwitch->getParent();
-#else
// Create the indirect branch instruction.
IndirectBranch = TmpBuilder.CreateIndirectBr(DestVal);
return IndirectBranch->getParent();
-#endif
}
llvm::Value *CodeGenFunction::GetVLASize(const VariableArrayType *VAT) {
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index fe8113e..d96c355 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -74,7 +74,7 @@ class CodeGenFunction : public BlockFunction {
void operator=(const CodeGenFunction&); // DO NOT IMPLEMENT
public:
CodeGenModule &CGM; // Per-module state.
- TargetInfo &Target;
+ const TargetInfo &Target;
typedef std::pair<llvm::Value *, llvm::Value *> ComplexPairTy;
CGBuilderTy Builder;
@@ -193,28 +193,12 @@ public:
private:
CGDebugInfo *DebugInfo;
-#ifndef USEINDIRECTBRANCH
- /// LabelIDs - Track arbitrary ids assigned to labels for use in implementing
- /// the GCC address-of-label extension and indirect goto. IDs are assigned to
- /// labels inside getIDForAddrOfLabel().
- std::map<const LabelStmt*, unsigned> LabelIDs;
-#else
/// IndirectBranch - The first time an indirect goto is seen we create a
/// block with an indirect branch. Every time we see the address of a label
/// taken, we add the label to the indirect goto. Every subsequent indirect
/// goto is codegen'd as a jump to the IndirectBranch's basic block.
llvm::IndirectBrInst *IndirectBranch;
-#endif
-
-#ifndef USEINDIRECTBRANCH
- /// IndirectGotoSwitch - The first time an indirect goto is seen we create a
- /// block with the switch for the indirect gotos. Every time we see the
- /// address of a label taken, we add the label to the indirect goto. Every
- /// subsequent indirect goto is codegen'd as a jump to the
- /// IndirectGotoSwitch's basic block.
- llvm::SwitchInst *IndirectGotoSwitch;
-#endif
/// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C
/// decls.
llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
@@ -397,9 +381,6 @@ public:
/// legal to call this function even if there is no current insertion point.
void FinishFunction(SourceLocation EndLoc=SourceLocation());
- /// GenerateVtable - Generate the vtable for the given type.
- llvm::Value *GenerateVtable(const CXXRecordDecl *RD);
-
/// DynamicTypeAdjust - Do the non-virtual and virtual adjustments on an
/// object pointer to alter the dynamic type of the pointer. Used by
/// GenerateCovariantThunk for building thunks.
@@ -586,11 +567,7 @@ public:
/// the input field number being accessed.
static unsigned getAccessedFieldNo(unsigned Idx, const llvm::Constant *Elts);
-#ifndef USEINDIRECTBRANCH
- unsigned GetIDForAddrOfLabel(const LabelStmt *L);
-#else
llvm::BlockAddress *GetAddrOfLabel(const LabelStmt *L);
-#endif
llvm::BasicBlock *GetIndirectGotoBlock();
/// EmitMemSetToZero - Generate code to memset a value of the given type to 0.
@@ -669,6 +646,14 @@ public:
const ArrayType *Array,
llvm::Value *This);
+ void EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
+ llvm::Value *NumElements,
+ llvm::Value *This);
+
+ llvm::Constant * GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
+ const ArrayType *Array,
+ llvm::Value *This);
+
void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type,
llvm::Value *This);
@@ -678,6 +663,12 @@ public:
llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E);
void EmitCXXDeleteExpr(const CXXDeleteExpr *E);
+ void EmitDeleteCall(const FunctionDecl *DeleteFD, llvm::Value *Ptr,
+ QualType DeleteTy);
+
+ llvm::Value* EmitCXXTypeidExpr(const CXXTypeidExpr *E);
+ llvm::Value *EmitDynamicCast(llvm::Value *V, const CXXDynamicCastExpr *DCE);
+
//===--------------------------------------------------------------------===//
// Declaration Emission
//===--------------------------------------------------------------------===//
@@ -851,17 +842,18 @@ public:
LValue EmitConditionalOperatorLValue(const ConditionalOperator *E);
LValue EmitCastLValue(const CastExpr *E);
LValue EmitNullInitializationLValue(const CXXZeroInitValueExpr *E);
- LValue EmitPointerToDataMemberLValue(const DeclRefExpr *E);
+
+ LValue EmitPointerToDataMemberLValue(const FieldDecl *Field);
llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
- LValue EmitLValueForField(llvm::Value* Base, FieldDecl* Field,
+ LValue EmitLValueForField(llvm::Value* Base, const FieldDecl* Field,
bool isUnion, unsigned CVRQualifiers);
LValue EmitLValueForIvar(QualType ObjectTy,
llvm::Value* Base, const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers);
- LValue EmitLValueForBitfield(llvm::Value* Base, FieldDecl* Field,
+ LValue EmitLValueForBitfield(llvm::Value* Base, const FieldDecl* Field,
unsigned CVRQualifiers);
LValue EmitBlockDeclRefLValue(const BlockDeclRefExpr *E);
@@ -870,6 +862,7 @@ public:
LValue EmitCXXConstructLValue(const CXXConstructExpr *E);
LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E);
LValue EmitCXXExprWithTemporariesLValue(const CXXExprWithTemporaries *E);
+ LValue EmitCXXTypeidLValue(const CXXTypeidExpr *E);
LValue EmitObjCMessageExprLValue(const ObjCMessageExpr *E);
LValue EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E);
@@ -901,8 +894,11 @@ public:
const Decl *TargetDecl = 0);
RValue EmitCallExpr(const CallExpr *E);
- llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *&This,
+ llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
const llvm::Type *Ty);
+ llvm::Value *BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
+ llvm::Value *&This, const llvm::Type *Ty);
+
RValue EmitCXXMemberCall(const CXXMethodDecl *MD,
llvm::Value *Callee,
llvm::Value *This,
@@ -1016,7 +1012,7 @@ public:
/// EmitCXXGlobalDtorRegistration - Emits a call to register the global ptr
/// with the C++ runtime so that its destructor will be called at exit.
- void EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor,
+ void EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
llvm::Constant *DeclPtr);
/// GenerateCXXGlobalInitFunc - Generates code for initializing global
@@ -1033,7 +1029,7 @@ public:
bool IsInitializer = false);
void EmitCXXThrowExpr(const CXXThrowExpr *E);
-
+
//===--------------------------------------------------------------------===//
// Internal Helpers
//===--------------------------------------------------------------------===//
@@ -1101,6 +1097,7 @@ private:
if (CallArgTypeInfo) {
for (typename T::arg_type_iterator I = CallArgTypeInfo->arg_type_begin(),
E = CallArgTypeInfo->arg_type_end(); I != E; ++I, ++Arg) {
+ assert(Arg != ArgEnd && "Running over edge of argument list!");
QualType ArgType = *I;
assert(getContext().getCanonicalType(ArgType.getNonReferenceType()).
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index db609f6..0e6f4a6 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -17,7 +17,7 @@
#include "CGCall.h"
#include "CGObjCRuntime.h"
#include "Mangle.h"
-#include "clang/Frontend/CompileOptions.h"
+#include "clang/CodeGen/CodeGenOptions.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
@@ -30,15 +30,16 @@
#include "llvm/Module.h"
#include "llvm/Intrinsics.h"
#include "llvm/Target/TargetData.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
using namespace CodeGen;
-CodeGenModule::CodeGenModule(ASTContext &C, const CompileOptions &compileOpts,
+CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
llvm::Module &M, const llvm::TargetData &TD,
Diagnostic &diags)
: BlockModule(C, M, TD, Types, *this), Context(C),
- Features(C.getLangOptions()), CompileOpts(compileOpts), TheModule(M),
+ Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M),
TheTargetData(TD), Diags(diags), Types(C, M, TD), MangleCtx(C),
VtableInfo(*this), Runtime(0),
MemCpyFn(0), MemMoveFn(0), MemSetFn(0), CFConstantStringClassRef(0),
@@ -54,7 +55,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CompileOptions &compileOpts,
Runtime = CreateMacObjCRuntime(*this);
// If debug info generation is enabled, create the CGDebugInfo object.
- DebugInfo = CompileOpts.DebugInfo ? new CGDebugInfo(this) : 0;
+ DebugInfo = CodeGenOpts.DebugInfo ? new CGDebugInfo(this) : 0;
}
CodeGenModule::~CodeGenModule() {
@@ -347,6 +348,11 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
if (D->hasAttr<NoInlineAttr>())
F->addFnAttr(llvm::Attribute::NoInline);
+ if (Features.getStackProtectorMode() == LangOptions::SSPOn)
+ F->addFnAttr(llvm::Attribute::StackProtect);
+ else if (Features.getStackProtectorMode() == LangOptions::SSPReq)
+ F->addFnAttr(llvm::Attribute::StackProtectReq);
+
if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
F->setAlignment(AA->getAlignment()/8);
// C++ ABI requires 2-byte alignment for member functions.
@@ -543,10 +549,15 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
// Static data may be deferred, but out-of-line static data members
// cannot be.
- // FIXME: What if the initializer has side effects?
- return VD->isInAnonymousNamespace() ||
- (VD->getStorageClass() == VarDecl::Static &&
- !(VD->isStaticDataMember() && VD->isOutOfLine()));
+ if (VD->isInAnonymousNamespace())
+ return true;
+ if (VD->getStorageClass() == VarDecl::Static) {
+ // Initializer has side effects?
+ if (VD->getInit() && VD->getInit()->HasSideEffects(Context))
+ return false;
+ return !(VD->isStaticDataMember() && VD->isOutOfLine());
+ }
+ return false;
}
void CodeGenModule::EmitGlobal(GlobalDecl GD) {
@@ -639,6 +650,24 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
return llvm::ConstantExpr::getBitCast(Entry, PTy);
}
+ // This function doesn't have a complete type (for example, the return
+ // type is an incomplete struct). Use a fake type instead, and make
+ // sure not to try to set attributes.
+ bool IsIncompleteFunction = false;
+ if (!isa<llvm::FunctionType>(Ty)) {
+ Ty = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+ std::vector<const llvm::Type*>(), false);
+ IsIncompleteFunction = true;
+ }
+ llvm::Function *F = llvm::Function::Create(cast<llvm::FunctionType>(Ty),
+ llvm::Function::ExternalLinkage,
+ "", &getModule());
+ F->setName(MangledName);
+ if (D.getDecl())
+ SetFunctionAttributes(cast<FunctionDecl>(D.getDecl()), F,
+ IsIncompleteFunction);
+ Entry = F;
+
// This is the first use or definition of a mangled name. If there is a
// deferred decl with this name, remember that we need to emit it at the end
// of the file.
@@ -672,23 +701,6 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
DeferredCopyAssignmentToEmit(D);
}
- // This function doesn't have a complete type (for example, the return
- // type is an incomplete struct). Use a fake type instead, and make
- // sure not to try to set attributes.
- bool IsIncompleteFunction = false;
- if (!isa<llvm::FunctionType>(Ty)) {
- Ty = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- std::vector<const llvm::Type*>(), false);
- IsIncompleteFunction = true;
- }
- llvm::Function *F = llvm::Function::Create(cast<llvm::FunctionType>(Ty),
- llvm::Function::ExternalLinkage,
- "", &getModule());
- F->setName(MangledName);
- if (D.getDecl())
- SetFunctionAttributes(cast<FunctionDecl>(D.getDecl()), F,
- IsIncompleteFunction);
- Entry = F;
return F;
}
@@ -1075,7 +1087,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage);
} else if (Linkage == GVA_TemplateInstantiation)
GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage);
- else if (!CompileOpts.NoCommon &&
+ else if (!CodeGenOpts.NoCommon &&
!D->hasExternalStorage() && !D->getInit() &&
!D->getAttr<SectionAttr>()) {
GV->setLinkage(llvm::GlobalVariable::CommonLinkage);
@@ -1548,7 +1560,14 @@ std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) {
llvm::Constant *
CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) {
// FIXME: This can be more efficient.
- return GetAddrOfConstantString(GetStringForStringLiteral(S));
+ // FIXME: We shouldn't need to bitcast the constant in the wide string case.
+ llvm::Constant *C = GetAddrOfConstantString(GetStringForStringLiteral(S));
+ if (S->isWide()) {
+ llvm::Type *DestTy =
+ llvm::PointerType::getUnqual(getTypes().ConvertType(S->getType()));
+ C = llvm::ConstantExpr::getBitCast(C, DestTy);
+ }
+ return C;
}
/// GetAddrOfConstantStringFromObjCEncode - Return a pointer to a constant
@@ -1697,6 +1716,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
EmitNamespace(cast<NamespaceDecl>(D));
break;
// No code generation needed.
+ case Decl::UsingShadow:
case Decl::Using:
case Decl::UsingDirective:
case Decl::ClassTemplate:
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 2e58337..c8562d6 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -23,6 +23,7 @@
#include "CGCXX.h"
#include "CGVtable.h"
#include "CodeGenTypes.h"
+#include "GlobalDecl.h"
#include "Mangle.h"
#include "llvm/Module.h"
#include "llvm/ADT/DenseMap.h"
@@ -31,8 +32,6 @@
#include "llvm/Support/ValueHandle.h"
#include <list>
-#define ATTACH_DEBUG_INFO_TO_AN_INSN 1
-
namespace llvm {
class Module;
class Constant;
@@ -61,7 +60,7 @@ namespace clang {
class ValueDecl;
class VarDecl;
class LangOptions;
- class CompileOptions;
+ class CodeGenOptions;
class Diagnostic;
class AnnotateAttr;
class CXXDestructorDecl;
@@ -72,46 +71,7 @@ namespace CodeGen {
class CGDebugInfo;
class CGObjCRuntime;
-/// GlobalDecl - represents a global declaration. This can either be a
-/// CXXConstructorDecl and the constructor type (Base, Complete).
-/// a CXXDestructorDecl and the destructor type (Base, Complete) or
-/// a VarDecl, a FunctionDecl or a BlockDecl.
-class GlobalDecl {
- llvm::PointerIntPair<const Decl*, 2> Value;
-
- void Init(const Decl *D) {
- assert(!isa<CXXConstructorDecl>(D) && "Use other ctor with ctor decls!");
- assert(!isa<CXXDestructorDecl>(D) && "Use other ctor with dtor decls!");
-
- Value.setPointer(D);
- }
-public:
- GlobalDecl() {}
-
- GlobalDecl(const VarDecl *D) { Init(D);}
- GlobalDecl(const FunctionDecl *D) { Init(D); }
- GlobalDecl(const BlockDecl *D) { Init(D); }
- GlobalDecl(const ObjCMethodDecl *D) { Init(D); }
-
- GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type)
- : Value(D, Type) {}
- GlobalDecl(const CXXDestructorDecl *D, CXXDtorType Type)
- : Value(D, Type) {}
-
- const Decl *getDecl() const { return Value.getPointer(); }
-
- CXXCtorType getCtorType() const {
- assert(isa<CXXConstructorDecl>(getDecl()) && "Decl is not a ctor!");
- return static_cast<CXXCtorType>(Value.getInt());
- }
-
- CXXDtorType getDtorType() const {
- assert(isa<CXXDestructorDecl>(getDecl()) && "Decl is not a dtor!");
- return static_cast<CXXDtorType>(Value.getInt());
- }
-};
-
/// CodeGenModule - This class organizes the cross-function state that is used
/// while generating LLVM code.
class CodeGenModule : public BlockModule {
@@ -122,7 +82,7 @@ class CodeGenModule : public BlockModule {
ASTContext &Context;
const LangOptions &Features;
- const CompileOptions &CompileOpts;
+ const CodeGenOptions &CodeGenOpts;
llvm::Module &TheModule;
const llvm::TargetData &TheTargetData;
Diagnostic &Diags;
@@ -201,7 +161,7 @@ class CodeGenModule : public BlockModule {
llvm::LLVMContext &VMContext;
public:
- CodeGenModule(ASTContext &C, const CompileOptions &CompileOpts,
+ CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts,
llvm::Module &M, const llvm::TargetData &TD, Diagnostic &Diags);
~CodeGenModule();
@@ -222,7 +182,7 @@ public:
CGDebugInfo *getDebugInfo() { return DebugInfo; }
ASTContext &getContext() const { return Context; }
- const CompileOptions &getCompileOpts() const { return CompileOpts; }
+ const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
const LangOptions &getLangOptions() const { return Features; }
llvm::Module &getModule() const { return TheModule; }
CodeGenTypes &getTypes() { return Types; }
@@ -252,8 +212,26 @@ public:
llvm::Constant *GetAddrOfFunction(GlobalDecl GD,
const llvm::Type *Ty = 0);
+ /// GenerateVtable - Generate the vtable for the given type. LayoutClass is
+ /// the class to use for the virtual base layout information. For
+ /// non-construction vtables, this is always the same as RD. Offset is the
+ /// offset in bits for the RD object in the LayoutClass, if we're generating a
+ /// construction vtable, otherwise 0.
+ llvm::Constant *GenerateVtable(const CXXRecordDecl *LayoutClass,
+ const CXXRecordDecl *RD,
+ uint64_t Offset=0);
+
+ /// GenerateVTT - Generate the VTT for the given type.
+ llvm::Constant *GenerateVTT(const CXXRecordDecl *RD);
+
/// GenerateRtti - Generate the rtti information for the given type.
llvm::Constant *GenerateRtti(const CXXRecordDecl *RD);
+ /// GenerateRttiRef - Generate a reference to the rtti information for the
+ /// given type.
+ llvm::Constant *GenerateRttiRef(const CXXRecordDecl *RD);
+ /// GenerateRttiNonClass - Generate the rtti information for the given
+ /// non-class type.
+ llvm::Constant *GenerateRttiNonClass(QualType Ty);
/// BuildThunk - Build a thunk for the given method
llvm::Constant *BuildThunk(const CXXMethodDecl *MD, bool Extern, int64_t nv,
@@ -263,6 +241,11 @@ public:
int64_t nv_t, int64_t v_t,
int64_t nv_r, int64_t v_r);
+ typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t;
+ typedef llvm::DenseMap<const CXXRecordDecl *,
+ llvm::DenseMap<CtorVtable_t, int64_t>*> AddrMap_t;
+ llvm::DenseMap<const CXXRecordDecl *, AddrMap_t*> AddressPoints;
+
/// GetCXXBaseClassOffset - Returns the offset from a derived class to its
/// base class. Returns null if the offset is 0.
llvm::Constant *GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl,
@@ -499,7 +482,7 @@ private:
/// EmitCXXGlobalInitFunc - Emit a function that initializes C++ globals.
void EmitCXXGlobalInitFunc();
-
+
// FIXME: Hardcoding priority here is gross.
void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535);
void AddGlobalDtor(llvm::Function *Dtor, int Priority=65535);
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index d43d13e..1f83f37 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -492,7 +492,7 @@ const CGRecordLayout &
CodeGenTypes::getCGRecordLayout(const TagDecl *TD) const {
const Type *Key =
Context.getTagDeclType(TD).getTypePtr();
- llvm::DenseMap<const Type*, CGRecordLayout *>::iterator I
+ llvm::DenseMap<const Type*, CGRecordLayout *>::const_iterator I
= CGRecordLayouts.find(Key);
assert (I != CGRecordLayouts.end()
&& "Unable to find record layout information for type");
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index a92a019..f447549 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -91,7 +91,7 @@ namespace CodeGen {
/// while lowering AST types to LLVM types.
class CodeGenTypes {
ASTContext &Context;
- TargetInfo &Target;
+ const TargetInfo &Target;
llvm::Module& TheModule;
const llvm::TargetData& TheTargetData;
mutable const ABIInfo* TheABIInfo;
@@ -153,7 +153,7 @@ public:
~CodeGenTypes();
const llvm::TargetData &getTargetData() const { return TheTargetData; }
- TargetInfo &getTarget() const { return Target; }
+ const TargetInfo &getTarget() const { return Target; }
ASTContext &getContext() const { return Context; }
const ABIInfo &getABIInfo() const;
llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); }
diff --git a/lib/CodeGen/GlobalDecl.h b/lib/CodeGen/GlobalDecl.h
new file mode 100644
index 0000000..b812020
--- /dev/null
+++ b/lib/CodeGen/GlobalDecl.h
@@ -0,0 +1,110 @@
+//===--- GlobalDecl.h - Global declaration holder ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A GlobalDecl can hold either a regular variable/function or a C++ ctor/dtor
+// together with its type.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_GLOBALDECL_H
+#define CLANG_CODEGEN_GLOBALDECL_H
+
+namespace clang {
+
+namespace CodeGen {
+
+/// GlobalDecl - represents a global declaration. This can either be a
+/// CXXConstructorDecl and the constructor type (Base, Complete).
+/// a CXXDestructorDecl and the destructor type (Base, Complete) or
+/// a VarDecl, a FunctionDecl or a BlockDecl.
+class GlobalDecl {
+ llvm::PointerIntPair<const Decl*, 2> Value;
+
+ void Init(const Decl *D) {
+ assert(!isa<CXXConstructorDecl>(D) && "Use other ctor with ctor decls!");
+ assert(!isa<CXXDestructorDecl>(D) && "Use other ctor with dtor decls!");
+
+ Value.setPointer(D);
+ }
+
+public:
+ GlobalDecl() {}
+
+ GlobalDecl(const VarDecl *D) { Init(D);}
+ GlobalDecl(const FunctionDecl *D) { Init(D); }
+ GlobalDecl(const BlockDecl *D) { Init(D); }
+ GlobalDecl(const ObjCMethodDecl *D) { Init(D); }
+
+ GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type)
+ : Value(D, Type) {}
+ GlobalDecl(const CXXDestructorDecl *D, CXXDtorType Type)
+ : Value(D, Type) {}
+
+ const Decl *getDecl() const { return Value.getPointer(); }
+
+ CXXCtorType getCtorType() const {
+ assert(isa<CXXConstructorDecl>(getDecl()) && "Decl is not a ctor!");
+ return static_cast<CXXCtorType>(Value.getInt());
+ }
+
+ CXXDtorType getDtorType() const {
+ assert(isa<CXXDestructorDecl>(getDecl()) && "Decl is not a dtor!");
+ return static_cast<CXXDtorType>(Value.getInt());
+ }
+
+ friend bool operator==(const GlobalDecl &LHS, const GlobalDecl &RHS) {
+ return LHS.Value == RHS.Value;
+ }
+
+ void *getAsOpaquePtr() const { return Value.getOpaqueValue(); }
+
+ static GlobalDecl getFromOpaquePtr(void *P) {
+ GlobalDecl GD;
+ GD.Value.setFromOpaqueValue(P);
+ return GD;
+ }
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+namespace llvm {
+ template<class> struct DenseMapInfo;
+
+ template<> struct DenseMapInfo<clang::CodeGen::GlobalDecl> {
+ static inline clang::CodeGen::GlobalDecl getEmptyKey() {
+ return clang::CodeGen::GlobalDecl();
+ }
+
+ static inline clang::CodeGen::GlobalDecl getTombstoneKey() {
+ return clang::CodeGen::GlobalDecl::
+ getFromOpaquePtr(reinterpret_cast<void*>(-1));
+ }
+
+ static unsigned getHashValue(clang::CodeGen::GlobalDecl GD) {
+ return DenseMapInfo<void*>::getHashValue(GD.getAsOpaquePtr());
+ }
+
+ static bool isEqual(clang::CodeGen::GlobalDecl LHS,
+ clang::CodeGen::GlobalDecl RHS) {
+ return LHS == RHS;
+ }
+
+ static bool isPod() {
+ // GlobalDecl isn't *technically* a POD type. However, we can get
+ // away with calling it a POD type since its copy constructor,
+ // copy assignment operator, and destructor are all trivial.
+ return true;
+ }
+
+ };
+
+}
+
+#endif
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index a5b3452..0a7124d 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -53,7 +53,10 @@ namespace {
void mangleCXXVtable(const CXXRecordDecl *RD);
void mangleCXXVTT(const CXXRecordDecl *RD);
+ void mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
+ const CXXRecordDecl *Type);
void mangleCXXRtti(QualType Ty);
+ void mangleCXXRttiName(QualType Ty);
void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type);
void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type);
@@ -65,6 +68,8 @@ namespace {
bool mangleStandardSubstitution(const NamedDecl *ND);
void addSubstitution(const NamedDecl *ND) {
+ ND = cast<NamedDecl>(ND->getCanonicalDecl());
+
addSubstitution(reinterpret_cast<uintptr_t>(ND));
}
void addSubstitution(QualType T);
@@ -127,8 +132,10 @@ static bool isInCLinkageSpecification(const Decl *D) {
bool CXXNameMangler::mangleFunctionDecl(const FunctionDecl *FD) {
// Clang's "overloadable" attribute extension to C/C++ implies name mangling
- // (always).
- if (!FD->hasAttr<OverloadableAttr>()) {
+ // (always) as does passing a C++ member function and a function
+ // whose name is not a simple identifier.
+ if (!FD->hasAttr<OverloadableAttr>() && !isa<CXXMethodDecl>(FD) &&
+ FD->getDeclName().isIdentifier()) {
// C functions are not mangled, and "main" is never mangled.
if (!Context.getASTContext().getLangOptions().CPlusPlus || FD->isMain())
return false;
@@ -140,7 +147,7 @@ bool CXXNameMangler::mangleFunctionDecl(const FunctionDecl *FD) {
return false;
// No name mangling in a C linkage specification.
- if (!isa<CXXMethodDecl>(FD) && isInCLinkageSpecification(FD))
+ if (isInCLinkageSpecification(FD))
return false;
}
@@ -212,6 +219,17 @@ void CXXNameMangler::mangleCXXVTT(const CXXRecordDecl *RD) {
mangleName(RD);
}
+void CXXNameMangler::mangleCXXCtorVtable(const CXXRecordDecl *RD,
+ int64_t Offset,
+ const CXXRecordDecl *Type) {
+ // <special-name> ::= TC <type> <offset number> _ <base type>
+ Out << "_ZTC";
+ mangleName(RD);
+ Out << Offset;
+ Out << "_";
+ mangleName(Type);
+}
+
void CXXNameMangler::mangleCXXRtti(QualType Ty) {
// <special-name> ::= TI <type> # typeinfo structure
Out << "_ZTI";
@@ -219,6 +237,13 @@ void CXXNameMangler::mangleCXXRtti(QualType Ty) {
mangleType(Ty);
}
+void CXXNameMangler::mangleCXXRttiName(QualType Ty) {
+ // <special-name> ::= TS <type> # typeinfo name (null terminated byte string)
+ Out << "_ZTS";
+
+ mangleType(Ty);
+}
+
void CXXNameMangler::mangleGuardVariable(const VarDecl *D) {
// <special-name> ::= GV <object name> # Guard variable for one-time
// # initialization
@@ -719,15 +744,15 @@ void CXXNameMangler::mangleType(QualType T) {
// Only operate on the canonical type!
T = Context.getASTContext().getCanonicalType(T);
- bool IsSubstitutable = T.hasQualifiers() || !isa<BuiltinType>(T);
+ bool IsSubstitutable = T.hasLocalQualifiers() || !isa<BuiltinType>(T);
if (IsSubstitutable && mangleSubstitution(T))
return;
- if (Qualifiers Quals = T.getQualifiers()) {
+ if (Qualifiers Quals = T.getLocalQualifiers()) {
mangleQualifiers(Quals);
// Recurse: even if the qualified type isn't yet substitutable,
// the unqualified type might be.
- mangleType(T.getUnqualifiedType());
+ mangleType(T.getLocalUnqualifiedType());
} else {
switch (T->getTypeClass()) {
#define ABSTRACT_TYPE(CLASS, PARENT)
@@ -1015,6 +1040,11 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
// ::= <expr-primary>
switch (E->getStmtClass()) {
default: assert(false && "Unhandled expression kind!");
+
+ case Expr::ParenExprClass:
+ mangleExpression(cast<ParenExpr>(E)->getSubExpr());
+ break;
+
case Expr::DeclRefExprClass: {
const Decl *D = cast<DeclRefExpr>(E)->getDecl();
@@ -1169,6 +1199,7 @@ bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) {
if (mangleStandardSubstitution(ND))
return true;
+ ND = cast<NamedDecl>(ND->getCanonicalDecl());
return mangleSubstitution(reinterpret_cast<uintptr_t>(ND));
}
@@ -1255,6 +1286,8 @@ static bool isCharSpecialization(QualType T, const char *Name) {
bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
// <substitution> ::= St # ::std::
+ // FIXME: type_info == comes out as __ZNK3std9type_infoeqERKS0_ instead of
+ // __ZNKSt9type_infoeqERKS_
if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
if (isStdNamespace(NS)) {
Out << "St";
@@ -1433,6 +1466,23 @@ namespace clang {
os.flush();
}
+ void mangleCXXVTT(MangleContext &Context, const CXXRecordDecl *RD,
+ llvm::raw_ostream &os) {
+ CXXNameMangler Mangler(Context, os);
+ Mangler.mangleCXXVTT(RD);
+
+ os.flush();
+ }
+
+ void mangleCXXCtorVtable(MangleContext &Context, const CXXRecordDecl *RD,
+ int64_t Offset, const CXXRecordDecl *Type,
+ llvm::raw_ostream &os) {
+ CXXNameMangler Mangler(Context, os);
+ Mangler.mangleCXXCtorVtable(RD, Offset, Type);
+
+ os.flush();
+ }
+
void mangleCXXRtti(MangleContext &Context, QualType Ty,
llvm::raw_ostream &os) {
CXXNameMangler Mangler(Context, os);
@@ -1440,4 +1490,12 @@ namespace clang {
os.flush();
}
+
+ void mangleCXXRttiName(MangleContext &Context, QualType Ty,
+ llvm::raw_ostream &os) {
+ CXXNameMangler Mangler(Context, os);
+ Mangler.mangleCXXRttiName(Ty);
+
+ os.flush();
+ }
}
diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h
index 7f46a10..458708f 100644
--- a/lib/CodeGen/Mangle.h
+++ b/lib/CodeGen/Mangle.h
@@ -67,8 +67,13 @@ namespace clang {
llvm::raw_ostream &os);
void mangleCXXVTT(MangleContext &Context, const CXXRecordDecl *RD,
llvm::raw_ostream &os);
+ void mangleCXXCtorVtable(MangleContext &Context, const CXXRecordDecl *RD,
+ int64_t Offset, const CXXRecordDecl *Type,
+ llvm::raw_ostream &os);
void mangleCXXRtti(MangleContext &Context, QualType T,
llvm::raw_ostream &os);
+ void mangleCXXRttiName(MangleContext &Context, QualType T,
+ llvm::raw_ostream &os);
void mangleCXXCtor(MangleContext &Context, const CXXConstructorDecl *D,
CXXCtorType Type, llvm::raw_ostream &os);
void mangleCXXDtor(MangleContext &Context, const CXXDestructorDecl *D,
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index c8f686a..1d8f31d 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -13,7 +13,7 @@
#include "clang/CodeGen/ModuleBuilder.h"
#include "CodeGenModule.h"
-#include "clang/Frontend/CompileOptions.h"
+#include "clang/CodeGen/CodeGenOptions.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
@@ -32,14 +32,14 @@ namespace {
Diagnostic &Diags;
llvm::OwningPtr<const llvm::TargetData> TD;
ASTContext *Ctx;
- const CompileOptions CompileOpts; // Intentionally copied in.
+ const CodeGenOptions CodeGenOpts; // Intentionally copied in.
protected:
llvm::OwningPtr<llvm::Module> M;
llvm::OwningPtr<CodeGen::CodeGenModule> Builder;
public:
CodeGeneratorImpl(Diagnostic &diags, const std::string& ModuleName,
- const CompileOptions &CO, llvm::LLVMContext& C)
- : Diags(diags), CompileOpts(CO), M(new llvm::Module(ModuleName, C)) {}
+ const CodeGenOptions &CGO, llvm::LLVMContext& C)
+ : Diags(diags), CodeGenOpts(CGO), M(new llvm::Module(ModuleName, C)) {}
virtual ~CodeGeneratorImpl() {}
@@ -57,7 +57,7 @@ namespace {
M->setTargetTriple(Ctx->Target.getTriple().getTriple());
M->setDataLayout(Ctx->Target.getTargetDescription());
TD.reset(new llvm::TargetData(Ctx->Target.getTargetDescription()));
- Builder.reset(new CodeGen::CodeGenModule(Context, CompileOpts,
+ Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts,
*M, *TD, Diags));
}
@@ -96,7 +96,7 @@ namespace {
CodeGenerator *clang::CreateLLVMCodeGen(Diagnostic &Diags,
const std::string& ModuleName,
- const CompileOptions &CO,
+ const CodeGenOptions &CGO,
llvm::LLVMContext& C) {
- return new CodeGeneratorImpl(Diags, ModuleName, CO, C);
+ return new CodeGeneratorImpl(Diags, ModuleName, CGO, C);
}
diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp
index 852bba4..ba0bc66 100644
--- a/lib/CodeGen/TargetABIInfo.cpp
+++ b/lib/CodeGen/TargetABIInfo.cpp
@@ -168,8 +168,28 @@ static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) {
return Size == 32 || Size == 64;
}
-static bool areAllFields32Or64BitBasicType(const RecordDecl *RD,
- ASTContext &Context) {
+/// canExpandIndirectArgument - Test whether an argument type which is to be
+/// passed indirectly (on the stack) would have the equivalent layout if it was
+/// expanded into separate arguments. If so, we prefer to do the latter to avoid
+/// inhibiting optimizations.
+///
+// FIXME: This predicate is missing many cases, currently it just follows
+// llvm-gcc (checks that all fields are 32-bit or 64-bit primitive types). We
+// should probably make this smarter, or better yet make the LLVM backend
+// capable of handling it.
+static bool canExpandIndirectArgument(QualType Ty, ASTContext &Context) {
+ // We can only expand structure types.
+ const RecordType *RT = Ty->getAs<RecordType>();
+ if (!RT)
+ return false;
+
+ // We can only expand (C) structures.
+ //
+ // FIXME: This needs to be generalized to handle classes as well.
+ const RecordDecl *RD = RT->getDecl();
+ if (!RD->isStruct() || isa<CXXRecordDecl>(RD))
+ return false;
+
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
i != e; ++i) {
const FieldDecl *FD = *i;
@@ -442,14 +462,13 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
if (Ty->isStructureType() && Context.getTypeSize(Ty) == 0)
return ABIArgInfo::getIgnore();
- // Expand structs with size <= 128-bits which consist only of
- // basic types (int, long long, float, double, xxx*). This is
- // non-recursive and does not ignore empty fields.
- if (const RecordType *RT = Ty->getAsStructureType()) {
- if (Context.getTypeSize(Ty) <= 4*32 &&
- areAllFields32Or64BitBasicType(RT->getDecl(), Context))
- return ABIArgInfo::getExpand();
- }
+ // Expand small (<= 128-bit) record types when we know that the stack layout
+ // of those arguments will match the struct. This is important because the
+ // LLVM backend isn't smart enough to remove byval, which inhibits many
+ // optimizations.
+ if (Context.getTypeSize(Ty) <= 4*32 &&
+ canExpandIndirectArgument(Ty, Context))
+ return ABIArgInfo::getExpand();
return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, Context));
} else {
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 6088d96..fcd96f1 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -137,7 +137,20 @@ public:
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
virtual bool IsMathErrnoDefault() const;
+ virtual bool IsBlocksDefault() const {
+ // Blocks default to on for 10.6 (darwin10) and beyond.
+ return (DarwinVersion[0] > 9);
+ }
+ virtual bool IsObjCNonFragileABIDefault() const {
+ // Non-fragile ABI default to on for 10.5 (darwin9) and beyond on x86-64.
+ return (DarwinVersion[0] >= 9 &&
+ getTriple().getArch() == llvm::Triple::x86_64);
+ }
virtual bool IsUnwindTablesDefault() const;
+ virtual unsigned GetDefaultStackProtectorLevel() const {
+ // Stack protectors default to on for 10.6 (darwin10) and beyond.
+ return (DarwinVersion[0] > 9) ? 1 : 0;
+ }
virtual const char *GetDefaultRelocationModel() const;
virtual const char *GetForcedPicModel() const;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 808c31c..34154f3 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -26,6 +26,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Host.h"
#include "llvm/System/Process.h"
#include "InputInfo.h"
@@ -320,6 +321,23 @@ static std::string getLLVMTriple(const ToolChain &TC, const ArgList &Args) {
}
}
+// FIXME: Move to target hook.
+static bool isSignedCharDefault(const llvm::Triple &Triple) {
+ switch (Triple.getArch()) {
+ default:
+ return true;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ if (Triple.getOS() == llvm::Triple::Darwin)
+ return true;
+ return false;
+
+ case llvm::Triple::systemz:
+ return false;
+ }
+}
+
void Clang::AddARMTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
const Driver &D = getToolChain().getHost().getDriver();
@@ -428,28 +446,42 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
false))
CmdArgs.push_back("--no-implicit-float");
+ const char *CPUName = 0;
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- // FIXME: We may need some translation here from the options gcc takes to
- // names the LLVM backend understand?
- CmdArgs.push_back("-mcpu");
- CmdArgs.push_back(A->getValue(Args));
- } else {
- // Select default CPU.
+ if (llvm::StringRef(A->getValue(Args)) == "native") {
+ // FIXME: Reject attempts to use -march=native unless the target matches
+ // the host.
+ //
+ // FIXME: We should also incorporate the detected target features for use
+ // with -native.
+ std::string CPU = llvm::sys::getHostCPUName();
+ if (!CPU.empty())
+ CPUName = Args.MakeArgString(CPU);
+ } else
+ CPUName = A->getValue(Args);
+ }
+ // Select the default CPU if none was given (or detection failed).
+ if (!CPUName) {
// FIXME: Need target hooks.
if (memcmp(getToolChain().getOS().c_str(), "darwin", 6) == 0) {
if (getToolChain().getArchName() == "x86_64")
- CmdArgs.push_back("--mcpu=core2");
+ CPUName = "core2";
else if (getToolChain().getArchName() == "i386")
- CmdArgs.push_back("--mcpu=yonah");
+ CPUName = "yonah";
} else {
if (getToolChain().getArchName() == "x86_64")
- CmdArgs.push_back("--mcpu=x86-64");
+ CPUName = "x86-64";
else if (getToolChain().getArchName() == "i386")
- CmdArgs.push_back("--mcpu=pentium4");
+ CPUName = "pentium4";
}
}
+ if (CPUName) {
+ CmdArgs.push_back("--mcpu");
+ CmdArgs.push_back(CPUName);
+ }
+
// FIXME: Use iterator.
for (ArgList::const_iterator
it = Args.begin(), ie = Args.end(); it != ie; ++it) {
@@ -855,18 +887,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
Args.AddLastArg(CmdArgs, options::OPT_ffreestanding);
Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
- Args.AddLastArg(CmdArgs, options::OPT_fgnu_runtime);
Args.AddLastArg(CmdArgs, options::OPT_flax_vector_conversions);
- Args.AddLastArg(CmdArgs, options::OPT_fms_extensions);
- Args.AddLastArg(CmdArgs, options::OPT_fnext_runtime);
Args.AddLastArg(CmdArgs, options::OPT_fno_caret_diagnostics);
Args.AddLastArg(CmdArgs, options::OPT_fno_show_column);
Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc_only);
Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc);
Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch);
- // FIXME: Should we remove this?
- Args.AddLastArg(CmdArgs, options::OPT_fobjc_nonfragile_abi);
- Args.AddLastArg(CmdArgs, options::OPT_fobjc_tight_layout);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
@@ -875,32 +901,34 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_pthread);
- // Forward stack protector flags.
+ // -stack-protector=0 is default.
+ unsigned StackProtectorLevel = 0;
if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector,
options::OPT_fstack_protector_all,
options::OPT_fstack_protector)) {
- if (A->getOption().matches(options::OPT_fno_stack_protector))
- CmdArgs.push_back("--stack-protector=0");
- else if (A->getOption().matches(options::OPT_fstack_protector))
- CmdArgs.push_back("--stack-protector=1");
- else
- CmdArgs.push_back("--stack-protector=2");
+ if (A->getOption().matches(options::OPT_fstack_protector))
+ StackProtectorLevel = 1;
+ else if (A->getOption().matches(options::OPT_fstack_protector_all))
+ StackProtectorLevel = 2;
+ } else
+ StackProtectorLevel = getToolChain().GetDefaultStackProtectorLevel();
+ if (StackProtectorLevel) {
+ CmdArgs.push_back("-stack-protector");
+ CmdArgs.push_back(Args.MakeArgString(llvm::Twine(StackProtectorLevel)));
}
// Forward -f options with positive and negative forms; we translate
// these by hand.
- // -fbuiltin is default, only pass non-default.
+ // -fbuiltin is default.
if (!Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin))
CmdArgs.push_back("-fbuiltin=0");
- // -fblocks default varies depending on platform and language; only
- // pass if specified.
- if (Arg *A = Args.getLastArg(options::OPT_fblocks, options::OPT_fno_blocks)) {
- if (A->getOption().matches(options::OPT_fblocks))
- CmdArgs.push_back("-fblocks");
- else
- CmdArgs.push_back("-fblocks=0");
+ // -fblocks=0 is default.
+ if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks,
+ getToolChain().IsBlocksDefault())) {
+ Args.AddLastArg(CmdArgs, options::OPT_fblock_introspection);
+ CmdArgs.push_back("-fblocks");
}
if (needsExceptions(Args, InputType, getToolChain().getTriple()))
@@ -908,18 +936,40 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
else
CmdArgs.push_back("-fexceptions=0");
- // -frtti is default, only pass non-default.
+ // -frtti is default.
if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti))
CmdArgs.push_back("-frtti=0");
- // -fsigned-char/-funsigned-char default varies depending on platform; only
+ // -fsigned-char is default.
+ if (!Args.hasFlag(options::OPT_fsigned_char,
+ options::OPT_funsigned_char,
+ isSignedCharDefault(getToolChain().getTriple())))
+ CmdArgs.push_back("-fsigned-char=0");
+
+ // -fms-extensions=0 is default.
+ if (Args.hasFlag(options::OPT_fms_extensions,
+ options::OPT_fno_ms_extensions,
+ getToolChain().getTriple().getOS() == llvm::Triple::Win32))
+ CmdArgs.push_back("-fms-extensions");
+
+ // -fnext-runtime is default.
+ if (!Args.hasFlag(options::OPT_fnext_runtime,
+ options::OPT_fgnu_runtime,
+ getToolChain().getTriple().getOS() == llvm::Triple::Darwin))
+ CmdArgs.push_back("-fgnu-runtime");
+
+ // -fobjc-nonfragile-abi=0 is default.
+ if (types::isObjC(InputType)) {
+ if (Args.hasArg(options::OPT_fobjc_nonfragile_abi) ||
+ getToolChain().IsObjCNonFragileABIDefault())
+ CmdArgs.push_back("-fobjc-nonfragile-abi");
+ }
+
+ // -fshort-wchar default varies depending on platform; only
// pass if specified.
- if (Arg *A = Args.getLastArg(options::OPT_fsigned_char,
- options::OPT_funsigned_char)) {
- if (A->getOption().matches(options::OPT_fsigned_char))
- CmdArgs.push_back("-fsigned-char");
- else
- CmdArgs.push_back("-fsigned-char=0");
+ if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar)) {
+ if (A->getOption().matches(options::OPT_fshort_wchar))
+ CmdArgs.push_back("-fshort-wchar");
}
// -fno-pascal-strings is default, only pass non-default. If the tool chain
@@ -2588,6 +2638,10 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
else
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o")));
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtn.o")));
+ // FIXME: g++ is more complicated here, it tries to put -lstdc++
+ // before -lm, for example.
+ if (D.CCCIsCXX)
+ CmdArgs.push_back("-lstdc++");
}
const char *Exec =
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index c616c6a..30893e7 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -89,6 +89,19 @@ bool types::isAcceptedByClang(ID Id) {
}
}
+bool types::isObjC(ID Id) {
+ switch (Id) {
+ default:
+ return false;
+
+ case TY_ObjC: case TY_PP_ObjC:
+ case TY_ObjCXX: case TY_PP_ObjCXX:
+ case TY_ObjCHeader: case TY_PP_ObjCHeader:
+ case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
+ return true;
+ }
+}
+
bool types::isCXX(ID Id) {
switch (Id) {
default:
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index c0415bf..e3cd6dd 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/Support/Compiler.h"
@@ -61,14 +62,14 @@ public:
return false;
}
- virtual bool ReadTargetTriple(const std::string &Triple) {
+ virtual bool ReadTargetTriple(llvm::StringRef Triple) {
TargetTriple = Triple;
return false;
}
- virtual bool ReadPredefinesBuffer(const char *PCHPredef,
- unsigned PCHPredefLen,
+ virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef,
FileID PCHBufferID,
+ llvm::StringRef OriginalFileName,
std::string &SuggestedPredefines) {
Predefines = PCHPredef;
return false;
@@ -132,7 +133,14 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
// PCH loaded successfully. Now create the preprocessor.
// Get information about the target being compiled for.
- AST->Target.reset(TargetInfo::CreateTargetInfo(TargetTriple));
+ //
+ // FIXME: This is broken, we should store the TargetOptions in the PCH.
+ TargetOptions TargetOpts;
+ TargetOpts.ABI = "";
+ TargetOpts.CPU = "";
+ TargetOpts.Features.clear();
+ TargetOpts.Triple = TargetTriple;
+ AST->Target.reset(TargetInfo::CreateTargetInfo(AST->Diags, TargetOpts));
AST->PP.reset(new Preprocessor(AST->Diags, LangInfo, *AST->Target.get(),
AST->getSourceManager(), HeaderInfo));
Preprocessor &PP = *AST->PP.get();
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
index d2831fa..ede3d47 100644
--- a/lib/Frontend/AnalysisConsumer.cpp
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -20,6 +20,7 @@
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Analysis/ManagerRegistry.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/PathSensitive/AnalysisManager.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
@@ -27,7 +28,6 @@
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Frontend/ManagerRegistry.h"
#include "clang/Frontend/PathDiagnosticClients.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/Compiler.h"
@@ -44,10 +44,6 @@ static ExplodedNode::Auditor* CreateUbiViz();
// Basic type definitions.
//===----------------------------------------------------------------------===//
-namespace {
- typedef void (*CodeAction)(AnalysisManager& Mgr, Decl *D);
-} // end anonymous namespace
-
//===----------------------------------------------------------------------===//
// Special PathDiagnosticClients.
//===----------------------------------------------------------------------===//
@@ -66,116 +62,135 @@ CreatePlistHTMLDiagnosticClient(const std::string& prefix,
namespace {
- class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer {
- typedef std::vector<CodeAction> Actions;
- Actions FunctionActions;
- Actions ObjCMethodActions;
- Actions ObjCImplementationActions;
- Actions TranslationUnitActions;
+ class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer {
+ public:
+ typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D);
+
+ private:
+ typedef std::vector<CodeAction> Actions;
+ Actions FunctionActions;
+ Actions ObjCMethodActions;
+ Actions ObjCImplementationActions;
+ Actions TranslationUnitActions;
- public:
- ASTContext* Ctx;
- const Preprocessor &PP;
- const std::string OutDir;
- AnalyzerOptions Opts;
+public:
+ ASTContext* Ctx;
+ const Preprocessor &PP;
+ const std::string OutDir;
+ AnalyzerOptions Opts;
+ bool declDisplayed;
- // PD is owned by AnalysisManager.
- PathDiagnosticClient *PD;
+ // PD is owned by AnalysisManager.
+ PathDiagnosticClient *PD;
- StoreManagerCreator CreateStoreMgr;
- ConstraintManagerCreator CreateConstraintMgr;
+ StoreManagerCreator CreateStoreMgr;
+ ConstraintManagerCreator CreateConstraintMgr;
- llvm::OwningPtr<AnalysisManager> Mgr;
+ llvm::OwningPtr<AnalysisManager> Mgr;
- AnalysisConsumer(const Preprocessor& pp,
- const std::string& outdir,
- const AnalyzerOptions& opts)
- : Ctx(0), PP(pp), OutDir(outdir),
- Opts(opts), PD(0) {
- DigestAnalyzerOptions();
- }
+ AnalysisConsumer(const Preprocessor& pp,
+ const std::string& outdir,
+ const AnalyzerOptions& opts)
+ : Ctx(0), PP(pp), OutDir(outdir),
+ Opts(opts), declDisplayed(false), PD(0) {
+ DigestAnalyzerOptions();
+ }
- void DigestAnalyzerOptions() {
- // Create the PathDiagnosticClient.
- if (!OutDir.empty()) {
- switch (Opts.AnalysisDiagOpt) {
- default:
+ void DigestAnalyzerOptions() {
+ // Create the PathDiagnosticClient.
+ if (!OutDir.empty()) {
+ switch (Opts.AnalysisDiagOpt) {
+ default:
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
- case PD_##NAME: PD = CREATEFN(OutDir, PP); break;
+ case PD_##NAME: PD = CREATEFN(OutDir, PP); break;
#include "clang/Frontend/Analyses.def"
- }
}
+ }
- // Create the analyzer component creators.
- if (ManagerRegistry::StoreMgrCreator != 0) {
- CreateStoreMgr = ManagerRegistry::StoreMgrCreator;
- }
- else {
- switch (Opts.AnalysisStoreOpt) {
- default:
- assert(0 && "Unknown store manager.");
+ // Create the analyzer component creators.
+ if (ManagerRegistry::StoreMgrCreator != 0) {
+ CreateStoreMgr = ManagerRegistry::StoreMgrCreator;
+ }
+ else {
+ switch (Opts.AnalysisStoreOpt) {
+ default:
+ assert(0 && "Unknown store manager.");
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \
- case NAME##Model: CreateStoreMgr = CREATEFN; break;
+ case NAME##Model: CreateStoreMgr = CREATEFN; break;
#include "clang/Frontend/Analyses.def"
- }
}
+ }
- if (ManagerRegistry::ConstraintMgrCreator != 0)
- CreateConstraintMgr = ManagerRegistry::ConstraintMgrCreator;
- else {
- switch (Opts.AnalysisConstraintsOpt) {
- default:
- assert(0 && "Unknown store manager.");
+ if (ManagerRegistry::ConstraintMgrCreator != 0)
+ CreateConstraintMgr = ManagerRegistry::ConstraintMgrCreator;
+ else {
+ switch (Opts.AnalysisConstraintsOpt) {
+ default:
+ assert(0 && "Unknown store manager.");
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
- case NAME##Model: CreateConstraintMgr = CREATEFN; break;
+ case NAME##Model: CreateConstraintMgr = CREATEFN; break;
#include "clang/Frontend/Analyses.def"
- }
}
}
-
- void addCodeAction(CodeAction action) {
- FunctionActions.push_back(action);
- ObjCMethodActions.push_back(action);
- }
-
- void addObjCImplementationAction(CodeAction action) {
- ObjCImplementationActions.push_back(action);
- }
-
- void addTranslationUnitAction(CodeAction action) {
- TranslationUnitActions.push_back(action);
+ }
+
+ void DisplayFunction(const Decl *D) {
+ if (!Opts.AnalyzerDisplayProgress || declDisplayed)
+ return;
+
+ declDisplayed = true;
+ // FIXME: Is getCodeDecl() always a named decl?
+ if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
+ const NamedDecl *ND = cast<NamedDecl>(D);
+ SourceManager &SM = Mgr->getASTContext().getSourceManager();
+ llvm::errs() << "ANALYZE: "
+ << SM.getPresumedLoc(ND->getLocation()).getFilename()
+ << ' ' << ND->getNameAsString() << '\n';
}
+ }
- virtual void Initialize(ASTContext &Context) {
- Ctx = &Context;
- Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
- PP.getLangOptions(), PD,
- CreateStoreMgr, CreateConstraintMgr,
- Opts.AnalyzerDisplayProgress,
- Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
- Opts.PurgeDead, Opts.EagerlyAssume,
- Opts.TrimGraph));
- }
+ void addCodeAction(CodeAction action) {
+ FunctionActions.push_back(action);
+ ObjCMethodActions.push_back(action);
+ }
- virtual void HandleTopLevelDecl(DeclGroupRef D) {
- for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
- HandleTopLevelSingleDecl(*I);
- }
+ void addObjCImplementationAction(CodeAction action) {
+ ObjCImplementationActions.push_back(action);
+ }
- void HandleTopLevelSingleDecl(Decl *D);
- virtual void HandleTranslationUnit(ASTContext &C);
+ void addTranslationUnitAction(CodeAction action) {
+ TranslationUnitActions.push_back(action);
+ }
- void HandleCode(Decl* D, Stmt* Body, Actions& actions);
- };
+ virtual void Initialize(ASTContext &Context) {
+ Ctx = &Context;
+ Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
+ PP.getLangOptions(), PD,
+ CreateStoreMgr, CreateConstraintMgr,
+ Opts.AnalyzerDisplayProgress,
+ Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
+ Opts.PurgeDead, Opts.EagerlyAssume,
+ Opts.TrimGraph));
+ }
+ virtual void HandleTopLevelDecl(DeclGroupRef D) {
+ declDisplayed = false;
+ for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
+ HandleTopLevelSingleDecl(*I);
+ }
+ void HandleTopLevelSingleDecl(Decl *D);
+ virtual void HandleTranslationUnit(ASTContext &C);
+ void HandleCode(Decl* D, Stmt* Body, Actions& actions);
+};
} // end anonymous namespace
namespace llvm {
- template <> struct FoldingSetTrait<CodeAction> {
- static inline void Profile(CodeAction X, FoldingSetNodeID& ID) {
+ template <> struct FoldingSetTrait<AnalysisConsumer::CodeAction> {
+ static inline void Profile(AnalysisConsumer::CodeAction X,
+ FoldingSetNodeID& ID) {
ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X)));
}
};
@@ -238,7 +253,7 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
for (Actions::iterator I = TranslationUnitActions.begin(),
E = TranslationUnitActions.end(); I != E; ++I)
- (*I)(*Mgr, FD);
+ (*I)(*this, *Mgr, FD);
}
if (!ObjCImplementationActions.empty()) {
@@ -272,34 +287,38 @@ void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) {
// Dispatch on the actions.
for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I)
- (*I)(*Mgr, D);
+ (*I)(*this, *Mgr, D);
}
//===----------------------------------------------------------------------===//
// Analyses
//===----------------------------------------------------------------------===//
-static void ActionWarnDeadStores(AnalysisManager& mgr, Decl *D) {
+static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr,
+ Decl *D) {
if (LiveVariables *L = mgr.getLiveVariables(D)) {
+ C.DisplayFunction(D);
BugReporter BR(mgr);
CheckDeadStores(*mgr.getCFG(D), *L, mgr.getParentMap(D), BR);
}
}
-static void ActionWarnUninitVals(AnalysisManager& mgr, Decl *D) {
- if (CFG* c = mgr.getCFG(D))
+static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr,
+ Decl *D) {
+ if (CFG* c = mgr.getCFG(D)) {
+ C.DisplayFunction(D);
CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic());
+ }
}
-static void ActionGRExprEngine(AnalysisManager& mgr, Decl *D,
+static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D,
GRTransferFuncs* tf) {
-
llvm::OwningPtr<GRTransferFuncs> TF(tf);
// Display progress.
- mgr.DisplayFunction(D);
+ C.DisplayFunction(D);
// Construct the analysis engine. We first query for the LiveVariables
// information to see if the CFG is valid.
@@ -312,8 +331,14 @@ static void ActionGRExprEngine(AnalysisManager& mgr, Decl *D,
Eng.setTransferFunctions(tf);
Eng.RegisterInternalChecks(); // FIXME: Internal checks should just
// automatically register.
+
+ if (C.Opts.EnableExperimentalInternalChecks)
+ RegisterExperimentalInternalChecks(Eng);
+
RegisterAppleChecks(Eng, *D);
-
+
+ if (C.Opts.EnableExperimentalChecks)
+ RegisterExperimentalChecks(Eng);
// Set the graph auditor.
llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
@@ -337,85 +362,103 @@ static void ActionGRExprEngine(AnalysisManager& mgr, Decl *D,
Eng.getBugReporter().FlushReports();
}
-static void ActionCheckerCFRefAux(AnalysisManager& mgr, Decl *D,
- bool GCEnabled) {
+static void ActionCheckerCFRefAux(AnalysisConsumer &C, AnalysisManager& mgr,
+ Decl *D, bool GCEnabled) {
GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(),
GCEnabled,
mgr.getLangOptions());
- ActionGRExprEngine(mgr, D, TF);
+ ActionGRExprEngine(C, mgr, D, TF);
}
-static void ActionCheckerCFRef(AnalysisManager& mgr, Decl *D) {
+static void ActionCheckerCFRef(AnalysisConsumer &C, AnalysisManager& mgr,
+ Decl *D) {
switch (mgr.getLangOptions().getGCMode()) {
default:
assert (false && "Invalid GC mode.");
case LangOptions::NonGC:
- ActionCheckerCFRefAux(mgr, D, false);
+ ActionCheckerCFRefAux(C, mgr, D, false);
break;
case LangOptions::GCOnly:
- ActionCheckerCFRefAux(mgr, D, true);
+ ActionCheckerCFRefAux(C, mgr, D, true);
break;
case LangOptions::HybridGC:
- ActionCheckerCFRefAux(mgr, D, false);
- ActionCheckerCFRefAux(mgr, D, true);
+ ActionCheckerCFRefAux(C, mgr, D, false);
+ ActionCheckerCFRefAux(C, mgr, D, true);
break;
}
}
-static void ActionDisplayLiveVariables(AnalysisManager& mgr, Decl *D) {
+static void ActionDisplayLiveVariables(AnalysisConsumer &C,
+ AnalysisManager& mgr, Decl *D) {
if (LiveVariables* L = mgr.getLiveVariables(D)) {
- mgr.DisplayFunction(D);
+ C.DisplayFunction(D);
L->dumpBlockLiveness(mgr.getSourceManager());
}
}
-static void ActionCFGDump(AnalysisManager& mgr, Decl *D) {
- if (CFG* c = mgr.getCFG(D)) {
- mgr.DisplayFunction(D);
- c->dump(mgr.getLangOptions());
+static void ActionCFGDump(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
+ if (CFG *cfg = mgr.getCFG(D)) {
+ C.DisplayFunction(D);
+ cfg->dump(mgr.getLangOptions());
}
}
-static void ActionCFGView(AnalysisManager& mgr, Decl *D) {
- if (CFG* c = mgr.getCFG(D)) {
- mgr.DisplayFunction(D);
- c->viewCFG(mgr.getLangOptions());
+static void ActionCFGView(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
+ if (CFG *cfg = mgr.getCFG(D)) {
+ C.DisplayFunction(D);
+ cfg->viewCFG(mgr.getLangOptions());
}
}
-static void ActionSecuritySyntacticChecks(AnalysisManager &mgr, Decl *D) {
+static void ActionSecuritySyntacticChecks(AnalysisConsumer &C,
+ AnalysisManager &mgr, Decl *D) {
+ C.DisplayFunction(D);
BugReporter BR(mgr);
CheckSecuritySyntaxOnly(D, BR);
}
-static void ActionWarnObjCDealloc(AnalysisManager& mgr, Decl *D) {
+static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr,
+ Decl *D) {
if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
return;
+ C.DisplayFunction(D);
BugReporter BR(mgr);
- CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR);
+ CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR);
}
-static void ActionWarnObjCUnusedIvars(AnalysisManager& mgr, Decl *D) {
+static void ActionWarnObjCUnusedIvars(AnalysisConsumer &C, AnalysisManager& mgr,
+ Decl *D) {
+ C.DisplayFunction(D);
BugReporter BR(mgr);
- CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR);
+ CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR);
}
-static void ActionWarnObjCMethSigs(AnalysisManager& mgr, Decl *D) {
+static void ActionWarnObjCMethSigs(AnalysisConsumer &C, AnalysisManager& mgr,
+ Decl *D) {
+ C.DisplayFunction(D);
BugReporter BR(mgr);
-
CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(D), BR);
}
-static void ActionInlineCall(AnalysisManager &mgr, Decl *D) {
+static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr,
+ Decl *D) {
+ C.DisplayFunction(D);
+ BugReporter BR(mgr);
+ CheckSizeofPointer(D, BR);
+}
+
+static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr,
+ Decl *D) {
if (!D)
return;
+ C.DisplayFunction(D);
llvm::OwningPtr<GRTransferFuncs> TF(CreateCallInliner(mgr.getASTContext()));
// Construct the analysis engine.
diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp
index 13aecf1..bc56029 100644
--- a/lib/Frontend/Backend.cpp
+++ b/lib/Frontend/Backend.cpp
@@ -8,12 +8,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/ASTConsumers.h"
-#include "clang/CodeGen/ModuleBuilder.h"
-#include "clang/Frontend/CompileOptions.h"
-#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/CodeGen/CodeGenOptions.h"
+#include "clang/CodeGen/ModuleBuilder.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/PassManager.h"
@@ -40,7 +41,8 @@ using namespace llvm;
namespace {
class VISIBILITY_HIDDEN BackendConsumer : public ASTConsumer {
BackendAction Action;
- CompileOptions CompileOpts;
+ CodeGenOptions CodeGenOpts;
+ TargetOptions TargetOpts;
llvm::raw_ostream *AsmOutStream;
llvm::formatted_raw_ostream FormattedOutStream;
ASTContext *Context;
@@ -75,11 +77,12 @@ namespace {
public:
BackendConsumer(BackendAction action, Diagnostic &Diags,
- const LangOptions &langopts, const CompileOptions &compopts,
- const std::string &infile, llvm::raw_ostream* OS,
- LLVMContext& C) :
+ const LangOptions &langopts, const CodeGenOptions &compopts,
+ const TargetOptions &targetopts, const std::string &infile,
+ llvm::raw_ostream* OS, LLVMContext& C) :
Action(action),
- CompileOpts(compopts),
+ CodeGenOpts(compopts),
+ TargetOpts(targetopts),
AsmOutStream(OS),
LLVMIRGeneration("LLVM IR Generation Time"),
CodeGenerationTime("Code Generation Time"),
@@ -92,7 +95,7 @@ namespace {
formatted_raw_ostream::PRESERVE_STREAM);
// Enable -time-passes if -ftime-report is enabled.
- llvm::TimePassesIsEnabled = CompileOpts.TimePasses;
+ llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
}
~BackendConsumer() {
@@ -106,7 +109,7 @@ namespace {
virtual void Initialize(ASTContext &Ctx) {
Context = &Ctx;
- if (CompileOpts.TimePasses)
+ if (CodeGenOpts.TimePasses)
LLVMIRGeneration.startTimer();
Gen->Initialize(Ctx);
@@ -115,7 +118,7 @@ namespace {
ModuleProvider = new ExistingModuleProvider(TheModule);
TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription());
- if (CompileOpts.TimePasses)
+ if (CodeGenOpts.TimePasses)
LLVMIRGeneration.stopTimer();
}
@@ -124,24 +127,24 @@ namespace {
Context->getSourceManager(),
"LLVM IR generation of declaration");
- if (CompileOpts.TimePasses)
+ if (CodeGenOpts.TimePasses)
LLVMIRGeneration.startTimer();
Gen->HandleTopLevelDecl(D);
- if (CompileOpts.TimePasses)
+ if (CodeGenOpts.TimePasses)
LLVMIRGeneration.stopTimer();
}
virtual void HandleTranslationUnit(ASTContext &C) {
{
PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
- if (CompileOpts.TimePasses)
+ if (CodeGenOpts.TimePasses)
LLVMIRGeneration.startTimer();
Gen->HandleTranslationUnit(C);
- if (CompileOpts.TimePasses)
+ if (CodeGenOpts.TimePasses)
LLVMIRGeneration.stopTimer();
}
@@ -202,7 +205,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) {
} else if (Action == Backend_EmitLL) {
getPerModulePasses()->add(createPrintModulePass(&FormattedOutStream));
} else {
- bool Fast = CompileOpts.OptimizationLevel == 0;
+ bool Fast = CodeGenOpts.OptimizationLevel == 0;
// Create the TargetMachine for generating code.
std::string Triple = TheModule->getTargetTriple();
@@ -213,12 +216,12 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) {
}
std::string FeaturesStr;
- if (CompileOpts.CPU.size() || CompileOpts.Features.size()) {
+ if (TargetOpts.CPU.size() || TargetOpts.Features.size()) {
SubtargetFeatures Features;
- Features.setCPU(CompileOpts.CPU);
+ Features.setCPU(TargetOpts.CPU);
for (std::vector<std::string>::iterator
- it = CompileOpts.Features.begin(),
- ie = CompileOpts.Features.end(); it != ie; ++it)
+ it = TargetOpts.Features.begin(),
+ ie = TargetOpts.Features.end(); it != ie; ++it)
Features.AddFeature(*it);
FeaturesStr = Features.getString();
}
@@ -237,7 +240,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) {
FunctionPassManager *PM = getCodeGenPasses();
CodeGenOpt::Level OptLevel = CodeGenOpt::Default;
- switch (CompileOpts.OptimizationLevel) {
+ switch (CodeGenOpts.OptimizationLevel) {
default: break;
case 0: OptLevel = CodeGenOpt::None; break;
case 3: OptLevel = CodeGenOpt::Aggressive; break;
@@ -266,37 +269,44 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) {
}
void BackendConsumer::CreatePasses() {
+ unsigned OptLevel = CodeGenOpts.OptimizationLevel;
+ CodeGenOptions::InliningMethod Inlining = CodeGenOpts.Inlining;
+
+ // Handle disabling of LLVM optimization, where we want to preserve the
+ // internal module before any optimization.
+ if (CodeGenOpts.DisableLLVMOpts) {
+ OptLevel = 0;
+ Inlining = CodeGenOpts.NoInlining;
+ }
+
// In -O0 if checking is disabled, we don't even have per-function passes.
- if (CompileOpts.VerifyModule)
+ if (CodeGenOpts.VerifyModule)
getPerFunctionPasses()->add(createVerifierPass());
// Assume that standard function passes aren't run for -O0.
- if (CompileOpts.OptimizationLevel > 0)
- llvm::createStandardFunctionPasses(getPerFunctionPasses(),
- CompileOpts.OptimizationLevel);
+ if (OptLevel > 0)
+ llvm::createStandardFunctionPasses(getPerFunctionPasses(), OptLevel);
llvm::Pass *InliningPass = 0;
- switch (CompileOpts.Inlining) {
- case CompileOptions::NoInlining: break;
- case CompileOptions::NormalInlining: {
+ switch (Inlining) {
+ case CodeGenOptions::NoInlining: break;
+ case CodeGenOptions::NormalInlining: {
// Inline small functions
- unsigned Threshold = (CompileOpts.OptimizeSize ||
- CompileOpts.OptimizationLevel < 3) ? 50 : 200;
+ unsigned Threshold = (CodeGenOpts.OptimizeSize || OptLevel < 3) ? 50 : 200;
InliningPass = createFunctionInliningPass(Threshold);
break;
}
- case CompileOptions::OnlyAlwaysInlining:
+ case CodeGenOptions::OnlyAlwaysInlining:
InliningPass = createAlwaysInlinerPass(); // Respect always_inline
break;
}
// For now we always create per module passes.
PassManager *PM = getPerModulePasses();
- llvm::createStandardModulePasses(PM, CompileOpts.OptimizationLevel,
- CompileOpts.OptimizeSize,
- CompileOpts.UnitAtATime,
- CompileOpts.UnrollLoops,
- CompileOpts.SimplifyLibCalls,
+ llvm::createStandardModulePasses(PM, OptLevel, CodeGenOpts.OptimizeSize,
+ CodeGenOpts.UnitAtATime,
+ CodeGenOpts.UnrollLoops,
+ CodeGenOpts.SimplifyLibCalls,
/*HaveExceptions=*/true,
InliningPass);
}
@@ -308,7 +318,7 @@ void BackendConsumer::EmitAssembly() {
if (!TheModule || !TheTargetData)
return;
- TimeRegion Region(CompileOpts.TimePasses ? &CodeGenerationTime : 0);
+ TimeRegion Region(CodeGenOpts.TimePasses ? &CodeGenerationTime : 0);
// Make sure IR generation is happy with the module. This is
// released by the module provider.
@@ -363,10 +373,11 @@ void BackendConsumer::EmitAssembly() {
ASTConsumer *clang::CreateBackendConsumer(BackendAction Action,
Diagnostic &Diags,
const LangOptions &LangOpts,
- const CompileOptions &CompileOpts,
+ const CodeGenOptions &CodeGenOpts,
+ const TargetOptions &TargetOpts,
const std::string& InFile,
llvm::raw_ostream* OS,
LLVMContext& C) {
- return new BackendConsumer(Action, Diags, LangOpts, CompileOpts,
- InFile, OS, C);
+ return new BackendConsumer(Action, Diags, LangOpts, CodeGenOpts,
+ TargetOpts, InFile, OS, C);
}
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index e3ec786..3f0f430 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -6,17 +6,21 @@ add_clang_library(clangFrontend
AnalysisConsumer.cpp
Backend.cpp
CacheTokens.cpp
+ CompilerInstance.cpp
+ CompilerInvocation.cpp
DeclXML.cpp
DependencyFile.cpp
DiagChecker.cpp
DocumentXML.cpp
FixItRewriter.cpp
+ FrontendAction.cpp
+ FrontendActions.cpp
+ FrontendOptions.cpp
GeneratePCH.cpp
HTMLDiagnostics.cpp
HTMLPrint.cpp
InitHeaderSearch.cpp
InitPreprocessor.cpp
- ManagerRegistry.cpp
PCHReader.cpp
PCHReaderDecl.cpp
PCHReaderStmt.cpp
@@ -34,6 +38,7 @@ add_clang_library(clangFrontend
TextDiagnosticBuffer.cpp
TextDiagnosticPrinter.cpp
TypeXML.cpp
+ VerifyDiagnosticsClient.cpp
Warnings.cpp
)
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
new file mode 100644
index 0000000..0365761
--- /dev/null
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -0,0 +1,403 @@
+//===--- CompilerInstance.cpp ---------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PTHManager.h"
+#include "clang/Frontend/ChainedDiagnosticClient.h"
+#include "clang/Frontend/PCHReader.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/VerifyDiagnosticsClient.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+using namespace clang;
+
+CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext,
+ bool _OwnsLLVMContext)
+ : LLVMContext(_LLVMContext),
+ OwnsLLVMContext(_OwnsLLVMContext) {
+ }
+
+CompilerInstance::~CompilerInstance() {
+ if (OwnsLLVMContext)
+ delete LLVMContext;
+}
+
+void CompilerInstance::setDiagnostics(Diagnostic *Value) {
+ Diagnostics.reset(Value);
+}
+
+void CompilerInstance::setDiagnosticClient(DiagnosticClient *Value) {
+ DiagClient.reset(Value);
+}
+
+void CompilerInstance::setTarget(TargetInfo *Value) {
+ Target.reset(Value);
+}
+
+void CompilerInstance::setFileManager(FileManager *Value) {
+ FileMgr.reset(Value);
+}
+
+void CompilerInstance::setSourceManager(SourceManager *Value) {
+ SourceMgr.reset(Value);
+}
+
+void CompilerInstance::setPreprocessor(Preprocessor *Value) {
+ PP.reset(Value);
+}
+
+void CompilerInstance::setASTContext(ASTContext *Value) {
+ Context.reset(Value);
+}
+
+void CompilerInstance::setASTConsumer(ASTConsumer *Value) {
+ Consumer.reset(Value);
+}
+
+void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
+ CompletionConsumer.reset(Value);
+}
+
+// Diagnostics
+
+static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
+ unsigned argc, char **argv,
+ llvm::OwningPtr<DiagnosticClient> &DiagClient) {
+ std::string ErrorInfo;
+ llvm::raw_ostream *OS =
+ new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo);
+ if (!ErrorInfo.empty()) {
+ // FIXME: Do not fail like this.
+ llvm::errs() << "error opening -dump-build-information file '"
+ << DiagOpts.DumpBuildInformation << "', option ignored!\n";
+ delete OS;
+ return;
+ }
+
+ (*OS) << "clang-cc command line arguments: ";
+ for (unsigned i = 0; i != argc; ++i)
+ (*OS) << argv[i] << ' ';
+ (*OS) << '\n';
+
+ // Chain in a diagnostic client which will log the diagnostics.
+ DiagnosticClient *Logger =
+ new TextDiagnosticPrinter(*OS, DiagOpts, /*OwnsOutputStream=*/true);
+ DiagClient.reset(new ChainedDiagnosticClient(DiagClient.take(), Logger));
+}
+
+void CompilerInstance::createDiagnostics(int Argc, char **Argv) {
+ Diagnostics.reset(createDiagnostics(getDiagnosticOpts(), Argc, Argv));
+
+ if (Diagnostics)
+ DiagClient.reset(Diagnostics->getClient());
+}
+
+Diagnostic *CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
+ int Argc, char **Argv) {
+ llvm::OwningPtr<Diagnostic> Diags(new Diagnostic());
+
+ // Create the diagnostic client for reporting errors or for
+ // implementing -verify.
+ llvm::OwningPtr<DiagnosticClient> DiagClient(
+ new TextDiagnosticPrinter(llvm::errs(), Opts));
+
+ // Chain in -verify checker, if requested.
+ if (Opts.VerifyDiagnostics)
+ DiagClient.reset(new VerifyDiagnosticsClient(*Diags, DiagClient.take()));
+
+ if (!Opts.DumpBuildInformation.empty())
+ SetUpBuildDumpLog(Opts, Argc, Argv, DiagClient);
+
+ // Configure our handling of diagnostics.
+ Diags->setClient(DiagClient.take());
+ if (ProcessWarningOptions(*Diags, Opts))
+ return 0;
+
+ return Diags.take();
+}
+
+// File Manager
+
+void CompilerInstance::createFileManager() {
+ FileMgr.reset(new FileManager());
+}
+
+// Source Manager
+
+void CompilerInstance::createSourceManager() {
+ SourceMgr.reset(new SourceManager());
+}
+
+// Preprocessor
+
+void CompilerInstance::createPreprocessor() {
+ PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(),
+ getPreprocessorOpts(), getHeaderSearchOpts(),
+ getDependencyOutputOpts(), getTarget(),
+ getSourceManager(), getFileManager()));
+}
+
+Preprocessor *
+CompilerInstance::createPreprocessor(Diagnostic &Diags,
+ const LangOptions &LangInfo,
+ const PreprocessorOptions &PPOpts,
+ const HeaderSearchOptions &HSOpts,
+ const DependencyOutputOptions &DepOpts,
+ const TargetInfo &Target,
+ SourceManager &SourceMgr,
+ FileManager &FileMgr) {
+ // Create a PTH manager if we are using some form of a token cache.
+ PTHManager *PTHMgr = 0;
+ if (!PPOpts.TokenCache.empty())
+ PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags);
+
+ // FIXME: Don't fail like this.
+ if (Diags.hasErrorOccurred())
+ exit(1);
+
+ // Create the Preprocessor.
+ HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr);
+ Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target,
+ SourceMgr, *HeaderInfo, PTHMgr,
+ /*OwnsHeaderSearch=*/true);
+
+ // Note that this is different then passing PTHMgr to Preprocessor's ctor.
+ // That argument is used as the IdentifierInfoLookup argument to
+ // IdentifierTable's ctor.
+ if (PTHMgr) {
+ PTHMgr->setPreprocessor(PP);
+ PP->setPTHManager(PTHMgr);
+ }
+
+ InitializePreprocessor(*PP, PPOpts, HSOpts);
+
+ // Handle generating dependencies, if requested.
+ if (!DepOpts.OutputFile.empty())
+ AttachDependencyFileGen(*PP, DepOpts);
+
+ return PP;
+}
+
+// ASTContext
+
+void CompilerInstance::createASTContext() {
+ Preprocessor &PP = getPreprocessor();
+ Context.reset(new ASTContext(getLangOpts(), PP.getSourceManager(),
+ getTarget(), PP.getIdentifierTable(),
+ PP.getSelectorTable(), PP.getBuiltinInfo(),
+ /*FreeMemory=*/ !getFrontendOpts().DisableFree,
+ /*size_reserve=*/ 0));
+}
+
+// ExternalASTSource
+
+void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path) {
+ llvm::OwningPtr<ExternalASTSource> Source;
+ Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot,
+ getPreprocessor(), getASTContext()));
+ getASTContext().setExternalSource(Source);
+}
+
+ExternalASTSource *
+CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path,
+ const std::string &Sysroot,
+ Preprocessor &PP,
+ ASTContext &Context) {
+ llvm::OwningPtr<PCHReader> Reader;
+ Reader.reset(new PCHReader(PP, &Context,
+ Sysroot.empty() ? 0 : Sysroot.c_str()));
+
+ switch (Reader->ReadPCH(Path)) {
+ case PCHReader::Success:
+ // Set the predefines buffer as suggested by the PCH reader. Typically, the
+ // predefines buffer will be empty.
+ PP.setPredefines(Reader->getSuggestedPredefines());
+ return Reader.take();
+
+ case PCHReader::Failure:
+ // Unrecoverable failure: don't even try to process the input file.
+ break;
+
+ case PCHReader::IgnorePCH:
+ // No suitable PCH file could be found. Return an error.
+ break;
+ }
+
+ return 0;
+}
+
+// Code Completion
+
+void CompilerInstance::createCodeCompletionConsumer() {
+ const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt;
+ CompletionConsumer.reset(
+ createCodeCompletionConsumer(getPreprocessor(),
+ Loc.FileName, Loc.Line, Loc.Column,
+ getFrontendOpts().DebugCodeCompletionPrinter,
+ getFrontendOpts().ShowMacrosInCodeCompletion,
+ llvm::outs()));
+}
+
+CodeCompleteConsumer *
+CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
+ const std::string &Filename,
+ unsigned Line,
+ unsigned Column,
+ bool UseDebugPrinter,
+ bool ShowMacros,
+ llvm::raw_ostream &OS) {
+ // Tell the source manager to chop off the given file at a specific
+ // line and column.
+ const FileEntry *Entry = PP.getFileManager().getFile(Filename);
+ if (!Entry) {
+ PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file)
+ << Filename;
+ return 0;
+ }
+
+ // Truncate the named file at the given line/column.
+ PP.getSourceManager().truncateFileAt(Entry, Line, Column);
+
+ // Set up the creation routine for code-completion.
+ if (UseDebugPrinter)
+ return new PrintingCodeCompleteConsumer(ShowMacros, OS);
+ else
+ return new CIndexCodeCompleteConsumer(ShowMacros, OS);
+}
+
+// Output Files
+
+void CompilerInstance::addOutputFile(llvm::StringRef Path,
+ llvm::raw_ostream *OS) {
+ assert(OS && "Attempt to add empty stream to output list!");
+ OutputFiles.push_back(std::make_pair(Path, OS));
+}
+
+void CompilerInstance::ClearOutputFiles(bool EraseFiles) {
+ for (std::list< std::pair<std::string, llvm::raw_ostream*> >::iterator
+ it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) {
+ delete it->second;
+ if (EraseFiles && !it->first.empty())
+ llvm::sys::Path(it->first).eraseFromDisk();
+ }
+ OutputFiles.clear();
+}
+
+llvm::raw_fd_ostream *
+CompilerInstance::createDefaultOutputFile(bool Binary,
+ llvm::StringRef InFile,
+ llvm::StringRef Extension) {
+ return createOutputFile(getFrontendOpts().OutputFile, Binary,
+ InFile, Extension);
+}
+
+llvm::raw_fd_ostream *
+CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
+ bool Binary,
+ llvm::StringRef InFile,
+ llvm::StringRef Extension) {
+ std::string Error, OutputPathName;
+ llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary,
+ InFile, Extension,
+ &OutputPathName);
+ if (!OS) {
+ // FIXME: Don't fail this way.
+ llvm::errs() << "ERROR: " << Error << "\n";
+ ::exit(1);
+ }
+
+ // Add the output file -- but don't try to remove "-", since this means we are
+ // using stdin.
+ addOutputFile((OutputPathName != "-") ? OutputPathName : "", OS);
+
+ return OS;
+}
+
+llvm::raw_fd_ostream *
+CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
+ std::string &Error,
+ bool Binary,
+ llvm::StringRef InFile,
+ llvm::StringRef Extension,
+ std::string *ResultPathName) {
+ std::string OutFile;
+ if (!OutputPath.empty()) {
+ OutFile = OutputPath;
+ } else if (InFile == "-") {
+ OutFile = "-";
+ } else if (!Extension.empty()) {
+ llvm::sys::Path Path(InFile);
+ Path.eraseSuffix();
+ Path.appendSuffix(Extension);
+ OutFile = Path.str();
+ } else {
+ OutFile = "-";
+ }
+
+ llvm::raw_fd_ostream *OS =
+ new llvm::raw_fd_ostream(OutFile.c_str(), Error,
+ (Binary ? llvm::raw_fd_ostream::F_Binary : 0));
+ if (!OS)
+ return 0;
+
+ if (ResultPathName)
+ *ResultPathName = OutFile;
+
+ return OS;
+}
+
+// Initialization Utilities
+
+bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile) {
+ return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(),
+ getSourceManager(), getFrontendOpts());
+}
+
+bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile,
+ Diagnostic &Diags,
+ FileManager &FileMgr,
+ SourceManager &SourceMgr,
+ const FrontendOptions &Opts) {
+ // Figure out where to get and map in the main file.
+ if (Opts.EmptyInputOnly) {
+ const char *EmptyStr = "";
+ llvm::MemoryBuffer *SB =
+ llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<empty input>");
+ SourceMgr.createMainFileIDForMemBuffer(SB);
+ } else if (InputFile != "-") {
+ const FileEntry *File = FileMgr.getFile(InputFile);
+ if (File) SourceMgr.createMainFileID(File, SourceLocation());
+ if (SourceMgr.getMainFileID().isInvalid()) {
+ Diags.Report(diag::err_fe_error_reading) << InputFile;
+ return false;
+ }
+ } else {
+ llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getSTDIN();
+ SourceMgr.createMainFileIDForMemBuffer(SB);
+ if (SourceMgr.getMainFileID().isInvalid()) {
+ Diags.Report(diag::err_fe_error_reading_stdin);
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
new file mode 100644
index 0000000..ed6d0b7
--- /dev/null
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -0,0 +1,548 @@
+//===--- CompilerInvocation.cpp -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/CompilerInvocation.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ErrorHandling.h"
+using namespace clang;
+
+void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
+ const llvm::SmallVectorImpl<llvm::StringRef> &Args) {
+ llvm::llvm_report_error("FIXME: Not yet implemented!");
+}
+
+static const char *getAnalysisName(Analyses Kind) {
+ switch (Kind) {
+ default:
+ llvm::llvm_unreachable("Unknown analysis store!");
+#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)\
+ case NAME: return CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+ }
+}
+
+static const char *getAnalysisStoreName(AnalysisStores Kind) {
+ switch (Kind) {
+ default:
+ llvm::llvm_unreachable("Unknown analysis store!");
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \
+ case NAME##Model: return CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+ }
+}
+
+static const char *getAnalysisConstraintName(AnalysisConstraints Kind) {
+ switch (Kind) {
+ default:
+ llvm::llvm_unreachable("Unknown analysis constraints!");
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \
+ case NAME##Model: return CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+ }
+}
+
+static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) {
+ switch (Kind) {
+ default:
+ llvm::llvm_unreachable("Unknown analysis client!");
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE) \
+ case PD_##NAME: return CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+ }
+}
+
+static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
+ std::vector<std::string> &Res) {
+ for (unsigned i = 0, e = Opts.AnalysisList.size(); i != e; ++i)
+ Res.push_back(getAnalysisName(Opts.AnalysisList[i]));
+ if (Opts.AnalysisStoreOpt != BasicStoreModel) {
+ Res.push_back("-analyzer-store");
+ Res.push_back(getAnalysisStoreName(Opts.AnalysisStoreOpt));
+ }
+ if (Opts.AnalysisConstraintsOpt != RangeConstraintsModel) {
+ Res.push_back("-analyzer-constraints");
+ Res.push_back(getAnalysisConstraintName(Opts.AnalysisConstraintsOpt));
+ }
+ if (Opts.AnalysisDiagOpt != PD_HTML) {
+ Res.push_back("-analyzer-output");
+ Res.push_back(getAnalysisDiagClientName(Opts.AnalysisDiagOpt));
+ }
+ if (!Opts.AnalyzeSpecificFunction.empty()) {
+ Res.push_back("-analyze-function");
+ Res.push_back(Opts.AnalyzeSpecificFunction);
+ }
+ if (Opts.AnalyzeAll)
+ Res.push_back("-analyzer-opt-analyze-headers");
+ if (Opts.AnalyzerDisplayProgress)
+ Res.push_back("-analyzer-display-progress");
+ if (Opts.EagerlyAssume)
+ Res.push_back("-analyzer-eagerly-assume");
+ if (Opts.PurgeDead)
+ Res.push_back("-analyzer-purge-dead");
+ if (Opts.TrimGraph)
+ Res.push_back("-trim-egraph");
+ if (Opts.VisualizeEGDot)
+ Res.push_back("-analyzer-viz-egraph-graphviz");
+ if (Opts.VisualizeEGDot)
+ Res.push_back("-analyzer-viz-egraph-ubigraph");
+ if (Opts.EnableExperimentalChecks)
+ Res.push_back("-analyzer-experimental-checks");
+ if (Opts.EnableExperimentalInternalChecks)
+ Res.push_back("-analyzer-experimental-internal-checls");
+}
+
+static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (Opts.DebugInfo)
+ Res.push_back("-g");
+ if (Opts.DisableLLVMOpts)
+ Res.push_back("-disable-llvm-optzns");
+ if (Opts.DisableRedZone)
+ Res.push_back("-disable-red-zone");
+ if (!Opts.MergeAllConstants)
+ Res.push_back("-fno-merge-all-constants");
+ // NoCommon is only derived.
+ if (Opts.NoImplicitFloat)
+ Res.push_back("-no-implicit-float");
+ if (Opts.OptimizeSize) {
+ assert(Opts.OptimizationLevel == 2 && "Invalid options!");
+ Res.push_back("-Os");
+ } else if (Opts.OptimizationLevel == 0)
+ Res.push_back("-O" + Opts.OptimizationLevel);
+ // SimplifyLibCalls is only derived.
+ // TimePasses is only derived.
+ // UnitAtATime is unused.
+ // UnrollLoops is only derived.
+ // VerifyModule is only derived.
+ // Inlining is only derived.
+}
+
+static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (Opts.IncludeSystemHeaders)
+ Res.push_back("-sys-header-deps");
+ if (Opts.UsePhonyTargets)
+ Res.push_back("-MP");
+ if (!Opts.OutputFile.empty()) {
+ Res.push_back("-dependency-file");
+ Res.push_back(Opts.OutputFile);
+ }
+ for (unsigned i = 0, e = Opts.Targets.size(); i != e; ++i) {
+ Res.push_back("-MT");
+ Res.push_back(Opts.Targets[i]);
+ }
+}
+
+static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (Opts.IgnoreWarnings)
+ Res.push_back("-w");
+ if (Opts.NoRewriteMacros)
+ Res.push_back("-Wno-rewrite-macros");
+ if (Opts.Pedantic)
+ Res.push_back("-pedantic");
+ if (Opts.PedanticErrors)
+ Res.push_back("-pedantic-errors");
+ if (!Opts.ShowColumn)
+ Res.push_back("-fno-show-column");
+ if (!Opts.ShowLocation)
+ Res.push_back("-fno-show-source-location");
+ if (!Opts.ShowCarets)
+ Res.push_back("-fno-caret-diagnostics");
+ if (!Opts.ShowFixits)
+ Res.push_back("-fno-diagnostics-fixit-info");
+ if (Opts.ShowSourceRanges)
+ Res.push_back("-fdiagnostics-print-source-range-info");
+ if (Opts.ShowColors)
+ Res.push_back("-fcolor-diagnostics");
+ if (Opts.VerifyDiagnostics)
+ Res.push_back("-verify");
+ if (Opts.ShowOptionNames)
+ Res.push_back("-fdiagnostics-show-option");
+ if (Opts.MessageLength) {
+ Res.push_back("-fmessage-length");
+ Res.push_back(llvm::utostr(Opts.MessageLength));
+ }
+ if (!Opts.DumpBuildInformation.empty()) {
+ Res.push_back("-dump-build-information");
+ Res.push_back(Opts.DumpBuildInformation);
+ }
+ for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i)
+ Res.push_back("-W" + Opts.Warnings[i]);
+}
+
+static const char *getInputKindName(FrontendOptions::InputKind Kind) {
+ switch (Kind) {
+ case FrontendOptions::IK_None: break;
+ case FrontendOptions::IK_AST: return "ast";
+ case FrontendOptions::IK_Asm: return "assembler-with-cpp";
+ case FrontendOptions::IK_C: return "c";
+ case FrontendOptions::IK_CXX: return "c++";
+ case FrontendOptions::IK_ObjC: return "objective-c";
+ case FrontendOptions::IK_ObjCXX: return "objective-c++";
+ case FrontendOptions::IK_OpenCL: return "cl";
+ case FrontendOptions::IK_PreprocessedC: return "cpp-output";
+ case FrontendOptions::IK_PreprocessedCXX: return "c++-cpp-output";
+ case FrontendOptions::IK_PreprocessedObjC: return "objective-c-cpp-output";
+ case FrontendOptions::IK_PreprocessedObjCXX: return "objective-c++-cpp-output";
+ }
+
+ llvm::llvm_unreachable("Unexpected language kind!");
+ return 0;
+}
+
+static const char *getActionName(frontend::ActionKind Kind) {
+ switch (Kind) {
+ case frontend::PluginAction:
+ case frontend::InheritanceView:
+ llvm::llvm_unreachable("Invalid kind!");
+
+ case frontend::ASTDump: return "-ast-dump";
+ case frontend::ASTPrint: return "-ast-print";
+ case frontend::ASTPrintXML: return "-ast-print-xml";
+ case frontend::ASTView: return "-ast-view";
+ case frontend::DumpRawTokens: return "-dump-raw-tokens";
+ case frontend::DumpRecordLayouts: return "-dump-record-layouts";
+ case frontend::DumpTokens: return "-dump-tokens";
+ case frontend::EmitAssembly: return "-S";
+ case frontend::EmitBC: return "-emit-llvm-bc";
+ case frontend::EmitHTML: return "-emit-html";
+ case frontend::EmitLLVM: return "-emit-llvm";
+ case frontend::EmitLLVMOnly: return "-emit-llvm-only";
+ case frontend::FixIt: return "-fixit";
+ case frontend::GeneratePCH: return "-emit-pch";
+ case frontend::GeneratePTH: return "-emit-pth";
+ case frontend::ParseNoop: return "-parse-noop";
+ case frontend::ParsePrintCallbacks: return "-parse-print-callbacks";
+ case frontend::ParseSyntaxOnly: return "-fsyntax-only";
+ case frontend::PrintDeclContext: return "-print-decl-contexts";
+ case frontend::PrintPreprocessedInput: return "-E";
+ case frontend::RewriteBlocks: return "-rewrite-blocks";
+ case frontend::RewriteMacros: return "-rewrite-macros";
+ case frontend::RewriteObjC: return "-rewrite-objc";
+ case frontend::RewriteTest: return "-rewrite-test";
+ case frontend::RunAnalysis: return "-analyze";
+ case frontend::RunPreprocessorOnly: return "-Eonly";
+ }
+
+ llvm::llvm_unreachable("Unexpected language kind!");
+ return 0;
+}
+
+static void FrontendOptsToArgs(const FrontendOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (!Opts.DebugCodeCompletionPrinter)
+ Res.push_back("-code-completion-debug-printer=0");
+ if (Opts.DisableFree)
+ Res.push_back("-disable-free");
+ if (Opts.EmptyInputOnly)
+ Res.push_back("-empty-input-only");
+ if (Opts.RelocatablePCH)
+ Res.push_back("-relocatable-pch");
+ if (Opts.ShowMacrosInCodeCompletion)
+ Res.push_back("-code-completion-macros");
+ if (Opts.ShowStats)
+ Res.push_back("-stats");
+ if (Opts.ShowTimers)
+ Res.push_back("-ftime-report");
+
+ bool NeedLang = false;
+ for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i)
+ if (FrontendOptions::getInputKindForExtension(Opts.Inputs[i].second) !=
+ Opts.Inputs[i].first)
+ NeedLang = true;
+ if (NeedLang) {
+ Res.push_back("-x");
+ Res.push_back(getInputKindName(Opts.Inputs[0].first));
+ }
+ for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) {
+ assert((!NeedLang || Opts.Inputs[i].first == Opts.Inputs[0].first) &&
+ "Unable to represent this input vector!");
+ Res.push_back(Opts.Inputs[i].second);
+ }
+
+ if (!Opts.OutputFile.empty()) {
+ Res.push_back("-o");
+ Res.push_back(Opts.OutputFile);
+ }
+ if (!Opts.ViewClassInheritance.empty()) {
+ Res.push_back("-cxx-inheritance-view");
+ Res.push_back(Opts.ViewClassInheritance);
+ }
+ for (unsigned i = 0, e = Opts.FixItLocations.size(); i != e; ++i) {
+ Res.push_back("-fixit-at");
+ Res.push_back(Opts.FixItLocations[i].FileName + ":" +
+ llvm::utostr(Opts.FixItLocations[i].Line) + ":" +
+ llvm::utostr(Opts.FixItLocations[i].Column));
+ }
+ if (!Opts.CodeCompletionAt.FileName.empty()) {
+ Res.push_back("-code-completion-at");
+ Res.push_back(Opts.CodeCompletionAt.FileName + ":" +
+ llvm::utostr(Opts.CodeCompletionAt.Line) + ":" +
+ llvm::utostr(Opts.CodeCompletionAt.Column));
+ }
+ if (Opts.ProgramAction != frontend::InheritanceView &&
+ Opts.ProgramAction != frontend::PluginAction)
+ Res.push_back(getActionName(Opts.ProgramAction));
+ if (!Opts.ActionName.empty()) {
+ Res.push_back("-plugin");
+ Res.push_back(Opts.ActionName);
+ }
+}
+
+static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (Opts.Sysroot.empty()) {
+ Res.push_back("-isysroot");
+ Res.push_back(Opts.Sysroot);
+ }
+
+ /// User specified include entries.
+ for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) {
+ const HeaderSearchOptions::Entry &E = Opts.UserEntries[i];
+ if (E.IsFramework && (E.Group != frontend::Angled || E.IsUserSupplied))
+ llvm::llvm_report_error("Invalid option set!");
+ if (E.IsUserSupplied) {
+ if (E.Group == frontend::After) {
+ Res.push_back("-idirafter");
+ } else if (E.Group == frontend::Quoted) {
+ Res.push_back("-iquoted");
+ } else if (E.Group == frontend::System) {
+ Res.push_back("-isystem");
+ } else {
+ assert(E.Group == frontend::Angled && "Invalid group!");
+ Res.push_back(E.IsFramework ? "-F" : "-I");
+ }
+ } else {
+ if (E.Group != frontend::Angled && E.Group != frontend::System)
+ llvm::llvm_report_error("Invalid option set!");
+ Res.push_back(E.Group == frontend::Angled ? "-iwithprefixbefore" :
+ "-iwithprefix");
+ }
+ Res.push_back(E.Path);
+ }
+
+ if (!Opts.EnvIncPath.empty()) {
+ // FIXME: Provide an option for this, and move env detection to driver.
+ llvm::llvm_report_error("Not yet implemented!");
+ }
+ if (!Opts.CEnvIncPath.empty()) {
+ // FIXME: Provide an option for this, and move env detection to driver.
+ llvm::llvm_report_error("Not yet implemented!");
+ }
+ if (!Opts.ObjCEnvIncPath.empty()) {
+ // FIXME: Provide an option for this, and move env detection to driver.
+ llvm::llvm_report_error("Not yet implemented!");
+ }
+ if (!Opts.CXXEnvIncPath.empty()) {
+ // FIXME: Provide an option for this, and move env detection to driver.
+ llvm::llvm_report_error("Not yet implemented!");
+ }
+ if (!Opts.ObjCXXEnvIncPath.empty()) {
+ // FIXME: Provide an option for this, and move env detection to driver.
+ llvm::llvm_report_error("Not yet implemented!");
+ }
+ if (!Opts.BuiltinIncludePath.empty()) {
+ // FIXME: Provide an option for this, and move to driver.
+ }
+ if (!Opts.UseStandardIncludes)
+ Res.push_back("-nostdinc");
+ if (Opts.Verbose)
+ Res.push_back("-v");
+}
+
+static void LangOptsToArgs(const LangOptions &Opts,
+ std::vector<std::string> &Res) {
+ LangOptions DefaultLangOpts;
+
+ // FIXME: Need to set -std to get all the implicit options.
+
+ // FIXME: We want to only pass options relative to the defaults, which
+ // requires constructing a target. :(
+ //
+ // It would be better to push the all target specific choices into the driver,
+ // so that everything below that was more uniform.
+
+ if (Opts.Trigraphs)
+ Res.push_back("-trigraphs");
+ // Implicit based on the input kind:
+ // AsmPreprocessor, CPlusPlus, ObjC1, ObjC2, OpenCL
+ // Implicit based on the input language standard:
+ // BCPLComment, C99, CPlusPlus0x, Digraphs, GNUInline, ImplicitInt, GNUMode
+ if (Opts.DollarIdents)
+ Res.push_back("-fdollars-in-identifiers");
+ if (Opts.Microsoft)
+ Res.push_back("-fms-extensions=1");
+ if (Opts.ObjCNonFragileABI)
+ Res.push_back("-fobjc-nonfragile-abi");
+ // NoInline is implicit.
+ if (!Opts.CXXOperatorNames)
+ Res.push_back("-fno-operator-names");
+ if (Opts.PascalStrings)
+ Res.push_back("-fpascal-strings");
+ if (Opts.WritableStrings)
+ Res.push_back("-fwritable-strings");
+ if (!Opts.LaxVectorConversions)
+ Res.push_back("-fno-lax-vector-conversions");
+ if (Opts.AltiVec)
+ Res.push_back("-faltivec");
+ Res.push_back("-fexceptions");
+ Res.push_back(Opts.Exceptions ? "1" : "0");
+ Res.push_back("-frtti");
+ Res.push_back(Opts.Rtti ? "1" : "0");
+ if (!Opts.NeXTRuntime)
+ Res.push_back("-fgnu-runtime");
+ if (Opts.Freestanding)
+ Res.push_back("-ffreestanding");
+ if (Opts.NoBuiltin)
+ Res.push_back("-fno-builtin");
+ if (Opts.ThreadsafeStatics)
+ llvm::llvm_report_error("FIXME: Not yet implemented!");
+ if (Opts.POSIXThreads)
+ Res.push_back("-pthread");
+ if (Opts.Blocks)
+ Res.push_back("-fblocks=1");
+ if (Opts.EmitAllDecls)
+ Res.push_back("-femit-all-decls");
+ if (!Opts.MathErrno)
+ Res.push_back("-fmath-errno=0");
+ if (Opts.OverflowChecking)
+ Res.push_back("-ftrapv");
+ if (Opts.HeinousExtensions)
+ Res.push_back("-fheinous-gnu-extensions");
+ // Optimize is implicit.
+ // OptimizeSize is implicit.
+ if (Opts.Static)
+ Res.push_back("-static-define");
+ if (Opts.PICLevel) {
+ Res.push_back("-pic-level");
+ Res.push_back(llvm::utostr(Opts.PICLevel));
+ }
+ if (Opts.ObjCGCBitmapPrint)
+ Res.push_back("-print-ivar-layout");
+ Res.push_back("-faccess-control");
+ Res.push_back(Opts.AccessControl ? "1" : "0");
+ Res.push_back("-fsigned-char");
+ Res.push_back(Opts.CharIsSigned ? "1" : "0");
+ Res.push_back("-fshort-wchar");
+ Res.push_back(Opts.ShortWChar ? "1" : "0");
+ if (!Opts.ElideConstructors)
+ Res.push_back("-fno-elide-constructors");
+ if (Opts.getGCMode() != LangOptions::NonGC) {
+ if (Opts.getGCMode() == LangOptions::HybridGC) {
+ Res.push_back("-fobjc-gc");
+ } else {
+ assert(Opts.getGCMode() == LangOptions::GCOnly && "Invalid GC mode!");
+ Res.push_back("-fobjc-gc-only");
+ }
+ }
+ if (Opts.getVisibilityMode() != LangOptions::Default) {
+ Res.push_back("-fvisibility");
+ if (Opts.getVisibilityMode() == LangOptions::Hidden) {
+ Res.push_back("default");
+ } else {
+ assert(Opts.getVisibilityMode() == LangOptions::Protected &&
+ "Invalid visibility!");
+ Res.push_back("protected");
+ }
+ }
+ if (Opts.getStackProtectorMode() != 0) {
+ Res.push_back("-stack-protector");
+ Res.push_back(llvm::utostr(Opts.getStackProtectorMode()));
+ }
+ if (Opts.getMainFileName()) {
+ Res.push_back("-main-file-name");
+ Res.push_back(Opts.getMainFileName());
+ }
+ if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth) {
+ Res.push_back("-ftemplate-depth");
+ Res.push_back(llvm::utostr(Opts.InstantiationDepth));
+ }
+ if (Opts.ObjCConstantStringClass) {
+ Res.push_back("-fconstant-string-class");
+ Res.push_back(Opts.ObjCConstantStringClass);
+ }
+}
+
+static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
+ std::vector<std::string> &Res) {
+ for (unsigned i = 0, e = Opts.Macros.size(); i != e; ++i)
+ Res.push_back((Opts.Macros[i].second ? "-U" : "-D") + Opts.Macros[i].first);
+ for (unsigned i = 0, e = Opts.Includes.size(); i != e; ++i) {
+ Res.push_back("-include");
+ Res.push_back(Opts.Includes[i]);
+ }
+ for (unsigned i = 0, e = Opts.MacroIncludes.size(); i != e; ++i) {
+ Res.push_back("-imacros");
+ Res.push_back(Opts.Includes[i]);
+ }
+ if (!Opts.UsePredefines)
+ Res.push_back("-undef");
+ if (!Opts.ImplicitPCHInclude.empty()) {
+ Res.push_back("-implicit-pch-include");
+ Res.push_back(Opts.ImplicitPCHInclude);
+ }
+ if (!Opts.ImplicitPTHInclude.empty()) {
+ Res.push_back("-implicit-pth-include");
+ Res.push_back(Opts.ImplicitPTHInclude);
+ }
+ if (!Opts.TokenCache.empty()) {
+ Res.push_back("-token-cache");
+ Res.push_back(Opts.TokenCache);
+ }
+}
+
+static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (!Opts.ShowCPP && !Opts.ShowMacros)
+ llvm::llvm_report_error("Invalid option combination!");
+
+ if (Opts.ShowCPP && Opts.ShowMacros)
+ Res.push_back("-dD");
+ else if (!Opts.ShowCPP && Opts.ShowMacros)
+ Res.push_back("-dM");
+
+ if (!Opts.ShowLineMarkers)
+ Res.push_back("-P");
+ if (Opts.ShowComments)
+ Res.push_back("-C");
+ if (Opts.ShowMacroComments)
+ Res.push_back("-CC");
+}
+
+static void TargetOptsToArgs(const TargetOptions &Opts,
+ std::vector<std::string> &Res) {
+ Res.push_back("-triple");
+ Res.push_back(Opts.Triple);
+ if (!Opts.CPU.empty()) {
+ Res.push_back("-target-cpu");
+ Res.push_back(Opts.CPU);
+ }
+ if (!Opts.ABI.empty()) {
+ Res.push_back("-target-abi");
+ Res.push_back(Opts.ABI);
+ }
+ for (unsigned i = 0, e = Opts.Features.size(); i != e; ++i) {
+ Res.push_back("-target-feature");
+ Res.push_back(Opts.Features[i]);
+ }
+}
+
+void CompilerInvocation::toArgs(std::vector<std::string> &Res) {
+ AnalyzerOptsToArgs(getAnalyzerOpts(), Res);
+ CodeGenOptsToArgs(getCodeGenOpts(), Res);
+ DependencyOutputOptsToArgs(getDependencyOutputOpts(), Res);
+ DiagnosticOptsToArgs(getDiagnosticOpts(), Res);
+ FrontendOptsToArgs(getFrontendOpts(), Res);
+ HeaderSearchOptsToArgs(getHeaderSearchOpts(), Res);
+ LangOptsToArgs(getLangOpts(), Res);
+ PreprocessorOptsToArgs(getPreprocessorOpts(), Res);
+ PreprocessorOutputOptsToArgs(getPreprocessorOutputOpts(), Res);
+ TargetOptsToArgs(getTargetOpts(), Res);
+}
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index 81d1179..c7f9359 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -12,12 +12,14 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/Utils.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/PPCallbacks.h"
-#include "clang/Lex/DirectoryLookup.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/DependencyOutputOptions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Lex/DirectoryLookup.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
@@ -42,11 +44,10 @@ private:
public:
DependencyFileCallback(const Preprocessor *_PP,
llvm::raw_ostream *_OS,
- const std::vector<std::string> &_Targets,
- bool _IncludeSystemHeaders,
- bool _PhonyTarget)
- : PP(_PP), Targets(_Targets), OS(_OS),
- IncludeSystemHeaders(_IncludeSystemHeaders), PhonyTarget(_PhonyTarget) {}
+ const DependencyOutputOptions &Opts)
+ : PP(_PP), Targets(Opts.Targets), OS(_OS),
+ IncludeSystemHeaders(Opts.IncludeSystemHeaders),
+ PhonyTarget(Opts.UsePhonyTargets) {}
~DependencyFileCallback() {
OutputDependencyFile();
@@ -59,18 +60,23 @@ public:
};
}
+void clang::AttachDependencyFileGen(Preprocessor &PP,
+ const DependencyOutputOptions &Opts) {
+ if (Opts.Targets.empty()) {
+ PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT);
+ return;
+ }
+ std::string Err;
+ llvm::raw_ostream *OS(new llvm::raw_fd_ostream(Opts.OutputFile.c_str(), Err));
+ if (!Err.empty()) {
+ PP.getDiagnostics().Report(diag::err_fe_error_opening)
+ << Opts.OutputFile << Err;
+ return;
+ }
-void clang::AttachDependencyFileGen(Preprocessor *PP, llvm::raw_ostream *OS,
- std::vector<std::string> &Targets,
- bool IncludeSystemHeaders,
- bool PhonyTarget) {
- assert(!Targets.empty() && "Target required for dependency generation");
-
- DependencyFileCallback *PPDep =
- new DependencyFileCallback(PP, OS, Targets, IncludeSystemHeaders,
- PhonyTarget);
- PP->setPPCallbacks(PPDep);
+ assert(!PP.getPPCallbacks() && "Preprocessor callbacks already registered!");
+ PP.setPPCallbacks(new DependencyFileCallback(&PP, OS, Opts));
}
/// FileMatchesDepCriteria - Determine whether the given Filename should be
diff --git a/lib/Frontend/DocumentXML.cpp b/lib/Frontend/DocumentXML.cpp
index d92d4cb..0263c30 100644
--- a/lib/Frontend/DocumentXML.cpp
+++ b/lib/Frontend/DocumentXML.cpp
@@ -135,7 +135,7 @@ void DocumentXML::finalize() {
for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end();
i != e; ++i) {
- if (i->first.hasQualifiers()) {
+ if (i->first.hasLocalQualifiers()) {
writeTypeToXML(i->first);
addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
toParent();
@@ -205,7 +205,7 @@ void DocumentXML::addTypeRecursively(const QualType& pType)
{
addTypeRecursively(pType.getTypePtr());
// beautifier: a non-qualified type shall be transparent
- if (!pType.hasQualifiers())
+ if (!pType.hasLocalQualifiers())
{
Types[pType] = BasicTypes[pType.getTypePtr()];
}
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
new file mode 100644
index 0000000..ff63a0d
--- /dev/null
+++ b/lib/Frontend/FrontendAction.cpp
@@ -0,0 +1,225 @@
+//===--- FrontendAction.cpp -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Sema/ParseAST.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+FrontendAction::FrontendAction() : Instance(0), CurrentTimer(0) {}
+
+FrontendAction::~FrontendAction() {}
+
+void FrontendAction::setCurrentFile(llvm::StringRef Value, ASTUnit *AST) {
+ CurrentFile = Value;
+ CurrentASTUnit.reset(AST);
+}
+
+bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
+ llvm::StringRef Filename,
+ bool IsAST) {
+ assert(!Instance && "Already processing a source file!");
+ assert(!Filename.empty() && "Unexpected empty filename!");
+ setCurrentFile(Filename);
+ setCompilerInstance(&CI);
+
+ // AST files follow a very different path, since they share objects via the
+ // AST unit.
+ if (IsAST) {
+ assert(!usesPreprocessorOnly() &&
+ "Attempt to pass AST file to preprocessor only action!");
+ assert(hasASTSupport() && "This action does not have AST support!");
+
+ std::string Error;
+ ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, &Error);
+ if (!AST) {
+ CI.getDiagnostics().Report(diag::err_fe_invalid_ast_file) << Error;
+ goto failure;
+ }
+
+ setCurrentFile(Filename, AST);
+
+ // Set the shared objects, these are reset when we finish processing the
+ // file, otherwise the CompilerInstance will happily destroy them.
+ CI.setFileManager(&AST->getFileManager());
+ CI.setSourceManager(&AST->getSourceManager());
+ CI.setPreprocessor(&AST->getPreprocessor());
+ CI.setASTContext(&AST->getASTContext());
+
+ // Initialize the action.
+ if (!BeginSourceFileAction(CI, Filename))
+ goto failure;
+
+ /// Create the AST consumer.
+ CI.setASTConsumer(CreateASTConsumer(CI, Filename));
+ if (!CI.hasASTConsumer())
+ goto failure;
+
+ return true;
+ }
+
+ // Inform the diagnostic client we are processing a source file.
+ CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
+ &CI.getPreprocessor());
+
+ // Initialize the action.
+ if (!BeginSourceFileAction(CI, Filename))
+ goto failure;
+
+ /// Create the AST context and consumer unless this is a preprocessor only
+ /// action.
+ if (!usesPreprocessorOnly()) {
+ CI.createASTContext();
+ CI.setASTConsumer(CreateASTConsumer(CI, Filename));
+ if (!CI.hasASTConsumer())
+ goto failure;
+
+ /// Use PCH?
+ if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
+ assert(hasPCHSupport() && "This action does not have PCH support!");
+ CI.createPCHExternalASTSource(
+ CI.getPreprocessorOpts().ImplicitPCHInclude);
+ if (!CI.getASTContext().getExternalSource())
+ goto failure;
+ }
+ }
+
+ // Initialize builtin info as long as we aren't using an external AST
+ // source.
+ if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
+ Preprocessor &PP = CI.getPreprocessor();
+ PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
+ PP.getLangOptions().NoBuiltin);
+ }
+
+ return true;
+
+ // If we failed, reset state since the client will not end up calling the
+ // matching EndSourceFile().
+ failure:
+ if (isCurrentFileAST()) {
+ CI.takeASTContext();
+ CI.takePreprocessor();
+ CI.takeSourceManager();
+ CI.takeFileManager();
+ }
+
+ CI.getDiagnosticClient().EndSourceFile();
+ setCurrentFile("");
+ setCompilerInstance(0);
+ return false;
+}
+
+void FrontendAction::Execute() {
+ CompilerInstance &CI = getCompilerInstance();
+
+ // Initialize the main file entry. This needs to be delayed until after PCH
+ // has loaded.
+ if (isCurrentFileAST()) {
+ // Set the main file ID to an empty file.
+ //
+ // FIXME: We probably shouldn't need this, but for now this is the
+ // simplest way to reuse the logic in ParseAST.
+ const char *EmptyStr = "";
+ llvm::MemoryBuffer *SB =
+ llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<dummy input>");
+ CI.getSourceManager().createMainFileIDForMemBuffer(SB);
+ } else {
+ if (!CI.InitializeSourceManager(getCurrentFile()))
+ return;
+ }
+
+ llvm::TimeRegion Timer(CurrentTimer);
+ ExecuteAction();
+}
+
+void FrontendAction::EndSourceFile() {
+ CompilerInstance &CI = getCompilerInstance();
+
+ // Finalize the action.
+ EndSourceFileAction();
+
+ // Release the consumer and the AST, in that order since the consumer may
+ // perform actions in its destructor which require the context.
+ //
+ // FIXME: There is more per-file stuff we could just drop here?
+ if (CI.getFrontendOpts().DisableFree) {
+ CI.takeASTConsumer();
+ if (!isCurrentFileAST())
+ CI.takeASTContext();
+ } else {
+ CI.setASTConsumer(0);
+ if (!isCurrentFileAST())
+ CI.setASTContext(0);
+ }
+
+ if (CI.getFrontendOpts().ShowStats) {
+ llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
+ CI.getPreprocessor().PrintStats();
+ CI.getPreprocessor().getIdentifierTable().PrintStats();
+ CI.getPreprocessor().getHeaderSearchInfo().PrintStats();
+ CI.getSourceManager().PrintStats();
+ llvm::errs() << "\n";
+ }
+
+ // Cleanup the output streams, and erase the output files if we encountered
+ // an error.
+ CI.ClearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors());
+
+ // Inform the diagnostic client we are done with this source file.
+ CI.getDiagnosticClient().EndSourceFile();
+
+ if (isCurrentFileAST()) {
+ CI.takeASTContext();
+ CI.takePreprocessor();
+ CI.takeSourceManager();
+ CI.takeFileManager();
+ }
+
+ setCompilerInstance(0);
+ setCurrentFile("");
+}
+
+//===----------------------------------------------------------------------===//
+// Utility Actions
+//===----------------------------------------------------------------------===//
+
+void ASTFrontendAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+
+ // FIXME: Move the truncation aspect of this into Sema, we delayed this till
+ // here so the source manager would be initialized.
+ if (hasCodeCompletionSupport() &&
+ !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
+ CI.createCodeCompletionConsumer();
+
+ // Use a code completion consumer?
+ CodeCompleteConsumer *CompletionConsumer = 0;
+ if (CI.hasCodeCompletionConsumer())
+ CompletionConsumer = &CI.getCodeCompletionConsumer();
+
+ ParseAST(CI.getPreprocessor(), &CI.getASTConsumer(), CI.getASTContext(),
+ CI.getFrontendOpts().ShowStats,
+ usesCompleteTranslationUnit(), CompletionConsumer);
+}
+
+ASTConsumer *
+PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ llvm::llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
+}
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
new file mode 100644
index 0000000..7a7537b
--- /dev/null
+++ b/lib/Frontend/FrontendActions.cpp
@@ -0,0 +1,281 @@
+//===--- FrontendActions.cpp ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/AnalysisConsumer.h"
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FixItRewriter.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/Utils.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// AST Consumer Actions
+//===----------------------------------------------------------------------===//
+
+ASTConsumer *AnalysisAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateAnalysisConsumer(CI.getPreprocessor(),
+ CI.getFrontendOpts().OutputFile,
+ CI.getAnalyzerOpts());
+}
+
+ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateASTPrinter(CI.createDefaultOutputFile(false, InFile));
+}
+
+ASTConsumer *ASTPrintXMLAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateASTPrinterXML(CI.createDefaultOutputFile(false, InFile,
+ "xml"));
+}
+
+ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateASTDumper();
+}
+
+ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateASTViewer();
+}
+
+ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateDeclContextPrinter();
+}
+
+ASTConsumer *DumpRecordAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateRecordLayoutDumper();
+}
+
+ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot;
+ if (CI.getFrontendOpts().RelocatablePCH &&
+ Sysroot.empty()) {
+ CI.getDiagnostics().Report(diag::err_relocatable_without_without_isysroot);
+ return 0;
+ }
+
+ llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile);
+ if (CI.getFrontendOpts().RelocatablePCH)
+ return CreatePCHGenerator(CI.getPreprocessor(), OS, Sysroot.c_str());
+
+ return CreatePCHGenerator(CI.getPreprocessor(), OS);
+}
+
+ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateHTMLPrinter(CI.createDefaultOutputFile(false, InFile),
+ CI.getPreprocessor());
+}
+
+ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateInheritanceViewer(CI.getFrontendOpts().ViewClassInheritance);
+}
+
+FixItAction::FixItAction() {}
+FixItAction::~FixItAction() {}
+
+ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return new ASTConsumer();
+}
+
+/// AddFixItLocations - Add any individual user specified "fix-it" locations,
+/// and return true on success.
+static bool AddFixItLocations(CompilerInstance &CI,
+ FixItRewriter &FixItRewrite) {
+ const std::vector<ParsedSourceLocation> &Locs =
+ CI.getFrontendOpts().FixItLocations;
+ for (unsigned i = 0, e = Locs.size(); i != e; ++i) {
+ const FileEntry *File = CI.getFileManager().getFile(Locs[i].FileName);
+ if (!File) {
+ CI.getDiagnostics().Report(diag::err_fe_unable_to_find_fixit_file)
+ << Locs[i].FileName;
+ return false;
+ }
+
+ RequestedSourceLocation Requested;
+ Requested.File = File;
+ Requested.Line = Locs[i].Line;
+ Requested.Column = Locs[i].Column;
+ FixItRewrite.addFixItLocation(Requested);
+ }
+
+ return true;
+}
+
+bool FixItAction::BeginSourceFileAction(CompilerInstance &CI,
+ llvm::StringRef Filename) {
+ Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
+ CI.getLangOpts()));
+ if (!AddFixItLocations(CI, *Rewriter))
+ return false;
+
+ return true;
+}
+
+void FixItAction::EndSourceFileAction() {
+ const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
+ Rewriter->WriteFixedFile(getCurrentFile(), FEOpts.OutputFile);
+}
+
+ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateObjCRewriter(InFile,
+ CI.createDefaultOutputFile(true, InFile, "cpp"),
+ CI.getDiagnostics(), CI.getLangOpts(),
+ CI.getDiagnosticOpts().NoRewriteMacros);
+}
+
+ASTConsumer *RewriteBlocksAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateBlockRewriter(InFile, CI.getDiagnostics(), CI.getLangOpts());
+}
+
+ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return new ASTConsumer();
+}
+
+CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {}
+
+ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ BackendAction BA = static_cast<BackendAction>(Act);
+ llvm::OwningPtr<llvm::raw_ostream> OS;
+ if (BA == Backend_EmitAssembly)
+ OS.reset(CI.createDefaultOutputFile(false, InFile, "s"));
+ else if (BA == Backend_EmitLL)
+ OS.reset(CI.createDefaultOutputFile(false, InFile, "ll"));
+ else if (BA == Backend_EmitBC)
+ OS.reset(CI.createDefaultOutputFile(true, InFile, "bc"));
+
+ return CreateBackendConsumer(BA, CI.getDiagnostics(), CI.getLangOpts(),
+ CI.getCodeGenOpts(), CI.getTargetOpts(), InFile,
+ OS.take(), CI.getLLVMContext());
+}
+
+EmitAssemblyAction::EmitAssemblyAction()
+ : CodeGenAction(Backend_EmitAssembly) {}
+
+EmitBCAction::EmitBCAction() : CodeGenAction(Backend_EmitBC) {}
+
+EmitLLVMAction::EmitLLVMAction() : CodeGenAction(Backend_EmitLL) {}
+
+EmitLLVMOnlyAction::EmitLLVMOnlyAction() : CodeGenAction(Backend_EmitNothing) {}
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Actions
+//===----------------------------------------------------------------------===//
+
+void DumpRawTokensAction::ExecuteAction() {
+ Preprocessor &PP = getCompilerInstance().getPreprocessor();
+ SourceManager &SM = PP.getSourceManager();
+
+ // Start lexing the specified input file.
+ Lexer RawLex(SM.getMainFileID(), SM, PP.getLangOptions());
+ RawLex.SetKeepWhitespaceMode(true);
+
+ Token RawTok;
+ RawLex.LexFromRawLexer(RawTok);
+ while (RawTok.isNot(tok::eof)) {
+ PP.DumpToken(RawTok, true);
+ fprintf(stderr, "\n");
+ RawLex.LexFromRawLexer(RawTok);
+ }
+}
+
+void DumpTokensAction::ExecuteAction() {
+ Preprocessor &PP = getCompilerInstance().getPreprocessor();
+ // Start preprocessing the specified input file.
+ Token Tok;
+ PP.EnterMainSourceFile();
+ do {
+ PP.Lex(Tok);
+ PP.DumpToken(Tok, true);
+ fprintf(stderr, "\n");
+ } while (Tok.isNot(tok::eof));
+}
+
+void GeneratePTHAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ if (CI.getFrontendOpts().OutputFile.empty() ||
+ CI.getFrontendOpts().OutputFile == "-") {
+ // FIXME: Don't fail this way.
+ // FIXME: Verify that we can actually seek in the given file.
+ llvm::errs() << "ERROR: PTH requires an seekable file for output!\n";
+ ::exit(1);
+ }
+ llvm::raw_fd_ostream *OS =
+ CI.createDefaultOutputFile(true, getCurrentFile());
+ CacheTokens(CI.getPreprocessor(), OS);
+}
+
+void ParseOnlyAction::ExecuteAction() {
+ Preprocessor &PP = getCompilerInstance().getPreprocessor();
+ llvm::OwningPtr<Action> PA(new MinimalAction(PP));
+
+ Parser P(PP, *PA);
+ PP.EnterMainSourceFile();
+ P.ParseTranslationUnit();
+}
+
+void PreprocessOnlyAction::ExecuteAction() {
+ Preprocessor &PP = getCompilerInstance().getPreprocessor();
+
+ Token Tok;
+ // Start parsing the specified input file.
+ PP.EnterMainSourceFile();
+ do {
+ PP.Lex(Tok);
+ } while (Tok.isNot(tok::eof));
+}
+
+void PrintParseAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ Preprocessor &PP = getCompilerInstance().getPreprocessor();
+ llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
+ llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS));
+
+ Parser P(PP, *PA);
+ PP.EnterMainSourceFile();
+ P.ParseTranslationUnit();
+}
+
+void PrintPreprocessedAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
+ DoPrintPreprocessedInput(CI.getPreprocessor(), OS,
+ CI.getPreprocessorOutputOpts());
+}
+
+void RewriteMacrosAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
+ RewriteMacrosInInput(CI.getPreprocessor(), OS);
+}
+
+void RewriteTestAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
+ DoRewriteTest(CI.getPreprocessor(), OS);
+}
diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp
new file mode 100644
index 0000000..bd91638
--- /dev/null
+++ b/lib/Frontend/FrontendOptions.cpp
@@ -0,0 +1,31 @@
+//===--- FrontendOptions.cpp ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/FrontendOptions.h"
+#include "llvm/ADT/StringSwitch.h"
+using namespace clang;
+
+FrontendOptions::InputKind
+FrontendOptions::getInputKindForExtension(llvm::StringRef Extension) {
+ return llvm::StringSwitch<InputKind>(Extension)
+ .Case("ast", IK_AST)
+ .Case("c", IK_C)
+ .Cases("S", "s", IK_Asm)
+ .Case("i", IK_PreprocessedC)
+ .Case("ii", IK_PreprocessedCXX)
+ .Case("m", IK_ObjC)
+ .Case("mi", IK_PreprocessedObjC)
+ .Cases("mm", "M", IK_ObjCXX)
+ .Case("mii", IK_PreprocessedObjCXX)
+ .Case("C", IK_CXX)
+ .Cases("C", "cc", "cp", IK_CXX)
+ .Cases("cpp", "CPP", "c++", "cxx", "hpp", IK_CXX)
+ .Case("cl", IK_OpenCL)
+ .Default(IK_C);
+}
diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp
index 145d53f..3ba7abf 100644
--- a/lib/Frontend/HTMLDiagnostics.cpp
+++ b/lib/Frontend/HTMLDiagnostics.cpp
@@ -109,6 +109,8 @@ HTMLDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade)
ReportDiag(*D, FilesMade);
delete D;
}
+
+ BatchedDiags.clear();
}
void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index c0b4eba..d19ae98 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -11,12 +11,16 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/InitHeaderSearch.h"
-#include "clang/Lex/HeaderSearch.h"
+#include "clang/Frontend/Utils.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Frontend/HeaderSearchOptions.h"
+#include "clang/Lex/HeaderSearch.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
#include "llvm/Config/config.h"
@@ -26,6 +30,66 @@
#include <windows.h>
#endif
using namespace clang;
+using namespace clang::frontend;
+
+namespace {
+
+/// InitHeaderSearch - This class makes it easier to set the search paths of
+/// a HeaderSearch object. InitHeaderSearch stores several search path lists
+/// internally, which can be sent to a HeaderSearch object in one swoop.
+class InitHeaderSearch {
+ std::vector<DirectoryLookup> IncludeGroup[4];
+ HeaderSearch& Headers;
+ bool Verbose;
+ std::string isysroot;
+
+public:
+
+ InitHeaderSearch(HeaderSearch &HS,
+ bool verbose = false, const std::string &iSysroot = "")
+ : Headers(HS), Verbose(verbose), isysroot(iSysroot) {}
+
+ /// AddPath - Add the specified path to the specified group list.
+ void AddPath(const llvm::StringRef &Path, IncludeDirGroup Group,
+ bool isCXXAware, bool isUserSupplied,
+ bool isFramework, bool IgnoreSysRoot = false);
+
+ /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to suport a gnu
+ /// libstdc++.
+ void AddGnuCPlusPlusIncludePaths(const std::string &Base,
+ const char *ArchDir,
+ const char *Dir32,
+ const char *Dir64,
+ const llvm::Triple &triple);
+
+ /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to suport a MinGW
+ /// libstdc++.
+ void AddMinGWCPlusPlusIncludePaths(const std::string &Base,
+ const char *Arch,
+ const char *Version);
+
+ /// AddDelimitedPaths - Add a list of paths delimited by the system PATH
+ /// separator. The processing follows that of the CPATH variable for gcc.
+ void AddDelimitedPaths(const char *String);
+
+ // AddDefaultCIncludePaths - Add paths that should always be searched.
+ void AddDefaultCIncludePaths(const llvm::Triple &triple);
+
+ // AddDefaultCPlusPlusIncludePaths - Add paths that should be searched when
+ // compiling c++.
+ void AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple);
+
+ /// AddDefaultSystemIncludePaths - Adds the default system include paths so
+ /// that e.g. stdio.h is found.
+ void AddDefaultSystemIncludePaths(const LangOptions &Lang,
+ const llvm::Triple &triple);
+
+ /// Realize - Merges all search path lists into one list and send it to
+ /// HeaderSearch.
+ void Realize();
+};
+
+}
void InitHeaderSearch::AddPath(const llvm::StringRef &Path,
IncludeDirGroup Group, bool isCXXAware,
@@ -82,9 +146,8 @@ void InitHeaderSearch::AddPath(const llvm::StringRef &Path,
}
-void InitHeaderSearch::AddEnvVarPaths(const char *Name) {
- const char* at = getenv(Name);
- if (!at || *at == 0) // Empty string should not add '.' path.
+void InitHeaderSearch::AddDelimitedPaths(const char *at) {
+ if (*at == 0) // Empty string should not add '.' path.
return;
const char* delim = strchr(at, llvm::sys::PathSeparator);
@@ -103,27 +166,30 @@ void InitHeaderSearch::AddEnvVarPaths(const char *Name) {
}
void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(const std::string &Base,
+ const char *ArchDir,
const char *Dir32,
const char *Dir64,
const llvm::Triple &triple) {
+ // Add the common dirs
+ AddPath(Base, System, true, false, false);
+ AddPath(Base + "/backward", System, true, false, false);
+
+ // Add the multilib dirs
llvm::Triple::ArchType arch = triple.getArch();
bool is64bit = arch == llvm::Triple::ppc64 || arch == llvm::Triple::x86_64;
-
- AddPath(Base, System, true, false, false);
if (is64bit)
- AddPath(Base + "/" + Dir64, System, true, false, false);
+ AddPath(Base + "/" + ArchDir + "/" + Dir64, System, true, false, false);
else
- AddPath(Base + "/" + Dir32, System, true, false, false);
- AddPath(Base + "/backward", System, true, false, false);
+ AddPath(Base + "/" + ArchDir + "/" + Dir32, System, true, false, false);
}
void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(const std::string &Base,
const char *Arch,
const char *Version) {
- std::string localBase = Base + "/" + Arch + "/" + Version + "/include";
- AddPath(localBase, System, true, false, false);
- AddPath(localBase + "/c++", System, true, false, false);
- AddPath(localBase + "/c++/backward", System, true, false, false);
+ std::string localBase = Base + "/" + Arch + "/" + Version + "/include";
+ AddPath(localBase, System, true, false, false);
+ AddPath(localBase + "/c++", System, true, false, false);
+ AddPath(localBase + "/c++/backward", System, true, false, false);
}
// FIXME: This probably should goto to some platform utils place.
@@ -243,6 +309,16 @@ bool getVisualStudioDir(std::string &path) {
void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) {
// FIXME: temporary hack: hard-coded paths.
+ llvm::StringRef CIncludeDirs(C_INCLUDE_DIRS);
+ if (CIncludeDirs != "") {
+ llvm::SmallVector<llvm::StringRef, 5> dirs;
+ CIncludeDirs.split(dirs, ":");
+ for (llvm::SmallVectorImpl<llvm::StringRef>::iterator i = dirs.begin();
+ i != dirs.end();
+ ++i)
+ AddPath(*i, System, false, false, false);
+ return;
+ }
llvm::Triple::OSType os = triple.getOS();
switch (os) {
case llvm::Triple::Win32:
@@ -288,6 +364,17 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) {
void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
llvm::Triple::OSType os = triple.getOS();
+ llvm::StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT);
+ if (CxxIncludeRoot != "") {
+ llvm::StringRef CxxIncludeArch(CXX_INCLUDE_ARCH);
+ if (CxxIncludeArch == "")
+ AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, triple.str().c_str(),
+ CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, triple);
+ else
+ AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, CXX_INCLUDE_ARCH,
+ CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, triple);
+ return;
+ }
// FIXME: temporary hack: hard-coded paths.
switch (os) {
case llvm::Triple::Cygwin:
@@ -310,113 +397,77 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
break;
case llvm::Triple::Darwin:
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1",
- "i686-apple-darwin10",
- "i686-apple-darwin10/x86_64",
- triple);
+ "i686-apple-darwin10", "", "x86_64", triple);
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0",
- "i686-apple-darwin8",
- "i686-apple-darwin8",
- triple);
+ "i686-apple-darwin8", "", "", triple);
break;
case llvm::Triple::Linux:
// Ubuntu 7.10 - Gutsy Gibbon
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.3",
- "i486-linux-gnu",
- "i486-linux-gnu",
- triple);
+ "i486-linux-gnu", "", "", triple);
// Ubuntu 9.04
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.3",
- "x86_64-linux-gnu/32",
- "x86_64-linux-gnu",
- triple);
+ "x86_64-linux-gnu","32", "", triple);
+ // Ubuntu 9.10
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1",
+ "x86_64-linux-gnu", "32", "", triple);
// Fedora 8
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2",
- "i386-redhat-linux",
- "i386-redhat-linux",
- triple);
+ "i386-redhat-linux", "", "", triple);
// Fedora 9
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0",
- "i386-redhat-linux",
- "i386-redhat-linux",
- triple);
+ "i386-redhat-linux", "", "", triple);
// Fedora 10
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2",
- "i386-redhat-linux",
- "i386-redhat-linux",
- triple);
+ "i386-redhat-linux","", "", triple);
+
+ // Fedora 11
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1",
+ "i586-redhat-linux","", "", triple);
+
// openSUSE 11.1 32 bit
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
- "i586-suse-linux",
- "i586-suse-linux",
- triple);
+ "i586-suse-linux", "", "", triple);
// openSUSE 11.1 64 bit
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
- "x86_64-suse-linux/32",
- "x86_64-suse-linux",
- triple);
+ "x86_64-suse-linux", "32", "", triple);
// openSUSE 11.2
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
- "i586-suse-linux",
- "i586-suse-linux",
- triple);
+ "i586-suse-linux", "", "", triple);
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
- "x86_64-suse-linux",
- "x86_64-suse-linux",
- triple);
+ "x86_64-suse-linux", "", "", triple);
// Arch Linux 2008-06-24
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1",
- "i686-pc-linux-gnu",
- "i686-pc-linux-gnu",
- triple);
+ "i686-pc-linux-gnu", "", "", triple);
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1",
- "x86_64-unknown-linux-gnu",
- "x86_64-unknown-linux-gnu",
- triple);
+ "x86_64-unknown-linux-gnu", "", "", triple);
// Gentoo x86 2009.1 stable
AddGnuCPlusPlusIncludePaths(
- "/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4",
- "i686-pc-linux-gnu",
- "i686-pc-linux-gnu",
- triple);
+ "/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4",
+ "i686-pc-linux-gnu", "", "", triple);
// Gentoo x86 2009.0 stable
AddGnuCPlusPlusIncludePaths(
- "/usr/lib/gcc/i686-pc-linux-gnu/4.3.2/include/g++-v4",
- "i686-pc-linux-gnu",
- "i686-pc-linux-gnu",
- triple);
+ "/usr/lib/gcc/i686-pc-linux-gnu/4.3.2/include/g++-v4",
+ "i686-pc-linux-gnu", "", "", triple);
// Gentoo x86 2008.0 stable
AddGnuCPlusPlusIncludePaths(
- "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4",
- "i686-pc-linux-gnu",
- "i686-pc-linux-gnu",
- triple);
+ "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4",
+ "i686-pc-linux-gnu", "", "", triple);
// Ubuntu 8.10
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
- "i486-pc-linux-gnu",
- "i486-pc-linux-gnu",
- triple);
+ "i486-pc-linux-gnu", "", "", triple);
// Ubuntu 9.04
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
- "i486-linux-gnu",
- "i486-linux-gnu",
- triple);
+ "i486-linux-gnu","", "", triple);
// Gentoo amd64 stable
AddGnuCPlusPlusIncludePaths(
"/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4",
- "i686-pc-linux-gnu",
- "i686-pc-linux-gnu",
- triple);
+ "i686-pc-linux-gnu", "", "", triple);
// Exherbo (2009-10-26)
- AddGnuCPlusPlusIncludePaths(
- "/usr/include/c++/4.4.2",
- "x86_64-pc-linux-gnu/32",
- "x86_64-pc-linux-gnu",
- triple);
- AddGnuCPlusPlusIncludePaths(
- "/usr/include/c++/4.4.2",
- "i686-pc-linux-gnu",
- "i686-pc-linux-gnu",
- triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
+ "x86_64-pc-linux-gnu", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
+ "i686-pc-linux-gnu", "", "", triple);
break;
case llvm::Triple::FreeBSD:
// DragonFly
@@ -429,44 +480,27 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
case llvm::Triple::AuroraUX:
// AuroraUX
AddGnuCPlusPlusIncludePaths("/opt/gcc4/include/c++/4.2.4",
- "i386-pc-solaris2.11",
- "i386-pc-solaris2.11",
- triple);
+ "i386-pc-solaris2.11", "", "", triple);
break;
default:
break;
}
}
-void InitHeaderSearch::AddDefaultFrameworkIncludePaths(const llvm::Triple &triple) {
- llvm::Triple::OSType os = triple.getOS();
- if (os != llvm::Triple::Darwin)
- return;
- AddPath("/System/Library/Frameworks", System, true, false, true);
- AddPath("/Library/Frameworks", System, true, false, true);
-}
-
void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang,
const llvm::Triple &triple) {
AddDefaultCIncludePaths(triple);
- AddDefaultFrameworkIncludePaths(triple);
+
+ // Add the default framework include paths on Darwin.
+ if (triple.getOS() == llvm::Triple::Darwin) {
+ AddPath("/System/Library/Frameworks", System, true, false, true);
+ AddPath("/Library/Frameworks", System, true, false, true);
+ }
+
if (Lang.CPlusPlus)
AddDefaultCPlusPlusIncludePaths(triple);
}
-void InitHeaderSearch::AddDefaultEnvVarPaths(const LangOptions &Lang) {
- AddEnvVarPaths("CPATH");
- if (Lang.CPlusPlus && Lang.ObjC1)
- AddEnvVarPaths("OBJCPLUS_INCLUDE_PATH");
- else if (Lang.CPlusPlus)
- AddEnvVarPaths("CPLUS_INCLUDE_PATH");
- else if (Lang.ObjC1)
- AddEnvVarPaths("OBJC_INCLUDE_PATH");
- else
- AddEnvVarPaths("C_INCLUDE_PATH");
-}
-
-
/// RemoveDuplicates - If there are duplicate directory entries in the specified
/// search list, remove the later (dead) ones.
static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
@@ -591,3 +625,40 @@ void InitHeaderSearch::Realize() {
fprintf(stderr, "End of search list.\n");
}
}
+
+void clang::ApplyHeaderSearchOptions(HeaderSearch &HS,
+ const HeaderSearchOptions &HSOpts,
+ const LangOptions &Lang,
+ const llvm::Triple &Triple) {
+ InitHeaderSearch Init(HS, HSOpts.Verbose, HSOpts.Sysroot);
+
+ // Add the user defined entries.
+ for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) {
+ const HeaderSearchOptions::Entry &E = HSOpts.UserEntries[i];
+ Init.AddPath(E.Path, E.Group, false, E.IsUserSupplied, E.IsFramework,
+ false);
+ }
+
+ // Add entries from CPATH and friends.
+ Init.AddDelimitedPaths(HSOpts.EnvIncPath.c_str());
+ if (Lang.CPlusPlus && Lang.ObjC1)
+ Init.AddDelimitedPaths(HSOpts.ObjCXXEnvIncPath.c_str());
+ else if (Lang.CPlusPlus)
+ Init.AddDelimitedPaths(HSOpts.CXXEnvIncPath.c_str());
+ else if (Lang.ObjC1)
+ Init.AddDelimitedPaths(HSOpts.ObjCEnvIncPath.c_str());
+ else
+ Init.AddDelimitedPaths(HSOpts.CEnvIncPath.c_str());
+
+ if (!HSOpts.BuiltinIncludePath.empty()) {
+ // Ignore the sys root, we *always* look for clang headers relative to
+ // supplied path.
+ Init.AddPath(HSOpts.BuiltinIncludePath, System,
+ false, false, false, /*IgnoreSysRoot=*/ true);
+ }
+
+ if (HSOpts.UseStandardIncludes)
+ Init.AddDefaultSystemIncludePaths(Lang, Triple);
+
+ Init.Realize();
+}
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 7139e55..4ee286d 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -11,8 +11,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/InitPreprocessor.h"
+#include "clang/Frontend/Utils.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Frontend/PreprocessorOptions.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/STLExtras.h"
@@ -60,9 +61,7 @@ static void UndefineBuiltinMacro(std::vector<char> &Buf, const char *Macro) {
Buf.push_back('\n');
}
-/// Add the quoted name of an implicit include file.
-static void AddQuotedIncludePath(std::vector<char> &Buf,
- const std::string &File) {
+std::string clang::NormalizeDashIncludePath(llvm::StringRef File) {
// Implicit include paths should be resolved relative to the current
// working directory first, and then use the regular header search
// mechanism. The proper way to handle this is to have the
@@ -75,9 +74,16 @@ static void AddQuotedIncludePath(std::vector<char> &Buf,
if (!Path.exists())
Path = File;
+ return Lexer::Stringify(Path.str());
+}
+
+/// Add the quoted name of an implicit include file.
+static void AddQuotedIncludePath(std::vector<char> &Buf,
+ const std::string &File) {
+
// Escape double quotes etc.
Buf.push_back('"');
- std::string EscapedFile = Lexer::Stringify(Path.str());
+ std::string EscapedFile = NormalizeDashIncludePath(File);
Buf.insert(Buf.end(), EscapedFile.begin(), EscapedFile.end());
Buf.push_back('"');
}
@@ -216,6 +222,14 @@ static void DefineTypeSize(const char *MacroName, unsigned TypeWidth,
DefineBuiltinMacro(Buf, MacroBuf);
}
+/// DefineTypeSize - An overloaded helper that uses TargetInfo to determine
+/// the width, suffix, and signedness of the given type
+static void DefineTypeSize(const char *MacroName, TargetInfo::IntType Ty,
+ const TargetInfo &TI, std::vector<char> &Buf) {
+ DefineTypeSize(MacroName, TI.getTypeWidth(Ty), TI.getTypeConstantSuffix(Ty),
+ TI.isTypeSigned(Ty), Buf);
+}
+
static void DefineType(const char *MacroName, TargetInfo::IntType Ty,
std::vector<char> &Buf) {
char MacroBuf[60];
@@ -223,6 +237,20 @@ static void DefineType(const char *MacroName, TargetInfo::IntType Ty,
DefineBuiltinMacro(Buf, MacroBuf);
}
+static void DefineExactWidthIntType(TargetInfo::IntType Ty,
+ const TargetInfo &TI, std::vector<char> &Buf) {
+ char MacroBuf[60];
+ int TypeWidth = TI.getTypeWidth(Ty);
+ sprintf(MacroBuf, "__INT%d_TYPE__", TypeWidth);
+ DefineType(MacroBuf, Ty, Buf);
+
+
+ const char *ConstSuffix = TargetInfo::getTypeConstantSuffix(Ty);
+ if (strlen(ConstSuffix) > 0) {
+ sprintf(MacroBuf, "__INT%d_C_SUFFIX__=%s", TypeWidth, ConstSuffix);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ }
+}
static void InitializePredefinedMacros(const TargetInfo &TI,
const LangOptions &LangOpts,
@@ -346,14 +374,12 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineBuiltinMacro(Buf, "__CHAR_BIT__=8");
DefineTypeSize("__SCHAR_MAX__", TI.getCharWidth(), "", true, Buf);
- DefineTypeSize("__SHRT_MAX__", TI.getShortWidth(), "", true, Buf);
- DefineTypeSize("__INT_MAX__", TI.getIntWidth(), "", true, Buf);
- DefineTypeSize("__LONG_MAX__", TI.getLongWidth(), "L", true, Buf);
- DefineTypeSize("__LONG_LONG_MAX__", TI.getLongLongWidth(), "LL", true, Buf);
- DefineTypeSize("__WCHAR_MAX__", TI.getWCharWidth(), "", true, Buf);
- TargetInfo::IntType IntMaxType = TI.getIntMaxType();
- DefineTypeSize("__INTMAX_MAX__", TI.getTypeWidth(IntMaxType),
- TI.getTypeConstantSuffix(IntMaxType), true, Buf);
+ DefineTypeSize("__SHRT_MAX__", TargetInfo::SignedShort, TI, Buf);
+ DefineTypeSize("__INT_MAX__", TargetInfo::SignedInt, TI, Buf);
+ DefineTypeSize("__LONG_MAX__", TargetInfo::SignedLong, TI, Buf);
+ DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Buf);
+ DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Buf);
+ DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Buf);
DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Buf);
DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Buf);
@@ -374,23 +400,22 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (!LangOpts.CharIsSigned)
DefineBuiltinMacro(Buf, "__CHAR_UNSIGNED__");
- // Define fixed-sized integer types for stdint.h
- assert(TI.getCharWidth() == 8 && "unsupported target types");
- assert(TI.getShortWidth() == 16 && "unsupported target types");
- DefineBuiltinMacro(Buf, "__INT8_TYPE__=char");
- DefineBuiltinMacro(Buf, "__INT16_TYPE__=short");
-
- if (TI.getIntWidth() == 32)
- DefineBuiltinMacro(Buf, "__INT32_TYPE__=int");
- else {
- assert(TI.getLongLongWidth() == 32 && "unsupported target types");
- DefineBuiltinMacro(Buf, "__INT32_TYPE__=long long");
- }
-
- // 16-bit targets doesn't necessarily have a 64-bit type.
- if (TI.getLongLongWidth() == 64)
- DefineType("__INT64_TYPE__", TI.getInt64Type(), Buf);
+ // Define exact-width integer types for stdint.h
+ sprintf(MacroBuf, "__INT%d_TYPE__=char", TI.getCharWidth());
+ DefineBuiltinMacro(Buf, MacroBuf);
+ if (TI.getShortWidth() > TI.getCharWidth())
+ DefineExactWidthIntType(TargetInfo::SignedShort, TI, Buf);
+
+ if (TI.getIntWidth() > TI.getShortWidth())
+ DefineExactWidthIntType(TargetInfo::SignedInt, TI, Buf);
+
+ if (TI.getLongWidth() > TI.getIntWidth())
+ DefineExactWidthIntType(TargetInfo::SignedLong, TI, Buf);
+
+ if (TI.getLongLongWidth() > TI.getLongWidth())
+ DefineExactWidthIntType(TargetInfo::SignedLongLong, TI, Buf);
+
// Add __builtin_va_list typedef.
{
const char *VAList = TI.getVAListDeclaration();
@@ -443,7 +468,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
/// environment ready to process a single file. This returns true on error.
///
void clang::InitializePreprocessor(Preprocessor &PP,
- const PreprocessorInitOptions &InitOpts) {
+ const PreprocessorOptions &InitOpts,
+ const HeaderSearchOptions &HSOpts) {
std::vector<char> PredefineBuffer;
const char *LineDirective = "# 1 \"<built-in>\" 3\n";
@@ -451,7 +477,7 @@ void clang::InitializePreprocessor(Preprocessor &PP,
LineDirective, LineDirective+strlen(LineDirective));
// Install things like __POWERPC__, __GNUC__, etc into the macro table.
- if (InitOpts.getUsePredefines())
+ if (InitOpts.UsePredefines)
InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(),
PredefineBuffer);
@@ -462,30 +488,33 @@ void clang::InitializePreprocessor(Preprocessor &PP,
LineDirective, LineDirective+strlen(LineDirective));
// Process #define's and #undef's in the order they are given.
- for (PreprocessorInitOptions::macro_iterator I = InitOpts.macro_begin(),
- E = InitOpts.macro_end(); I != E; ++I) {
- if (I->second) // isUndef
- UndefineBuiltinMacro(PredefineBuffer, I->first.c_str());
+ for (unsigned i = 0, e = InitOpts.Macros.size(); i != e; ++i) {
+ if (InitOpts.Macros[i].second) // isUndef
+ UndefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str());
else
- DefineBuiltinMacro(PredefineBuffer, I->first.c_str());
+ DefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str());
}
// If -imacros are specified, include them now. These are processed before
// any -include directives.
- for (PreprocessorInitOptions::imacro_iterator I = InitOpts.imacro_begin(),
- E = InitOpts.imacro_end(); I != E; ++I)
- AddImplicitIncludeMacros(PredefineBuffer, *I);
+ for (unsigned i = 0, e = InitOpts.MacroIncludes.size(); i != e; ++i)
+ AddImplicitIncludeMacros(PredefineBuffer, InitOpts.MacroIncludes[i]);
// Process -include directives.
- for (PreprocessorInitOptions::include_iterator I = InitOpts.include_begin(),
- E = InitOpts.include_end(); I != E; ++I) {
- if (I->second) // isPTH
- AddImplicitIncludePTH(PredefineBuffer, PP, I->first);
+ for (unsigned i = 0, e = InitOpts.Includes.size(); i != e; ++i) {
+ const std::string &Path = InitOpts.Includes[i];
+ if (Path == InitOpts.ImplicitPTHInclude)
+ AddImplicitIncludePTH(PredefineBuffer, PP, Path);
else
- AddImplicitInclude(PredefineBuffer, I->first);
+ AddImplicitInclude(PredefineBuffer, Path);
}
// Null terminate PredefinedBuffer and add it.
PredefineBuffer.push_back(0);
PP.setPredefines(&PredefineBuffer[0]);
+
+ // Initialize the header search object.
+ ApplyHeaderSearchOptions(PP.getHeaderSearchInfo(), HSOpts,
+ PP.getLangOptions(),
+ PP.getTargetInfo().getTriple());
}
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 26f426ba..ca7aa32 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -13,6 +13,7 @@
#include "clang/Frontend/PCHReader.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/Utils.h"
#include "../Sema/Sema.h" // FIXME: move Sema headers elsewhere
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -104,6 +105,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
PARSE_LANGOPT_IMPORTANT(NoInline, diag::warn_pch_no_inline);
PARSE_LANGOPT_IMPORTANT(AccessControl, diag::warn_pch_access_control);
PARSE_LANGOPT_IMPORTANT(CharIsSigned, diag::warn_pch_char_signed);
+ PARSE_LANGOPT_IMPORTANT(ShortWChar, diag::warn_pch_short_wchar);
if ((PPLangOpts.getGCMode() != 0) != (LangOpts.getGCMode() != 0)) {
Reader.Diag(diag::warn_pch_gc_mode)
<< LangOpts.getGCMode() << PPLangOpts.getGCMode();
@@ -121,83 +123,56 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
return false;
}
-bool PCHValidator::ReadTargetTriple(const std::string &Triple) {
- if (Triple != PP.getTargetInfo().getTriple().getTriple()) {
- Reader.Diag(diag::warn_pch_target_triple)
- << Triple << PP.getTargetInfo().getTriple().getTriple();
- return true;
- }
- return false;
-}
-
-/// \brief Split the given string into a vector of lines, eliminating
-/// any empty lines in the process.
-///
-/// \param Str the string to split.
-/// \param Len the length of Str.
-/// \param KeepEmptyLines true if empty lines should be included
-/// \returns a vector of lines, with the line endings removed
-static std::vector<std::string> splitLines(const char *Str, unsigned Len,
- bool KeepEmptyLines = false) {
- std::vector<std::string> Lines;
- for (unsigned LineStart = 0; LineStart < Len; ++LineStart) {
- unsigned LineEnd = LineStart;
- while (LineEnd < Len && Str[LineEnd] != '\n')
- ++LineEnd;
- if (LineStart != LineEnd || KeepEmptyLines)
- Lines.push_back(std::string(&Str[LineStart], &Str[LineEnd]));
- LineStart = LineEnd;
- }
- return Lines;
-}
-
-/// \brief Determine whether the string Haystack starts with the
-/// substring Needle.
-static bool startsWith(const std::string &Haystack, const char *Needle) {
- for (unsigned I = 0, N = Haystack.size(); Needle[I] != 0; ++I) {
- if (I == N)
- return false;
- if (Haystack[I] != Needle[I])
- return false;
- }
+bool PCHValidator::ReadTargetTriple(llvm::StringRef Triple) {
+ if (Triple == PP.getTargetInfo().getTriple().str())
+ return false;
+ Reader.Diag(diag::warn_pch_target_triple)
+ << Triple << PP.getTargetInfo().getTriple().str();
return true;
}
-/// \brief Determine whether the string Haystack starts with the
-/// substring Needle.
-static inline bool startsWith(const std::string &Haystack,
- const std::string &Needle) {
- return startsWith(Haystack, Needle.c_str());
-}
-
-bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef,
- unsigned PCHPredefLen,
+bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef,
FileID PCHBufferID,
+ llvm::StringRef OriginalFileName,
std::string &SuggestedPredefines) {
- const char *Predef = PP.getPredefines().c_str();
- unsigned PredefLen = PP.getPredefines().size();
-
- // If the two predefines buffers compare equal, we're done!
- if (PredefLen == PCHPredefLen &&
- strncmp(Predef, PCHPredef, PCHPredefLen) == 0)
+ // We are in the context of an implicit include, so the predefines buffer will
+ // have a #include entry for the PCH file itself (as normalized by the
+ // preprocessor initialization). Find it and skip over it in the checking
+ // below.
+ llvm::SmallString<256> PCHInclude;
+ PCHInclude += "#include \"";
+ PCHInclude += NormalizeDashIncludePath(OriginalFileName);
+ PCHInclude += "\"\n";
+ std::pair<llvm::StringRef,llvm::StringRef> Split =
+ llvm::StringRef(PP.getPredefines()).split(PCHInclude.str());
+ llvm::StringRef Left = Split.first, Right = Split.second;
+ assert(Left != PP.getPredefines() && "Missing PCH include entry!");
+
+ // If the predefines is equal to the joined left and right halves, we're done!
+ if (Left.size() + Right.size() == PCHPredef.size() &&
+ PCHPredef.startswith(Left) && PCHPredef.endswith(Right))
return false;
SourceManager &SourceMgr = PP.getSourceManager();
- // The predefines buffers are different. Determine what the
- // differences are, and whether they require us to reject the PCH
- // file.
- std::vector<std::string> CmdLineLines = splitLines(Predef, PredefLen);
- std::vector<std::string> PCHLines = splitLines(PCHPredef, PCHPredefLen);
+ // The predefines buffers are different. Determine what the differences are,
+ // and whether they require us to reject the PCH file.
+ llvm::SmallVector<llvm::StringRef, 8> PCHLines;
+ PCHPredef.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+
+ llvm::SmallVector<llvm::StringRef, 8> CmdLineLines;
+ Left.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ Right.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
- // Sort both sets of predefined buffer lines, since
+ // Sort both sets of predefined buffer lines, since we allow some extra
+ // definitions and they may appear at any point in the output.
std::sort(CmdLineLines.begin(), CmdLineLines.end());
std::sort(PCHLines.begin(), PCHLines.end());
- // Determine which predefines that where used to build the PCH file
- // are missing from the command line.
- std::vector<std::string> MissingPredefines;
+ // Determine which predefines that were used to build the PCH file are missing
+ // from the command line.
+ std::vector<llvm::StringRef> MissingPredefines;
std::set_difference(PCHLines.begin(), PCHLines.end(),
CmdLineLines.begin(), CmdLineLines.end(),
std::back_inserter(MissingPredefines));
@@ -205,31 +180,30 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef,
bool MissingDefines = false;
bool ConflictingDefines = false;
for (unsigned I = 0, N = MissingPredefines.size(); I != N; ++I) {
- const std::string &Missing = MissingPredefines[I];
- if (!startsWith(Missing, "#define ") != 0) {
+ llvm::StringRef Missing = MissingPredefines[I];
+ if (!Missing.startswith("#define ")) {
Reader.Diag(diag::warn_pch_compiler_options_mismatch);
return true;
}
- // This is a macro definition. Determine the name of the macro
- // we're defining.
+ // This is a macro definition. Determine the name of the macro we're
+ // defining.
std::string::size_type StartOfMacroName = strlen("#define ");
std::string::size_type EndOfMacroName
= Missing.find_first_of("( \n\r", StartOfMacroName);
assert(EndOfMacroName != std::string::npos &&
"Couldn't find the end of the macro name");
- std::string MacroName = Missing.substr(StartOfMacroName,
- EndOfMacroName - StartOfMacroName);
+ llvm::StringRef MacroName = Missing.slice(StartOfMacroName, EndOfMacroName);
- // Determine whether this macro was given a different definition
- // on the command line.
- std::string MacroDefStart = "#define " + MacroName;
+ // Determine whether this macro was given a different definition on the
+ // command line.
+ std::string MacroDefStart = "#define " + MacroName.str();
std::string::size_type MacroDefLen = MacroDefStart.size();
- std::vector<std::string>::iterator ConflictPos
+ llvm::SmallVector<llvm::StringRef, 8>::iterator ConflictPos
= std::lower_bound(CmdLineLines.begin(), CmdLineLines.end(),
MacroDefStart);
for (; ConflictPos != CmdLineLines.end(); ++ConflictPos) {
- if (!startsWith(*ConflictPos, MacroDefStart)) {
+ if (!ConflictPos->startswith(MacroDefStart)) {
// Different macro; we're done.
ConflictPos = CmdLineLines.end();
break;
@@ -250,21 +224,18 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef,
<< MacroName;
// Show the definition of this macro within the PCH file.
- const char *MissingDef = strstr(PCHPredef, Missing.c_str());
- unsigned Offset = MissingDef - PCHPredef;
- SourceLocation PCHMissingLoc
- = SourceMgr.getLocForStartOfFile(PCHBufferID)
- .getFileLocWithOffset(Offset);
- Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as)
- << MacroName;
+ llvm::StringRef::size_type Offset = PCHPredef.find(Missing);
+ assert(Offset != llvm::StringRef::npos && "Unable to find macro!");
+ SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(PCHBufferID)
+ .getFileLocWithOffset(Offset);
+ Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) << MacroName;
ConflictingDefines = true;
continue;
}
- // If the macro doesn't conflict, then we'll just pick up the
- // macro definition from the PCH file. Warn the user that they
- // made a mistake.
+ // If the macro doesn't conflict, then we'll just pick up the macro
+ // definition from the PCH file. Warn the user that they made a mistake.
if (ConflictingDefines)
continue; // Don't complain if there are already conflicting defs
@@ -274,10 +245,9 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef,
}
// Show the definition of this macro within the PCH file.
- const char *MissingDef = strstr(PCHPredef, Missing.c_str());
- unsigned Offset = MissingDef - PCHPredef;
- SourceLocation PCHMissingLoc
- = SourceMgr.getLocForStartOfFile(PCHBufferID)
+ llvm::StringRef::size_type Offset = PCHPredef.find(Missing);
+ assert(Offset != llvm::StringRef::npos && "Unable to find macro!");
+ SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(PCHBufferID)
.getFileLocWithOffset(Offset);
Reader.Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch);
}
@@ -289,13 +259,13 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef,
// parameters that were not present when building the PCH
// file. Extra #defines are okay, so long as the identifiers being
// defined were not used within the precompiled header.
- std::vector<std::string> ExtraPredefines;
+ std::vector<llvm::StringRef> ExtraPredefines;
std::set_difference(CmdLineLines.begin(), CmdLineLines.end(),
PCHLines.begin(), PCHLines.end(),
std::back_inserter(ExtraPredefines));
for (unsigned I = 0, N = ExtraPredefines.size(); I != N; ++I) {
- const std::string &Extra = ExtraPredefines[I];
- if (!startsWith(Extra, "#define ") != 0) {
+ llvm::StringRef &Extra = ExtraPredefines[I];
+ if (!Extra.startswith("#define ")) {
Reader.Diag(diag::warn_pch_compiler_options_mismatch);
return true;
}
@@ -307,16 +277,13 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef,
= Extra.find_first_of("( \n\r", StartOfMacroName);
assert(EndOfMacroName != std::string::npos &&
"Couldn't find the end of the macro name");
- std::string MacroName = Extra.substr(StartOfMacroName,
- EndOfMacroName - StartOfMacroName);
+ llvm::StringRef MacroName = Extra.slice(StartOfMacroName, EndOfMacroName);
// Check whether this name was used somewhere in the PCH file. If
// so, defining it as a macro could change behavior, so we reject
// the PCH file.
- if (IdentifierInfo *II = Reader.get(MacroName.c_str(),
- MacroName.c_str() + MacroName.size())) {
- Reader.Diag(diag::warn_macro_name_used_in_pch)
- << II;
+ if (IdentifierInfo *II = Reader.get(MacroName)) {
+ Reader.Diag(diag::warn_macro_name_used_in_pch) << II;
return true;
}
@@ -650,11 +617,11 @@ bool PCHReader::Error(const char *Msg) {
///
/// \returns true if there was a mismatch (in which case the PCH file
/// should be ignored), or false otherwise.
-bool PCHReader::CheckPredefinesBuffer(const char *PCHPredef,
- unsigned PCHPredefLen,
+bool PCHReader::CheckPredefinesBuffer(llvm::StringRef PCHPredef,
FileID PCHBufferID) {
if (Listener)
- return Listener->ReadPredefinesBuffer(PCHPredef, PCHPredefLen, PCHBufferID,
+ return Listener->ReadPredefinesBuffer(PCHPredef, PCHBufferID,
+ ActualOriginalFileName,
SuggestedPredefines);
return false;
}
@@ -1364,7 +1331,8 @@ PCHReader::ReadPCHBlock() {
break;
case pch::ORIGINAL_FILE_NAME:
- OriginalFileName.assign(BlobStart, BlobLen);
+ ActualOriginalFileName.assign(BlobStart, BlobLen);
+ OriginalFileName = ActualOriginalFileName;
MaybeAddSystemRootToFilename(OriginalFileName);
break;
@@ -1403,10 +1371,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
//
// FIXME: This shouldn't be here, we should just take a raw_ostream.
std::string ErrStr;
- if (FileName == "-")
- Buffer.reset(llvm::MemoryBuffer::getSTDIN());
- else
- Buffer.reset(llvm::MemoryBuffer::getFile(FileName.c_str(), &ErrStr));
+ Buffer.reset(llvm::MemoryBuffer::getFileOrSTDIN(FileName, &ErrStr));
if (!Buffer) {
Error(ErrStr.c_str());
return IgnorePCH;
@@ -1478,7 +1443,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
}
// Check the predefines buffer.
- if (CheckPredefinesBuffer(PCHPredefines, PCHPredefinesLen,
+ if (CheckPredefinesBuffer(llvm::StringRef(PCHPredefines, PCHPredefinesLen),
PCHPredefinesBufferID))
return IgnorePCH;
@@ -1741,6 +1706,7 @@ bool PCHReader::ParseLanguageOptions(
PARSE_LANGOPT(NoInline);
PARSE_LANGOPT(AccessControl);
PARSE_LANGOPT(CharIsSigned);
+ PARSE_LANGOPT(ShortWChar);
LangOpts.setGCMode((LangOptions::GCMode)Record[Idx]);
++Idx;
LangOpts.setVisibilityMode((LangOptions::VisibilityMode)Record[Idx]);
@@ -2213,6 +2179,14 @@ PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind,
return ReadDeclExpr();
case TemplateArgument::Type:
return GetDeclaratorInfo(Record, Index);
+ case TemplateArgument::Template: {
+ SourceLocation
+ QualStart = SourceLocation::getFromRawEncoding(Record[Index++]),
+ QualEnd = SourceLocation::getFromRawEncoding(Record[Index++]),
+ TemplateNameLoc = SourceLocation::getFromRawEncoding(Record[Index++]);
+ return TemplateArgumentLocInfo(SourceRange(QualStart, QualEnd),
+ TemplateNameLoc);
+ }
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index b9ece21..6a92a2d 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -264,7 +264,12 @@ void PCHDeclReader::VisitObjCClassDecl(ObjCClassDecl *CD) {
ClassRefs.reserve(NumClassRefs);
for (unsigned I = 0; I != NumClassRefs; ++I)
ClassRefs.push_back(cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
- CD->setClassList(*Reader.getContext(), ClassRefs.data(), NumClassRefs);
+ llvm::SmallVector<SourceLocation, 16> SLocs;
+ SLocs.reserve(NumClassRefs);
+ for (unsigned I = 0; I != NumClassRefs; ++I)
+ SLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ CD->setClassList(*Reader.getContext(), ClassRefs.data(), SLocs.data(),
+ NumClassRefs);
}
void PCHDeclReader::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *FPD) {
@@ -442,6 +447,8 @@ Attr *PCHReader::ReadAttributes() {
(BlocksAttr::BlocksAttrTypes)Record[Idx++]);
break;
+ SIMPLE_ATTR(CDecl);
+
case Attr::Cleanup:
New = ::new (*Context) CleanupAttr(
cast<FunctionDecl>(GetDecl(Record[Idx++])));
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index de56166..8a45ebc 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -765,6 +765,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
// be enabled.
Record.push_back(LangOpts.CharIsSigned); // Whether char is a signed or
// unsigned type
+ Record.push_back(LangOpts.ShortWChar); // force wchar_t to be unsigned short
Record.push_back(LangOpts.getGCMode());
Record.push_back(LangOpts.getVisibilityMode());
Record.push_back(LangOpts.getStackProtectorMode());
@@ -1247,9 +1248,9 @@ void PCHWriter::WriteType(QualType T) {
// Emit the type's representation.
PCHTypeWriter W(*this, Record);
- if (T.hasNonFastQualifiers()) {
- Qualifiers Qs = T.getQualifiers();
- AddTypeRef(T.getUnqualifiedType(), Record);
+ if (T.hasLocalNonFastQualifiers()) {
+ Qualifiers Qs = T.getLocalQualifiers();
+ AddTypeRef(T.getLocalUnqualifiedType(), Record);
Record.push_back(Qs.getAsOpaqueValue());
W.Code = pch::TYPE_EXT_QUAL;
} else {
@@ -1767,6 +1768,9 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
Record.push_back(cast<BlocksAttr>(Attr)->getType()); // FIXME: stable
break;
+ case Attr::CDecl:
+ break;
+
case Attr::Cleanup:
AddDeclRef(cast<CleanupAttr>(Attr)->getFunctionDecl(), Record);
break;
@@ -2118,6 +2122,12 @@ void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg,
case TemplateArgument::Type:
AddDeclaratorInfo(Arg.getLocInfo().getAsDeclaratorInfo(), Record);
break;
+ case TemplateArgument::Template:
+ Record.push_back(
+ Arg.getTemplateQualifierRange().getBegin().getRawEncoding());
+ Record.push_back(Arg.getTemplateQualifierRange().getEnd().getRawEncoding());
+ Record.push_back(Arg.getTemplateNameLoc().getRawEncoding());
+ break;
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
@@ -2144,10 +2154,10 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {
return;
}
- unsigned FastQuals = T.getFastQualifiers();
+ unsigned FastQuals = T.getLocalFastQualifiers();
T.removeFastQualifiers();
- if (T.hasNonFastQualifiers()) {
+ if (T.hasLocalNonFastQualifiers()) {
pch::TypeID &ID = TypeIDs[T];
if (ID == 0) {
// We haven't seen these qualifiers applied to this type before.
@@ -2162,7 +2172,7 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {
return;
}
- assert(!T.hasQualifiers());
+ assert(!T.hasLocalQualifiers());
if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr())) {
pch::TypeID ID = 0;
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index 8997e66..c7bfee2 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -260,7 +260,9 @@ void PCHDeclWriter::VisitObjCClassDecl(ObjCClassDecl *D) {
VisitDecl(D);
Record.push_back(D->size());
for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I)
- Writer.AddDeclRef(*I, Record);
+ Writer.AddDeclRef(I->getInterface(), Record);
+ for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I)
+ Writer.AddSourceLocation(I->getLocation(), Record);
Code = pch::DECL_OBJC_CLASS;
}
diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp
index 1be9ea8..6bcf39a 100644
--- a/lib/Frontend/PlistDiagnostics.cpp
+++ b/lib/Frontend/PlistDiagnostics.cpp
@@ -37,6 +37,7 @@ namespace {
const std::string OutputFile;
const LangOptions &LangOpts;
llvm::OwningPtr<PathDiagnosticClient> SubPD;
+ bool flushed;
public:
PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts,
PathDiagnosticClient *subPD);
@@ -61,7 +62,7 @@ namespace {
PlistDiagnostics::PlistDiagnostics(const std::string& output,
const LangOptions &LO,
PathDiagnosticClient *subPD)
- : OutputFile(output), LangOpts(LO), SubPD(subPD) {}
+ : OutputFile(output), LangOpts(LO), SubPD(subPD), flushed(false) {}
PathDiagnosticClient*
clang::CreatePlistDiagnosticClient(const std::string& s, const Preprocessor &PP,
@@ -310,6 +311,11 @@ void PlistDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string>
*FilesMade) {
+
+ if (flushed)
+ return;
+
+ flushed = true;
// Build up a set of FIDs that we use by scanning the locations and
// ranges of the diagnostics.
@@ -423,4 +429,6 @@ void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string>
if (FilesMade)
FilesMade->push_back(OutputFile);
+
+ BatchedDiags.clear();
}
diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp
index 25b40c7..deb5498 100644
--- a/lib/Frontend/PrintParserCallbacks.cpp
+++ b/lib/Frontend/PrintParserCallbacks.cpp
@@ -79,10 +79,11 @@ namespace {
/// Scope will always be top level file scope.
Action::DeclPtrTy ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
IdentifierInfo **IdentList,
+ SourceLocation *IdentLocs,
unsigned NumElts) {
Out << __FUNCTION__ << "\n";
return MinimalAction::ActOnForwardClassDeclaration(AtClassLoc, IdentList,
- NumElts);
+ IdentLocs, NumElts);
}
// Pure Printing
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 630a093..3742405 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -13,13 +13,14 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/Utils.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/PreprocessorOutputOptions.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/PPCallbacks.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/Pragma.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/TokenConcatenation.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/config.h"
@@ -439,7 +440,7 @@ namespace {
};
}
-void clang::DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
+static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
// -dM mode just scans and ignores all tokens in the files, then dumps out
// the macro table at the end.
PP.EnterMainSourceFile();
@@ -467,18 +468,23 @@ void clang::DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
/// DoPrintPreprocessedInput - This implements -E mode.
///
void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS,
- bool EnableCommentOutput,
- bool EnableMacroCommentOutput,
- bool DisableLineMarkers,
- bool DumpDefines) {
+ const PreprocessorOutputOptions &Opts) {
+ // Show macros with no output is handled specially.
+ if (!Opts.ShowCPP) {
+ assert(Opts.ShowMacros && "Not yet implemented!");
+ DoPrintMacros(PP, OS);
+ return;
+ }
+
// Inform the preprocessor whether we want it to retain comments or not, due
// to -C or -CC.
- PP.SetCommentRetentionState(EnableCommentOutput, EnableMacroCommentOutput);
+ PP.SetCommentRetentionState(Opts.ShowComments, Opts.ShowMacroComments);
OS->SetBufferSize(64*1024);
PrintPPOutputPPCallbacks *Callbacks =
- new PrintPPOutputPPCallbacks(PP, *OS, DisableLineMarkers, DumpDefines);
+ new PrintPPOutputPPCallbacks(PP, *OS, !Opts.ShowLineMarkers,
+ Opts.ShowMacros);
PP.AddPragmaHandler(0, new UnknownPragmaHandler("#pragma", Callbacks));
PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC",
Callbacks));
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index 24ad69e..06955e5 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -744,7 +744,7 @@ void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) {
typedefString += "\n";
for (ObjCClassDecl::iterator I = ClassDecl->begin(), E = ClassDecl->end();
I != E; ++I) {
- ObjCInterfaceDecl *ForwardDecl = *I;
+ ObjCInterfaceDecl *ForwardDecl = I->getInterface();
typedefString += "#ifndef _REWRITER_typedef_";
typedefString += ForwardDecl->getNameAsString();
typedefString += "\n";
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 4f8c804..6ab0e16 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -39,9 +39,16 @@ static const enum llvm::raw_ostream::Colors savedColor =
const unsigned WordWrapIndentation = 6;
TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream &os,
- const DiagnosticOptions &diags)
+ const DiagnosticOptions &diags,
+ bool _OwnsOutputStream)
: OS(os), LangOpts(0), DiagOpts(&diags),
- LastCaretDiagnosticWasNote(false) {
+ LastCaretDiagnosticWasNote(0),
+ OwnsOutputStream(_OwnsOutputStream) {
+}
+
+TextDiagnosticPrinter::~TextDiagnosticPrinter() {
+ if (OwnsOutputStream)
+ delete &OS;
}
void TextDiagnosticPrinter::
diff --git a/lib/Frontend/VerifyDiagnosticsClient.cpp b/lib/Frontend/VerifyDiagnosticsClient.cpp
new file mode 100644
index 0000000..2891aec
--- /dev/null
+++ b/lib/Frontend/VerifyDiagnosticsClient.cpp
@@ -0,0 +1,344 @@
+//===--- VerifyDiagnosticsClient.cpp - Verifying Diagnostic Client --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a concrete diagnostic client, which buffers the diagnostic messages.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/VerifyDiagnosticsClient.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+VerifyDiagnosticsClient::VerifyDiagnosticsClient(Diagnostic &_Diags,
+ DiagnosticClient *_Primary)
+ : Diags(_Diags), PrimaryClient(_Primary),
+ Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0), NumErrors(0) {
+}
+
+VerifyDiagnosticsClient::~VerifyDiagnosticsClient() {
+ CheckDiagnostics();
+}
+
+// DiagnosticClient interface.
+
+void VerifyDiagnosticsClient::BeginSourceFile(const LangOptions &LangOpts,
+ const Preprocessor *PP) {
+ // FIXME: Const hack, we screw up the preprocessor but in practice its ok
+ // because it doesn't get reused. It would be better if we could make a copy
+ // though.
+ CurrentPreprocessor = const_cast<Preprocessor*>(PP);
+
+ PrimaryClient->BeginSourceFile(LangOpts, PP);
+}
+
+void VerifyDiagnosticsClient::EndSourceFile() {
+ CheckDiagnostics();
+
+ PrimaryClient->EndSourceFile();
+
+ CurrentPreprocessor = 0;
+}
+
+void VerifyDiagnosticsClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info) {
+ // Send the diagnostic to the buffer, we will check it once we reach the end
+ // of the source file (or are destructed).
+ Buffer->HandleDiagnostic(DiagLevel, Info);
+}
+
+// FIXME: It would be nice to just get this from the primary diagnostic client
+// or something.
+bool VerifyDiagnosticsClient::HadErrors() {
+ CheckDiagnostics();
+
+ return NumErrors != 0;
+}
+
+//===----------------------------------------------------------------------===//
+// Checking diagnostics implementation.
+//===----------------------------------------------------------------------===//
+
+typedef TextDiagnosticBuffer::DiagList DiagList;
+typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
+
+/// FindDiagnostics - Go through the comment and see if it indicates expected
+/// diagnostics. If so, then put them in a diagnostic list.
+///
+static void FindDiagnostics(const char *CommentStart, unsigned CommentLen,
+ DiagList &ExpectedDiags,
+ Preprocessor &PP, SourceLocation Pos,
+ const char *ExpectedStr) {
+ const char *CommentEnd = CommentStart+CommentLen;
+ unsigned ExpectedStrLen = strlen(ExpectedStr);
+
+ // Find all expected-foo diagnostics in the string and add them to
+ // ExpectedDiags.
+ while (CommentStart != CommentEnd) {
+ CommentStart = std::find(CommentStart, CommentEnd, 'e');
+ if (unsigned(CommentEnd-CommentStart) < ExpectedStrLen) return;
+
+ // If this isn't expected-foo, ignore it.
+ if (memcmp(CommentStart, ExpectedStr, ExpectedStrLen)) {
+ ++CommentStart;
+ continue;
+ }
+
+ CommentStart += ExpectedStrLen;
+
+ // Skip whitespace.
+ while (CommentStart != CommentEnd &&
+ isspace(CommentStart[0]))
+ ++CommentStart;
+
+ // Default, if we find the '{' now, is 1 time.
+ int Times = 1;
+ int Temp = 0;
+ // In extended syntax, there could be a digit now.
+ while (CommentStart != CommentEnd &&
+ CommentStart[0] >= '0' && CommentStart[0] <= '9') {
+ Temp *= 10;
+ Temp += CommentStart[0] - '0';
+ ++CommentStart;
+ }
+ if (Temp > 0)
+ Times = Temp;
+
+ // Skip whitespace again.
+ while (CommentStart != CommentEnd &&
+ isspace(CommentStart[0]))
+ ++CommentStart;
+
+ // We should have a {{ now.
+ if (CommentEnd-CommentStart < 2 ||
+ CommentStart[0] != '{' || CommentStart[1] != '{') {
+ if (std::find(CommentStart, CommentEnd, '{') != CommentEnd)
+ PP.Diag(Pos, diag::err_verify_bogus_characters);
+ else
+ PP.Diag(Pos, diag::err_verify_missing_start);
+ return;
+ }
+ CommentStart += 2;
+
+ // Find the }}.
+ const char *ExpectedEnd = CommentStart;
+ while (1) {
+ ExpectedEnd = std::find(ExpectedEnd, CommentEnd, '}');
+ if (CommentEnd-ExpectedEnd < 2) {
+ PP.Diag(Pos, diag::err_verify_missing_end);
+ return;
+ }
+
+ if (ExpectedEnd[1] == '}')
+ break;
+
+ ++ExpectedEnd; // Skip over singular }'s
+ }
+
+ std::string Msg(CommentStart, ExpectedEnd);
+ std::string::size_type FindPos;
+ while ((FindPos = Msg.find("\\n")) != std::string::npos)
+ Msg.replace(FindPos, 2, "\n");
+ // Add is possibly multiple times.
+ for (int i = 0; i < Times; ++i)
+ ExpectedDiags.push_back(std::make_pair(Pos, Msg));
+
+ CommentStart = ExpectedEnd;
+ }
+}
+
+/// FindExpectedDiags - Lex the main source file to find all of the
+// expected errors and warnings.
+static void FindExpectedDiags(Preprocessor &PP,
+ DiagList &ExpectedErrors,
+ DiagList &ExpectedWarnings,
+ DiagList &ExpectedNotes) {
+ // Create a raw lexer to pull all the comments out of the main file. We don't
+ // want to look in #include'd headers for expected-error strings.
+ FileID FID = PP.getSourceManager().getMainFileID();
+ if (PP.getSourceManager().getMainFileID().isInvalid())
+ return;
+
+ // Create a lexer to lex all the tokens of the main file in raw mode.
+ Lexer RawLex(FID, PP.getSourceManager(), PP.getLangOptions());
+
+ // Return comments as tokens, this is how we find expected diagnostics.
+ RawLex.SetCommentRetentionState(true);
+
+ Token Tok;
+ Tok.setKind(tok::comment);
+ while (Tok.isNot(tok::eof)) {
+ RawLex.Lex(Tok);
+ if (!Tok.is(tok::comment)) continue;
+
+ std::string Comment = PP.getSpelling(Tok);
+ if (Comment.empty()) continue;
+
+ // Find all expected errors.
+ FindDiagnostics(&Comment[0], Comment.size(), ExpectedErrors, PP,
+ Tok.getLocation(), "expected-error");
+
+ // Find all expected warnings.
+ FindDiagnostics(&Comment[0], Comment.size(), ExpectedWarnings, PP,
+ Tok.getLocation(), "expected-warning");
+
+ // Find all expected notes.
+ FindDiagnostics(&Comment[0], Comment.size(), ExpectedNotes, PP,
+ Tok.getLocation(), "expected-note");
+ };
+}
+
+/// PrintProblem - This takes a diagnostic map of the delta between expected and
+/// seen diagnostics. If there's anything in it, then something unexpected
+/// happened. Print the map out in a nice format and return "true". If the map
+/// is empty and we're not going to print things, then return "false".
+///
+static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr,
+ const_diag_iterator diag_begin,
+ const_diag_iterator diag_end,
+ const char *Kind, bool Expected) {
+ if (diag_begin == diag_end) return 0;
+
+ llvm::SmallString<256> Fmt;
+ llvm::raw_svector_ostream OS(Fmt);
+ for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) {
+ if (I->first.isInvalid() || !SourceMgr)
+ OS << "\n (frontend)";
+ else
+ OS << "\n Line " << SourceMgr->getInstantiationLineNumber(I->first);
+ OS << ": " << I->second;
+ }
+
+ Diags.Report(diag::err_verify_inconsistent_diags)
+ << Kind << !Expected << OS.str();
+ return std::distance(diag_begin, diag_end);
+}
+
+/// CompareDiagLists - Compare two diagnostic lists and return the difference
+/// between them.
+///
+static unsigned CompareDiagLists(Diagnostic &Diags,
+ SourceManager &SourceMgr,
+ const_diag_iterator d1_begin,
+ const_diag_iterator d1_end,
+ const_diag_iterator d2_begin,
+ const_diag_iterator d2_end,
+ const char *Label) {
+ DiagList LeftOnly;
+ DiagList Left(d1_begin, d1_end);
+ DiagList Right(d2_begin, d2_end);
+
+ for (const_diag_iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
+ unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(I->first);
+ const std::string &Diag1 = I->second;
+
+ DiagList::iterator II, IE;
+ for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
+ unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first);
+ if (LineNo1 != LineNo2) continue;
+
+ const std::string &Diag2 = II->second;
+ if (Diag2.find(Diag1) != std::string::npos ||
+ Diag1.find(Diag2) != std::string::npos) {
+ break;
+ }
+ }
+ if (II == IE) {
+ // Not found.
+ LeftOnly.push_back(*I);
+ } else {
+ // Found. The same cannot be found twice.
+ Right.erase(II);
+ }
+ }
+ // Now all that's left in Right are those that were not matched.
+
+ return (PrintProblem(Diags, &SourceMgr,
+ LeftOnly.begin(), LeftOnly.end(), Label, true) +
+ PrintProblem(Diags, &SourceMgr,
+ Right.begin(), Right.end(), Label, false));
+}
+
+/// CheckResults - This compares the expected results to those that
+/// were actually reported. It emits any discrepencies. Return "true" if there
+/// were problems. Return "false" otherwise.
+///
+static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr,
+ const TextDiagnosticBuffer &Buffer,
+ const DiagList &ExpectedErrors,
+ const DiagList &ExpectedWarnings,
+ const DiagList &ExpectedNotes) {
+ // We want to capture the delta between what was expected and what was
+ // seen.
+ //
+ // Expected \ Seen - set expected but not seen
+ // Seen \ Expected - set seen but not expected
+ unsigned NumProblems = 0;
+
+ // See if there are error mismatches.
+ NumProblems += CompareDiagLists(Diags, SourceMgr,
+ ExpectedErrors.begin(), ExpectedErrors.end(),
+ Buffer.err_begin(), Buffer.err_end(),
+ "error");
+
+ // See if there are warning mismatches.
+ NumProblems += CompareDiagLists(Diags, SourceMgr,
+ ExpectedWarnings.begin(),
+ ExpectedWarnings.end(),
+ Buffer.warn_begin(), Buffer.warn_end(),
+ "warning");
+
+ // See if there are note mismatches.
+ NumProblems += CompareDiagLists(Diags, SourceMgr,
+ ExpectedNotes.begin(),
+ ExpectedNotes.end(),
+ Buffer.note_begin(), Buffer.note_end(),
+ "note");
+
+ return NumProblems;
+}
+
+
+void VerifyDiagnosticsClient::CheckDiagnostics() {
+ DiagList ExpectedErrors, ExpectedWarnings, ExpectedNotes;
+
+ // Ensure any diagnostics go to the primary client.
+ DiagnosticClient *CurClient = Diags.getClient();
+ Diags.setClient(PrimaryClient.get());
+
+ // If we have a preprocessor, scan the source for expected diagnostic
+ // markers. If not then any diagnostics are unexpected.
+ if (CurrentPreprocessor) {
+ FindExpectedDiags(*CurrentPreprocessor, ExpectedErrors, ExpectedWarnings,
+ ExpectedNotes);
+
+ // Check that the expected diagnostics occurred.
+ NumErrors += CheckResults(Diags, CurrentPreprocessor->getSourceManager(),
+ *Buffer,
+ ExpectedErrors, ExpectedWarnings, ExpectedNotes);
+ } else {
+ NumErrors += (PrintProblem(Diags, 0,
+ Buffer->err_begin(), Buffer->err_end(),
+ "error", false) +
+ PrintProblem(Diags, 0,
+ Buffer->warn_begin(), Buffer->warn_end(),
+ "warn", false) +
+ PrintProblem(Diags, 0,
+ Buffer->note_begin(), Buffer->note_end(),
+ "note", false));
+ }
+
+ Diags.setClient(CurClient);
+
+ // Reset the buffer, we have processed all the diagnostics in it.
+ Buffer.reset(new TextDiagnosticBuffer());
+}
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
index 7b01b0f..ff44c90 100644
--- a/lib/Frontend/Warnings.cpp
+++ b/lib/Frontend/Warnings.cpp
@@ -24,6 +24,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include <cstdio>
#include <cstring>
@@ -32,26 +33,24 @@
using namespace clang;
bool clang::ProcessWarningOptions(Diagnostic &Diags,
- std::vector<std::string> &Warnings,
- bool Pedantic, bool PedanticErrors,
- bool NoWarnings) {
+ const DiagnosticOptions &Opts) {
Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers
- Diags.setIgnoreAllWarnings(NoWarnings);
+ Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings);
// If -pedantic or -pedantic-errors was specified, then we want to map all
// extension diagnostics onto WARNING or ERROR unless the user has futz'd
// around with them explicitly.
- if (PedanticErrors)
+ if (Opts.PedanticErrors)
Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Error);
- else if (Pedantic)
+ else if (Opts.Pedantic)
Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Warn);
else
Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Ignore);
// FIXME: -Wfatal-errors / -Wfatal-errors=foo
- for (unsigned i = 0, e = Warnings.size(); i != e; ++i) {
- const std::string &Opt = Warnings[i];
+ for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) {
+ const std::string &Opt = Opts.Warnings[i];
const char *OptStart = &Opt[0];
const char *OptEnd = OptStart+Opt.size();
assert(*OptEnd == 0 && "Expect null termination for lower-bound search");
@@ -100,8 +99,7 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags,
}
if (Diags.setDiagnosticGroupMapping(OptStart, Mapping))
- Diags.Report(FullSourceLoc(), diag::warn_unknown_warning_option)
- << ("-W" + Opt);
+ Diags.Report(diag::warn_unknown_warning_option) << ("-W" + Opt);
}
return false;
diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h
index f03c177..bb81a6a 100644
--- a/lib/Headers/stdint.h
+++ b/lib/Headers/stdint.h
@@ -33,60 +33,178 @@
# include_next <stdint.h>
#else
-/* We currently only support targets with power of two, 2s complement integers.
- */
-
/* C99 7.18.1.1 Exact-width integer types.
* C99 7.18.1.2 Minimum-width integer types.
* C99 7.18.1.3 Fastest minimum-width integer types.
- * Since we only support pow-2 targets, these map directly to exact width types.
+ *
+ * The standard requires that exact-width type be defined for 8-, 16-, 32-, and
+ * 64-bit types if they are implemented. Other exact width types are optional.
+ * This implementation defines an exact-width types for every integer width
+ * that is represented in the standard integer types.
+ *
+ * The standard also requires minimum-width types be defined for 8-, 16-, 32-,
+ * and 64-bit widths regardless of whether there are corresponding exact-width
+ * types.
+ *
+ * To accomodate targets that are missing types that are exactly 8, 16, 32, or
+ * 64 bits wide, this implementation takes an approach of cascading
+ * redefintions, redefining __int_leastN_t to successively smaller exact-width
+ * types. It is therefore important that the types are defined in order of
+ * descending widths.
+ *
+ * We currently assume that the minimum-width types and the fastest
+ * minimum-width types are the same. This is allowed by the standard, but is
+ * suboptimal.
+ *
+ * In violation of the standard, some targets do not implement a type that is
+ * wide enough to represent all of the required widths (8-, 16-, 32-, 64-bit).
+ * To accomodate these targets, a required minimum-width type is only
+ * defined if there exists an exact-width type of equal or greater width.
*/
-/* Some 16-bit targets do not have a 64-bit datatype. Only define the 64-bit
- * typedefs if there is something to typedef them to.
- */
#ifdef __INT64_TYPE__
-#ifndef __int8_t_defined /* glibc does weird things with sys/types.h */
-typedef __INT64_TYPE__ int64_t;
-#endif
+# ifndef __int8_t_defined /* glibc sys/types.h also defines int64_t*/
+typedef signed __INT64_TYPE__ int64_t;
+# endif /* __int8_t_defined */
typedef unsigned __INT64_TYPE__ uint64_t;
-typedef int64_t int_least64_t;
-typedef uint64_t uint_least64_t;
-typedef int64_t int_fast64_t;
-typedef uint64_t uint_fast64_t;
-#endif
-
-#ifndef __int8_t_defined /* glibc does weird things with sys/types.h */
-typedef __INT32_TYPE__ int32_t;
-#endif
-#ifndef __uint32_t_defined /* more glibc compatibility */
-#define __uint32_t_defined
+# define __int_least64_t int64_t
+# define __uint_least64_t uint64_t
+# define __int_least32_t int64_t
+# define __uint_least32_t uint64_t
+# define __int_least16_t int64_t
+# define __uint_least16_t uint64_t
+# define __int_least8_t int64_t
+# define __uint_least8_t uint64_t
+#endif /* __INT64_TYPE__ */
+
+#ifdef __int_least64_t
+typedef __int_least64_t int_least64_t;
+typedef __uint_least64_t uint_least64_t;
+typedef __int_least64_t int_fast64_t;
+typedef __uint_least64_t uint_fast64_t;
+#endif /* __int_least64_t */
+
+#ifdef __INT56_TYPE__
+typedef signed __INT56_TYPE__ int56_t;
+typedef unsigned __INT56_TYPE__ uint56_t;
+typedef int56_t int_least56_t;
+typedef uint56_t uint_least56_t;
+typedef int56_t int_fast56_t;
+typedef uint56_t uint_fast56_t;
+# define __int_least32_t int56_t
+# define __uint_least32_t uint56_t
+# define __int_least16_t int56_t
+# define __uint_least16_t uint56_t
+# define __int_least8_t int56_t
+# define __uint_least8_t uint56_t
+#endif /* __INT56_TYPE__ */
+
+
+#ifdef __INT48_TYPE__
+typedef signed __INT48_TYPE__ int48_t;
+typedef unsigned __INT48_TYPE__ uint48_t;
+typedef int48_t int_least48_t;
+typedef uint48_t uint_least48_t;
+typedef int48_t int_fast48_t;
+typedef uint48_t uint_fast48_t;
+# define __int_least32_t int48_t
+# define __uint_least32_t uint48_t
+# define __int_least16_t int48_t
+# define __uint_least16_t uint48_t
+# define __int_least8_t int48_t
+# define __uint_least8_t uint48_t
+#endif /* __INT48_TYPE__ */
+
+
+#ifdef __INT40_TYPE__
+typedef signed __INT40_TYPE__ int40_t;
+typedef unsigned __INT40_TYPE__ uint40_t;
+typedef int40_t int_least40_t;
+typedef uint40_t uint_least40_t;
+typedef int40_t int_fast40_t;
+typedef uint40_t uint_fast40_t;
+# define __int_least32_t int40_t
+# define __uint_least32_t uint40_t
+# define __int_least16_t int40_t
+# define __uint_least16_t uint40_t
+# define __int_least8_t int40_t
+# define __uint_least8_t uint40_t
+#endif /* __INT40_TYPE__ */
+
+
+#ifdef __INT32_TYPE__
+
+# ifndef __int8_t_defined /* glibc sys/types.h also defines int32_t*/
+typedef signed __INT32_TYPE__ int32_t;
+# endif /* __int8_t_defined */
+
+# ifndef __uint32_t_defined /* more glibc compatibility */
+# define __uint32_t_defined
typedef unsigned __INT32_TYPE__ uint32_t;
-#endif
-typedef int32_t int_least32_t;
-typedef uint32_t uint_least32_t;
-typedef int32_t int_fast32_t;
-typedef uint32_t uint_fast32_t;
-
-
-#ifndef __int8_t_defined /* glibc does weird things with sys/types.h */
-typedef __INT16_TYPE__ int16_t;
-#endif
+# endif /* __uint32_t_defined */
+
+# define __int_least32_t int32_t
+# define __uint_least32_t uint32_t
+# define __int_least16_t int32_t
+# define __uint_least16_t uint32_t
+# define __int_least8_t int32_t
+# define __uint_least8_t uint32_t
+#endif /* __INT32_TYPE__ */
+
+#ifdef __int_least32_t
+typedef __int_least32_t int_least32_t;
+typedef __uint_least32_t uint_least32_t;
+typedef __int_least32_t int_fast32_t;
+typedef __uint_least32_t uint_fast32_t;
+#endif /* __int_least32_t */
+
+#ifdef __INT24_TYPE__
+typedef signed __INT24_TYPE__ int24_t;
+typedef unsigned __INT24_TYPE__ uint24_t;
+typedef int24_t int_least24_t;
+typedef uint24_t uint_least24_t;
+typedef int24_t int_fast24_t;
+typedef uint24_t uint_fast24_t;
+# define __int_least16_t int24_t
+# define __uint_least16_t uint24_t
+# define __int_least8_t int24_t
+# define __uint_least8_t uint24_t
+#endif /* __INT24_TYPE__ */
+
+#ifdef __INT16_TYPE__
+#ifndef __int8_t_defined /* glibc sys/types.h also defines int16_t*/
+typedef signed __INT16_TYPE__ int16_t;
+#endif /* __int8_t_defined */
typedef unsigned __INT16_TYPE__ uint16_t;
-typedef int16_t int_least16_t;
-typedef uint16_t uint_least16_t;
-typedef int16_t int_fast16_t;
-typedef uint16_t uint_fast16_t;
-
-
-#ifndef __int8_t_defined /* glibc does weird things with sys/types.h */
+# define __int_least16_t int16_t
+# define __uint_least16_t uint16_t
+# define __int_least8_t int16_t
+# define __uint_least8_t uint16_t
+#endif /* __INT16_TYPE__ */
+
+#ifdef __int_least16_t
+typedef __int_least16_t int_least16_t;
+typedef __uint_least16_t uint_least16_t;
+typedef __int_least16_t int_fast16_t;
+typedef __uint_least16_t uint_fast16_t;
+#endif /* __int_least16_t */
+
+
+#ifdef __INT8_TYPE__
+#ifndef __int8_t_defined /* glibc sys/types.h also defines int8_t*/
typedef signed __INT8_TYPE__ int8_t;
-#endif
+#endif /* __int8_t_defined */
typedef unsigned __INT8_TYPE__ uint8_t;
-typedef int8_t int_least8_t;
-typedef uint8_t uint_least8_t;
-typedef int8_t int_fast8_t;
-typedef uint8_t uint_fast8_t;
+# define __int_least8_t int8_t
+# define __uint_least8_t uint8_t
+#endif /* __INT8_TYPE__ */
+
+#ifdef __int_least8_t
+typedef __int_least8_t int_least8_t;
+typedef __uint_least8_t uint_least8_t;
+typedef __int_least8_t int_fast8_t;
+typedef __uint_least8_t uint_fast8_t;
+#endif /* __int_least8_t */
/* prevent glibc sys/types.h from defining conflicting types */
#ifndef __int8_t_defined
@@ -108,75 +226,376 @@ typedef __UINTMAX_TYPE__ uintmax_t;
/* C99 7.18.4 Macros for minimum-width integer constants.
*
+ * The standard requires that integer constant macros be defined for all the
+ * minimum-width types defined above. As 8-, 16-, 32-, and 64-bit minimum-width
+ * types are required, the corresponding integer constant macros are defined
+ * here. This implementation also defines minimum-width types for every other
+ * integer width that the target implements, so corresponding macros are
+ * defined below, too.
+ *
+ * These macros are defined using the same successive-shrinking approach as
+ * the type definitions above. It is likewise important that macros are defined
+ * in order of decending width.
+ *
* Note that C++ should not check __STDC_CONSTANT_MACROS here, contrary to the
* claims of the C standard (see C++ 18.3.1p2, [cstdint.syn]).
*/
-/* Only define the 64-bit size macros if we have 64-bit support. */
+#define __int_c_join(a, b) a ## b
+#define __int_c(v, suffix) __int_c_join(v, suffix)
+#define __uint_c(v, suffix) __int_c_join(v##U, suffix)
+
+
#ifdef __INT64_TYPE__
-#define INT64_C(v) (v##LL)
-#define UINT64_C(v) (v##ULL)
-#endif
+# ifdef __INT64_C_SUFFIX__
+# define __int64_c_suffix __INT64_C_SUFFIX__
+# define __int32_c_suffix __INT64_C_SUFFIX__
+# define __int16_c_suffix __INT64_C_SUFFIX__
+# define __int8_c_suffix __INT64_C_SUFFIX__
+# else
+# undef __int64_c_suffix
+# undef __int32_c_suffix
+# undef __int16_c_suffix
+# undef __int8_c_suffix
+# endif /* __INT64_C_SUFFIX__ */
+#endif /* __INT64_TYPE__ */
+
+#ifdef __int_least64_t
+# ifdef __int64_c_suffix
+# define INT64_C(v) __int_c(v, __int64_c_suffix)
+# define UINT64_C(v) __uint_c(v, __int64_c_suffix)
+# else
+# define INT64_C(v) v
+# define UINT64_C(v) v ## U
+# endif /* __int64_c_suffix */
+#endif /* __int_least64_t */
+
+
+#ifdef __INT56_TYPE__
+# ifdef __INT56_C_SUFFIX__
+# define INT56_C(v) __int_c(v, __INT56_C_SUFFIX__)
+# define UINT56_C(v) __uint_c(v, __INT56_C_SUFFIX__)
+# define __int32_c_suffix __INT56_C_SUFFIX__
+# define __int16_c_suffix __INT56_C_SUFFIX__
+# define __int8_c_suffix __INT56_C_SUFFIX__
+# else
+# define INT56_C(v) v
+# define UINT56_C(v) v ## U
+# undef __int32_c_suffix
+# undef __int16_c_suffix
+# undef __int8_c_suffix
+# endif /* __INT56_C_SUFFIX__ */
+#endif /* __INT56_TYPE__ */
+
+
+#ifdef __INT48_TYPE__
+# ifdef __INT48_C_SUFFIX__
+# define INT48_C(v) __int_c(v, __INT48_C_SUFFIX__)
+# define UINT48_C(v) __uint_c(v, __INT48_C_SUFFIX__)
+# define __int32_c_suffix __INT48_C_SUFFIX__
+# define __int16_c_suffix __INT48_C_SUFFIX__
+# define __int8_c_suffix __INT48_C_SUFFIX__
+# else
+# define INT48_C(v) v
+# define UINT48_C(v) v ## U
+# undef __int32_c_suffix
+# undef __int16_c_suffix
+# undef __int8_c_suffix
+# endif /* __INT48_C_SUFFIX__ */
+#endif /* __INT48_TYPE__ */
+
+
+#ifdef __INT40_TYPE__
+# ifdef __INT40_C_SUFFIX__
+# define INT40_C(v) __int_c(v, __INT40_C_SUFFIX__)
+# define UINT40_C(v) __uint_c(v, __INT40_C_SUFFIX__)
+# define __int32_c_suffix __INT40_C_SUFFIX__
+# define __int16_c_suffix __INT40_C_SUFFIX__
+# define __int8_c_suffix __INT40_C_SUFFIX__
+# else
+# define INT40_C(v) v
+# define UINT40_C(v) v ## U
+# undef __int32_c_suffix
+# undef __int16_c_suffix
+# undef __int8_c_suffix
+# endif /* __INT40_C_SUFFIX__ */
+#endif /* __INT40_TYPE__ */
+
+
+#ifdef __INT32_TYPE__
+# ifdef __INT32_C_SUFFIX__
+# define __int32_c_suffix __INT32_C_SUFFIX__
+# define __int16_c_suffix __INT32_C_SUFFIX__
+# define __int8_c_suffix __INT32_C_SUFFIX__
+#else
+# undef __int32_c_suffix
+# undef __int16_c_suffix
+# undef __int8_c_suffix
+# endif /* __INT32_C_SUFFIX__ */
+#endif /* __INT32_TYPE__ */
+
+#ifdef __int_least32_t
+# ifdef __int32_c_suffix
+# define INT32_C(v) __int_c(v, __int32_c_suffix)
+# define UINT32_C(v) __uint_c(v, __int32_c_suffix)
+# else
+# define INT32_C(v) v
+# define UINT32_C(v) v ## U
+# endif /* __int32_c_suffix */
+#endif /* __int_least32_t */
+
+
+#ifdef __INT24_TYPE__
+# ifdef __INT24_C_SUFFIX__
+# define INT24_C(v) __int_c(v, __INT24_C_SUFFIX__)
+# define UINT24_C(v) __uint_c(v, __INT24_C_SUFFIX__)
+# define __int16_c_suffix __INT24_C_SUFFIX__
+# define __int8_c_suffix __INT24_C_SUFFIX__
+# else
+# define INT24_C(v) v
+# define UINT24_C(v) v ## U
+# undef __int16_c_suffix
+# undef __int8_c_suffix
+# endif /* __INT24_C_SUFFIX__ */
+#endif /* __INT24_TYPE__ */
+
+
+#ifdef __INT16_TYPE__
+# ifdef __INT16_C_SUFFIX__
+# define __int16_c_suffix __INT16_C_SUFFIX__
+# define __int8_c_suffix __INT16_C_SUFFIX__
+#else
+# undef __int16_c_suffix
+# undef __int8_c_suffix
+# endif /* __INT16_C_SUFFIX__ */
+#endif /* __INT16_TYPE__ */
+
+#ifdef __int_least16_t
+# ifdef __int16_c_suffix
+# define INT16_C(v) __int_c(v, __int16_c_suffix)
+# define UINT16_C(v) __uint_c(v, __int16_c_suffix)
+# else
+# define INT16_C(v) v
+# define UINT16_C(v) v ## U
+# endif /* __int16_c_suffix */
+#endif /* __int_least16_t */
+
+
+#ifdef __INT8_TYPE__
+# ifdef __INT8_C_SUFFIX__
+# define __int8_c_suffix __INT8_C_SUFFIX__
+#else
+# undef __int8_c_suffix
+# endif /* __INT8_C_SUFFIX__ */
+#endif /* __INT8_TYPE__ */
+
+#ifdef __int_least8_t
+# ifdef __int8_c_suffix
+# define INT8_C(v) __int_c(v, __int8_c_suffix)
+# define UINT8_C(v) __uint_c(v, __int8_c_suffix)
+# else
+# define INT8_C(v) v
+# define UINT8_C(v) v ## U
+# endif /* __int8_c_suffix */
+#endif /* __int_least8_t */
-#define INT32_C(v) (v)
-#define UINT32_C(v) (v##U)
-#define INT16_C(v) (v)
-#define UINT16_C(v) (v##U)
-#define INT8_C(v) (v)
-#define UINT8_C(v) (v##U)
/* C99 7.18.2.1 Limits of exact-width integer types.
- * Fixed sized values have fixed size max/min.
* C99 7.18.2.2 Limits of minimum-width integer types.
- * Since we map these directly onto fixed-sized types, these values the same.
* C99 7.18.2.3 Limits of fastest minimum-width integer types.
*
+ * The presence of limit macros are completely optional in C99. This
+ * implementation defines limits for all of the types (exact- and
+ * minimum-width) that it defines above, using the limits of the minimum-width
+ * type for any types that do not have exact-width representations.
+ *
+ * As in the type definitions, this section takes an approach of
+ * successive-shrinking to determine which limits to use for the standard (8,
+ * 16, 32, 64) bit widths when they don't have exact representations. It is
+ * therefore important that the defintions be kept in order of decending
+ * widths.
+ *
* Note that C++ should not check __STDC_LIMIT_MACROS here, contrary to the
* claims of the C standard (see C++ 18.3.1p2, [cstdint.syn]).
*/
-/* If we do not have 64-bit support, don't define the 64-bit size macros. */
#ifdef __INT64_TYPE__
-#define INT64_MAX 9223372036854775807LL
-#define INT64_MIN (-9223372036854775807LL-1)
-#define UINT64_MAX 18446744073709551615ULL
-#define INT_LEAST64_MIN INT64_MIN
-#define INT_LEAST64_MAX INT64_MAX
-#define UINT_LEAST64_MAX UINT64_MAX
-#define INT_FAST64_MIN INT64_MIN
-#define INT_FAST64_MAX INT64_MAX
-#define UINT_FAST64_MAX UINT64_MAX
-#endif
-
-#define INT32_MAX 2147483647
-#define INT32_MIN (-2147483647-1)
-#define UINT32_MAX 4294967295U
-#define INT_LEAST32_MIN INT32_MIN
-#define INT_LEAST32_MAX INT32_MAX
-#define UINT_LEAST32_MAX UINT32_MAX
-#define INT_FAST32_MIN INT32_MIN
-#define INT_FAST32_MAX INT32_MAX
-#define UINT_FAST32_MAX UINT32_MAX
-
-#define INT16_MAX 32767
-#define INT16_MIN (-32768)
-#define UINT16_MAX 65535
-#define INT_LEAST16_MIN INT16_MIN
-#define INT_LEAST16_MAX INT16_MAX
-#define UINT_LEAST16_MAX UINT16_MAX
-#define INT_FAST16_MIN INT16_MIN
-#define INT_FAST16_MAX INT16_MAX
-#define UINT_FAST16_MAX UINT16_MAX
-
-#define INT8_MAX 127
-#define INT8_MIN (-128)
-#define UINT8_MAX 255
-#define INT_LEAST8_MIN INT8_MIN
-#define INT_LEAST8_MAX INT8_MAX
-#define UINT_LEAST8_MAX UINT8_MAX
-#define INT_FAST8_MIN INT8_MIN
-#define INT_FAST8_MAX INT8_MAX
-#define UINT_FAST8_MAX UINT8_MAX
+# define INT64_MAX INT64_C( 9223372036854775807)
+# define INT64_MIN (-INT64_C( 9223372036854775807)-1)
+# define UINT64_MAX UINT64_C(18446744073709551615)
+# define __INT_LEAST64_MIN INT64_MIN
+# define __INT_LEAST64_MAX INT64_MAX
+# define __UINT_LEAST64_MAX UINT64_MAX
+# define __INT_LEAST32_MIN INT64_MIN
+# define __INT_LEAST32_MAX INT64_MAX
+# define __UINT_LEAST32_MAX UINT64_MAX
+# define __INT_LEAST16_MIN INT64_MIN
+# define __INT_LEAST16_MAX INT64_MAX
+# define __UINT_LEAST16_MAX UINT64_MAX
+# define __INT_LEAST8_MIN INT64_MIN
+# define __INT_LEAST8_MAX INT64_MAX
+# define __UINT_LEAST8_MAX UINT64_MAX
+#endif /* __INT64_TYPE__ */
+
+#ifdef __INT_LEAST64_MIN
+# define INT_LEAST64_MIN __INT_LEAST64_MIN
+# define INT_LEAST64_MAX __INT_LEAST64_MAX
+# define UINT_LEAST64_MAX __UINT_LEAST64_MAX
+# define INT_FAST64_MIN __INT_LEAST64_MIN
+# define INT_FAST64_MAX __INT_LEAST64_MAX
+# define UINT_FAST64_MAX __UINT_LEAST64_MAX
+#endif /* __INT_LEAST64_MIN */
+
+
+#ifdef __INT56_TYPE__
+# define INT56_MAX INT56_C(36028797018963967)
+# define INT56_MIN (-INT56_C(36028797018963967)-1)
+# define UINT56_MAX UINT56_C(72057594037927935)
+# define INT_LEAST56_MIN INT56_MIN
+# define INT_LEAST56_MAX INT56_MAX
+# define UINT_LEAST56_MAX UINT56_MAX
+# define INT_FAST56_MIN INT56_MIN
+# define INT_FAST56_MAX INT56_MAX
+# define UINT_FAST56_MAX UINT56_MAX
+# define __INT_LEAST32_MIN INT56_MIN
+# define __INT_LEAST32_MAX INT56_MAX
+# define __UINT_LEAST32_MAX UINT56_MAX
+# define __INT_LEAST16_MIN INT56_MIN
+# define __INT_LEAST16_MAX INT56_MAX
+# define __UINT_LEAST16_MAX UINT56_MAX
+# define __INT_LEAST8_MIN INT56_MIN
+# define __INT_LEAST8_MAX INT56_MAX
+# define __UINT_LEAST8_MAX UINT56_MAX
+#endif /* __INT56_TYPE__ */
+
+
+#ifdef __INT48_TYPE__
+# define INT48_MAX INT48_C(140737488355327)
+# define INT48_MIN (-INT48_C(140737488355327)-1)
+# define UINT48_MAX UINT48_C(281474976710655)
+# define INT_LEAST48_MIN INT48_MIN
+# define INT_LEAST48_MAX INT48_MAX
+# define UINT_LEAST48_MAX UINT48_MAX
+# define INT_FAST48_MIN INT48_MIN
+# define INT_FAST48_MAX INT48_MAX
+# define UINT_FAST48_MAX UINT48_MAX
+# define __INT_LEAST32_MIN INT48_MIN
+# define __INT_LEAST32_MAX INT48_MAX
+# define __UINT_LEAST32_MAX UINT48_MAX
+# define __INT_LEAST16_MIN INT48_MIN
+# define __INT_LEAST16_MAX INT48_MAX
+# define __UINT_LEAST16_MAX UINT48_MAX
+# define __INT_LEAST8_MIN INT48_MIN
+# define __INT_LEAST8_MAX INT48_MAX
+# define __UINT_LEAST8_MAX UINT48_MAX
+#endif /* __INT48_TYPE__ */
+
+
+#ifdef __INT40_TYPE__
+# define INT40_MAX INT40_C(549755813887)
+# define INT40_MIN (-INT40_C(549755813887)-1)
+# define UINT40_MAX UINT40_C(1099511627775)
+# define INT_LEAST40_MIN INT40_MIN
+# define INT_LEAST40_MAX INT40_MAX
+# define UINT_LEAST40_MAX UINT40_MAX
+# define INT_FAST40_MIN INT40_MIN
+# define INT_FAST40_MAX INT40_MAX
+# define UINT_FAST40_MAX UINT40_MAX
+# define __INT_LEAST32_MIN INT40_MIN
+# define __INT_LEAST32_MAX INT40_MAX
+# define __UINT_LEAST32_MAX UINT40_MAX
+# define __INT_LEAST16_MIN INT40_MIN
+# define __INT_LEAST16_MAX INT40_MAX
+# define __UINT_LEAST16_MAX UINT40_MAX
+# define __INT_LEAST8_MIN INT40_MIN
+# define __INT_LEAST8_MAX INT40_MAX
+# define __UINT_LEAST8_MAX UINT40_MAX
+#endif /* __INT40_TYPE__ */
+
+
+#ifdef __INT32_TYPE__
+# define INT32_MAX INT32_C(2147483647)
+# define INT32_MIN (-INT32_C(2147483647)-1)
+# define UINT32_MAX UINT32_C(4294967295)
+# define __INT_LEAST32_MIN INT32_MIN
+# define __INT_LEAST32_MAX INT32_MAX
+# define __UINT_LEAST32_MAX UINT32_MAX
+# define __INT_LEAST16_MIN INT32_MIN
+# define __INT_LEAST16_MAX INT32_MAX
+# define __UINT_LEAST16_MAX UINT32_MAX
+# define __INT_LEAST8_MIN INT32_MIN
+# define __INT_LEAST8_MAX INT32_MAX
+# define __UINT_LEAST8_MAX UINT32_MAX
+#endif /* __INT32_TYPE__ */
+
+#ifdef __INT_LEAST32_MIN
+# define INT_LEAST32_MIN __INT_LEAST32_MIN
+# define INT_LEAST32_MAX __INT_LEAST32_MAX
+# define UINT_LEAST32_MAX __UINT_LEAST32_MAX
+# define INT_FAST32_MIN __INT_LEAST32_MIN
+# define INT_FAST32_MAX __INT_LEAST32_MAX
+# define UINT_FAST32_MAX __UINT_LEAST32_MAX
+#endif /* __INT_LEAST32_MIN */
+
+
+#ifdef __INT24_TYPE__
+# define INT24_MAX INT24_C(8388607)
+# define INT24_MIN (-INT24_C(8388607)-1)
+# define UINT24_MAX UINT24_C(16777215)
+# define INT_LEAST24_MIN INT24_MIN
+# define INT_LEAST24_MAX INT24_MAX
+# define UINT_LEAST24_MAX UINT24_MAX
+# define INT_FAST24_MIN INT24_MIN
+# define INT_FAST24_MAX INT24_MAX
+# define UINT_FAST24_MAX UINT24_MAX
+# define __INT_LEAST16_MIN INT24_MIN
+# define __INT_LEAST16_MAX INT24_MAX
+# define __UINT_LEAST16_MAX UINT24_MAX
+# define __INT_LEAST8_MIN INT24_MIN
+# define __INT_LEAST8_MAX INT24_MAX
+# define __UINT_LEAST8_MAX UINT24_MAX
+#endif /* __INT24_TYPE__ */
+
+
+#ifdef __INT16_TYPE__
+#define INT16_MAX INT16_C(32767)
+#define INT16_MIN (-INT16_C(32767)-1)
+#define UINT16_MAX UINT16_C(65535)
+# define __INT_LEAST16_MIN INT16_MIN
+# define __INT_LEAST16_MAX INT16_MAX
+# define __UINT_LEAST16_MAX UINT16_MAX
+# define __INT_LEAST8_MIN INT16_MIN
+# define __INT_LEAST8_MAX INT16_MAX
+# define __UINT_LEAST8_MAX UINT16_MAX
+#endif /* __INT16_TYPE__ */
+
+#ifdef __INT_LEAST16_MIN
+# define INT_LEAST16_MIN __INT_LEAST16_MIN
+# define INT_LEAST16_MAX __INT_LEAST16_MAX
+# define UINT_LEAST16_MAX __UINT_LEAST16_MAX
+# define INT_FAST16_MIN __INT_LEAST16_MIN
+# define INT_FAST16_MAX __INT_LEAST16_MAX
+# define UINT_FAST16_MAX __UINT_LEAST16_MAX
+#endif /* __INT_LEAST16_MIN */
+
+
+#ifdef __INT8_TYPE__
+# define INT8_MAX INT8_C(127)
+# define INT8_MIN (-INT8_C(127)-1)
+# define UINT8_MAX UINT8_C(255)
+# define __INT_LEAST8_MIN INT8_MIN
+# define __INT_LEAST8_MAX INT8_MAX
+# define __UINT_LEAST8_MAX UINT8_MAX
+#endif /* __INT8_TYPE__ */
+
+#ifdef __INT_LEAST8_MIN
+# define INT_LEAST8_MIN __INT_LEAST8_MIN
+# define INT_LEAST8_MAX __INT_LEAST8_MAX
+# define UINT_LEAST8_MAX __UINT_LEAST8_MAX
+# define INT_FAST8_MIN __INT_LEAST8_MIN
+# define INT_FAST8_MAX __INT_LEAST8_MAX
+# define UINT_FAST8_MAX __UINT_LEAST8_MAX
+#endif /* __INT_LEAST8_MIN */
/* C99 7.18.2.4 Limits of integer types capable of holding object pointers. */
/* C99 7.18.3 Limits of other integer types. */
@@ -234,8 +653,8 @@ typedef __UINTMAX_TYPE__ uintmax_t;
#endif
/* 7.18.4.2 Macros for greatest-width integer constants. */
-#define INTMAX_C(v) (v##LL)
-#define UINTMAX_C(v) (v##ULL)
+#define INTMAX_C(v) v##LL
+#define UINTMAX_C(v) v##ULL
#endif /* __STDC_HOSTED__ */
#endif /* __CLANG_STDINT_H */
diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp
index 73b584b..ed905f3 100644
--- a/lib/Index/ResolveLocation.cpp
+++ b/lib/Index/ResolveLocation.cpp
@@ -112,6 +112,7 @@ public:
ASTLocation VisitDeclaratorDecl(DeclaratorDecl *D);
ASTLocation VisitVarDecl(VarDecl *D);
ASTLocation VisitFunctionDecl(FunctionDecl *D);
+ ASTLocation VisitObjCClassDecl(ObjCClassDecl *D);
ASTLocation VisitObjCMethodDecl(ObjCMethodDecl *D);
ASTLocation VisitTypedefDecl(TypedefDecl *D);
ASTLocation VisitDecl(Decl *D);
@@ -327,6 +328,17 @@ ASTLocation DeclLocResolver::VisitVarDecl(VarDecl *D) {
return ASTLocation(D);
}
+ASTLocation DeclLocResolver::VisitObjCClassDecl(ObjCClassDecl *D) {
+ assert(ContainsLocation(D) &&
+ "Should visit only after verifying that loc is in range");
+
+ for (ObjCClassDecl::iterator I = D->begin(), E = D->end() ; I != E; ++I) {
+ if (CheckRange(I->getLocation()) == ContainsLoc)
+ return ASTLocation(D, I->getInterface(), I->getLocation());
+ }
+ return ASTLocation(D);
+}
+
ASTLocation DeclLocResolver::VisitObjCMethodDecl(ObjCMethodDecl *D) {
assert(ContainsLocation(D) &&
"Should visit only after verifying that loc is in range");
@@ -484,7 +496,7 @@ ASTLocation LocResolverBase::ResolveInDeclarator(Decl *D, Stmt *Stm,
assert(ContainsLocation(DInfo) &&
"Should visit only after verifying that loc is in range");
- TypeLocResolver(Ctx, Loc, D);
+ (void)TypeLocResolver(Ctx, Loc, D);
for (TypeLoc TL = DInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc())
if (ContainsLocation(TL))
return TypeLocResolver(Ctx, Loc, D).Visit(TL);
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index c8b9a5d..f4a4432 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -384,10 +384,10 @@ static inline bool isNumberBody(unsigned char c) {
/// lexer buffer was all instantiated at a single point, perform the mapping.
/// This is currently only used for _Pragma implementation, so it is the slow
/// path of the hot getSourceLocation method. Do not allow it to be inlined.
-static SourceLocation GetMappedTokenLoc(Preprocessor &PP,
- SourceLocation FileLoc,
- unsigned CharNo,
- unsigned TokLen) DISABLE_INLINE;
+static DISABLE_INLINE SourceLocation GetMappedTokenLoc(Preprocessor &PP,
+ SourceLocation FileLoc,
+ unsigned CharNo,
+ unsigned TokLen);
static SourceLocation GetMappedTokenLoc(Preprocessor &PP,
SourceLocation FileLoc,
unsigned CharNo, unsigned TokLen) {
diff --git a/lib/Lex/PPCaching.cpp b/lib/Lex/PPCaching.cpp
index c3f0eea..7c3780f 100644
--- a/lib/Lex/PPCaching.cpp
+++ b/lib/Lex/PPCaching.cpp
@@ -109,6 +109,4 @@ void Preprocessor::AnnotatePreviousCachedTokens(const Token &Tok) {
return;
}
}
-
- assert(0&&"Didn't find the first token represented by the annotation token!");
}
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index a74396c..b54dfe0 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -228,7 +228,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
return true; // A diagnostic was already emitted.
// Character literals are always int or wchar_t, expand to intmax_t.
- TargetInfo &TI = PP.getTargetInfo();
+ const TargetInfo &TI = PP.getTargetInfo();
unsigned NumBits;
if (Literal.isMultiChar())
NumBits = TI.getIntWidth();
diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp
index f17a5d9..d6a73cc 100644
--- a/lib/Lex/PTHLexer.cpp
+++ b/lib/Lex/PTHLexer.cpp
@@ -15,6 +15,7 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/PTHLexer.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PTHManager.h"
@@ -407,27 +408,17 @@ PTHManager::~PTHManager() {
free(PerIDCache);
}
-static void InvalidPTH(Diagnostic *Diags, Diagnostic::Level level,
- const char* Msg = 0) {
- if (!Diags) return;
- if (!Msg) Msg = "Invalid or corrupted PTH file";
- unsigned DiagID = Diags->getCustomDiagID(level, Msg);
- Diags->Report(FullSourceLoc(), DiagID);
+static void InvalidPTH(Diagnostic &Diags, const char *Msg) {
+ Diags.Report(Diags.getCustomDiagID(Diagnostic::Error, Msg));
}
-PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags,
- Diagnostic::Level level) {
+PTHManager* PTHManager::Create(const std::string& file, Diagnostic &Diags) {
// Memory map the PTH file.
llvm::OwningPtr<llvm::MemoryBuffer>
File(llvm::MemoryBuffer::getFile(file.c_str()));
if (!File) {
- if (Diags) {
- unsigned DiagID = Diags->getCustomDiagID(level,
- "PTH file %0 could not be read");
- Diags->Report(FullSourceLoc(), DiagID) << file;
- }
-
+ Diags.Report(diag::err_invalid_pth_file) << file;
return 0;
}
@@ -439,7 +430,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags,
// Check the prologue of the file.
if ((BufEnd - BufBeg) < (signed) (sizeof("cfe-pth") + 3 + 4) ||
memcmp(BufBeg, "cfe-pth", sizeof("cfe-pth") - 1) != 0) {
- InvalidPTH(Diags, level);
+ Diags.Report(diag::err_invalid_pth_file) << file;
return 0;
}
@@ -447,8 +438,8 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags,
const unsigned char *p = BufBeg + (sizeof("cfe-pth") - 1);
unsigned Version = ReadLE32(p);
- if (Version != PTHManager::Version) {
- InvalidPTH(Diags, level,
+ if (Version < PTHManager::Version) {
+ InvalidPTH(Diags,
Version < PTHManager::Version
? "PTH file uses an older PTH format that is no longer supported"
: "PTH file uses a newer PTH format that cannot be read");
@@ -459,7 +450,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags,
const unsigned char *PrologueOffset = p;
if (PrologueOffset >= BufEnd) {
- InvalidPTH(Diags, level);
+ Diags.Report(diag::err_invalid_pth_file) << file;
return 0;
}
@@ -469,7 +460,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags,
const unsigned char* FileTable = BufBeg + ReadLE32(FileTableOffset);
if (!(FileTable > BufBeg && FileTable < BufEnd)) {
- InvalidPTH(Diags, level);
+ Diags.Report(diag::err_invalid_pth_file) << file;
return 0; // FIXME: Proper error diagnostic?
}
@@ -478,7 +469,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags,
// Warn if the PTH file is empty. We still want to create a PTHManager
// as the PTH could be used with -include-pth.
if (FL->isEmpty())
- InvalidPTH(Diags, level, "PTH file contains no cached source data");
+ InvalidPTH(Diags, "PTH file contains no cached source data");
// Get the location of the table mapping from persistent ids to the
// data needed to reconstruct identifiers.
@@ -486,7 +477,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags,
const unsigned char* IData = BufBeg + ReadLE32(IDTableOffset);
if (!(IData >= BufBeg && IData < BufEnd)) {
- InvalidPTH(Diags, level);
+ Diags.Report(diag::err_invalid_pth_file) << file;
return 0;
}
@@ -495,7 +486,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags,
const unsigned char* StringIdTableOffset = PrologueOffset + sizeof(uint32_t)*1;
const unsigned char* StringIdTable = BufBeg + ReadLE32(StringIdTableOffset);
if (!(StringIdTable >= BufBeg && StringIdTable < BufEnd)) {
- InvalidPTH(Diags, level);
+ Diags.Report(diag::err_invalid_pth_file) << file;
return 0;
}
@@ -506,7 +497,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags,
const unsigned char* spellingBaseOffset = PrologueOffset + sizeof(uint32_t)*3;
const unsigned char* spellingBase = BufBeg + ReadLE32(spellingBaseOffset);
if (!(spellingBase >= BufBeg && spellingBase < BufEnd)) {
- InvalidPTH(Diags, level);
+ Diags.Report(diag::err_invalid_pth_file) << file;
return 0;
}
@@ -521,8 +512,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags,
if (NumIds) {
PerIDCache = (IdentifierInfo**)calloc(NumIds, sizeof(*PerIDCache));
if (!PerIDCache) {
- InvalidPTH(Diags, level,
- "Could not allocate memory for processing PTH file");
+ InvalidPTH(Diags, "Could not allocate memory for processing PTH file");
return 0;
}
}
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 487b9d6..0669094 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -44,14 +44,16 @@ using namespace clang;
//===----------------------------------------------------------------------===//
Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
- TargetInfo &target, SourceManager &SM,
+ const TargetInfo &target, SourceManager &SM,
HeaderSearch &Headers,
- IdentifierInfoLookup* IILookup)
+ IdentifierInfoLookup* IILookup,
+ bool OwnsHeaders)
: Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()),
SourceMgr(SM), HeaderInfo(Headers), Identifiers(opts, IILookup),
BuiltinInfo(Target), CurPPLexer(0), CurDirLookup(0), Callbacks(0) {
ScratchBuf = new ScratchBuffer(SourceMgr);
CounterValue = 0; // __COUNTER__ starts at 0.
+ OwnsHeaderSearch = OwnsHeaders;
// Clear stats.
NumDirectives = NumDefined = NumUndefined = NumPragma = 0;
@@ -115,6 +117,10 @@ Preprocessor::~Preprocessor() {
// Delete the scratch buffer info.
delete ScratchBuf;
+ // Delete the header search info, if we own it.
+ if (OwnsHeaderSearch)
+ delete &HeaderInfo;
+
delete Callbacks;
}
@@ -186,13 +192,14 @@ void Preprocessor::PrintStats() {
// Token Spelling
//===----------------------------------------------------------------------===//
-
/// getSpelling() - Return the 'spelling' of this token. The spelling of a
/// token are the characters used to represent the token in the source file
/// after trigraph expansion and escaped-newline folding. In particular, this
/// wants to get the true, uncanonicalized, spelling of things like digraphs
/// UCNs, etc.
-std::string Preprocessor::getSpelling(const Token &Tok) const {
+std::string Preprocessor::getSpelling(const Token &Tok,
+ const SourceManager &SourceMgr,
+ const LangOptions &Features) {
assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
// If this token contains nothing interesting, return it directly.
@@ -215,6 +222,15 @@ std::string Preprocessor::getSpelling(const Token &Tok) const {
return Result;
}
+/// getSpelling() - Return the 'spelling' of this token. The spelling of a
+/// token are the characters used to represent the token in the source file
+/// after trigraph expansion and escaped-newline folding. In particular, this
+/// wants to get the true, uncanonicalized, spelling of things like digraphs
+/// UCNs, etc.
+std::string Preprocessor::getSpelling(const Token &Tok) const {
+ return getSpelling(Tok, SourceMgr, Features);
+}
+
/// getSpelling - This method is used to get the spelling of a token into a
/// preallocated buffer, instead of as an std::string. The caller is required
/// to allocate enough space for the token, which is guaranteed to be at least
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
index 344ce9e..dde4bc8 100644
--- a/lib/Parse/AttributeList.cpp
+++ b/lib/Parse/AttributeList.cpp
@@ -59,6 +59,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("mode", AT_mode)
.Case("used", AT_used)
.Case("alias", AT_alias)
+ .Case("cdecl", AT_cdecl)
.Case("const", AT_const)
.Case("packed", AT_packed)
.Case("malloc", AT_malloc)
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index 0a4e036..f00f33f 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -13,6 +13,7 @@
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Template.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/STLExtras.h"
@@ -26,6 +27,15 @@ static DiagnosticBuilder Diag(Diagnostic &D, SourceLocation Loc,
return D.Report(FullSourceLoc(Loc, SrcMgr), DiagID);
}
+
+void UnqualifiedId::setTemplateId(TemplateIdAnnotation *TemplateId) {
+ assert(TemplateId && "NULL template-id annotation?");
+ Kind = IK_TemplateId;
+ this->TemplateId = TemplateId;
+ StartLocation = TemplateId->TemplateNameLoc;
+ EndLocation = TemplateId->RAngleLoc;
+}
+
/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
/// "TheDeclarator" is the declarator that this will be added to.
DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index bf05b2b..7681eac 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/lib/Parse/MinimalAction.cpp
@@ -49,7 +49,8 @@ Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope,
const CXXScopeSpec &SS,
UnqualifiedId &Name,
AttributeList *AttrList,
- bool IsTypeName) {
+ bool IsTypeName,
+ SourceLocation TypenameLoc) {
// FIXME: Parser seems to assume that Action::ActOn* takes ownership over
// passed AttributeList, however other actions don't free it, is it
@@ -213,7 +214,9 @@ MinimalAction::ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
/// Scope will always be top level file scope.
Action::DeclPtrTy
MinimalAction::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
- IdentifierInfo **IdentList, unsigned NumElts) {
+ IdentifierInfo **IdentList,
+ SourceLocation *IdentLocs,
+ unsigned NumElts) {
for (unsigned i = 0; i != NumElts; ++i) {
// Allocate and add the 'TypeNameInfo' "decl".
getTable(TypeNameInfoTablePtr)->AddEntry(true, IdentList[i]);
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 99752b5..2bfda30 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -14,6 +14,7 @@
#include "clang/Parse/Parser.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Scope.h"
+#include "clang/Parse/Template.h"
#include "ExtensionRAIIObject.h"
#include "llvm/ADT/SmallSet.h"
using namespace clang;
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 154c292..914bfc9 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -16,6 +16,7 @@
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
+#include "clang/Parse/Template.h"
#include "ExtensionRAIIObject.h"
using namespace clang;
@@ -282,11 +283,13 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
SourceLocation &DeclEnd,
AccessSpecifier AS) {
CXXScopeSpec SS;
+ SourceLocation TypenameLoc;
bool IsTypeName;
// Ignore optional 'typename'.
// FIXME: This is wrong; we should parse this as a typename-specifier.
if (Tok.is(tok::kw_typename)) {
+ TypenameLoc = Tok.getLocation();
ConsumeToken();
IsTypeName = true;
}
@@ -329,7 +332,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
tok::semi);
return Actions.ActOnUsingDeclaration(CurScope, AS, UsingLoc, SS, Name,
- AttrList, IsTypeName);
+ AttrList, IsTypeName, TypenameLoc);
}
/// ParseStaticAssertDeclaration - Parse C++0x static_assert-declaratoion.
@@ -586,13 +589,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Eat the template argument list and try to continue parsing this as
// a class (or template thereof).
TemplateArgList TemplateArgs;
- TemplateArgIsTypeList TemplateArgIsType;
- TemplateArgLocationList TemplateArgLocations;
SourceLocation LAngleLoc, RAngleLoc;
if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, &SS,
true, LAngleLoc,
- TemplateArgs, TemplateArgIsType,
- TemplateArgLocations, RAngleLoc)) {
+ TemplateArgs, RAngleLoc)) {
// We couldn't parse the template argument list at all, so don't
// try to give any location information for the list.
LAngleLoc = RAngleLoc = SourceLocation();
@@ -704,7 +704,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// or explicit instantiation.
ASTTemplateArgsPtr TemplateArgsPtr(Actions,
TemplateId->getTemplateArgs(),
- TemplateId->getTemplateArgIsType(),
TemplateId->NumArgs);
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
TUK == Action::TUK_Declaration) {
@@ -720,7 +719,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
- TemplateId->getTemplateArgLocations(),
TemplateId->RAngleLoc,
Attr);
} else if (TUK == Action::TUK_Reference) {
@@ -729,7 +727,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
- TemplateId->getTemplateArgLocations(),
TemplateId->RAngleLoc);
TypeResult = Actions.ActOnTagTemplateIdType(TypeResult, TUK,
@@ -777,7 +774,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
- TemplateId->getTemplateArgLocations(),
TemplateId->RAngleLoc,
Attr,
Action::MultiTemplateParamsArg(Actions,
@@ -1304,7 +1300,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// Check for extraneous top-level semicolon.
if (Tok.is(tok::semi)) {
- Diag(Tok, diag::ext_extra_struct_semi);
+ Diag(Tok, diag::ext_extra_struct_semi)
+ << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation()));
ConsumeToken();
continue;
}
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index a00dfb0..b2ecc9e 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -14,6 +14,7 @@
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Template.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -108,52 +109,43 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
if (!HasScopeSpecifier && !ObjectType)
break;
+ TentativeParsingAction TPA(*this);
SourceLocation TemplateKWLoc = ConsumeToken();
UnqualifiedId TemplateName;
if (Tok.is(tok::identifier)) {
- TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
-
- // If the next token is not '<', we may have a stray 'template' keyword.
- // Complain and suggest removing the template keyword, but otherwise
- // allow parsing to continue.
- if (NextToken().isNot(tok::less)) {
- Diag(NextToken().getLocation(),
- diag::err_less_after_template_name_in_nested_name_spec)
- << Tok.getIdentifierInfo()->getName()
- << CodeModificationHint::CreateRemoval(SourceRange(TemplateKWLoc));
- break;
- }
-
// Consume the identifier.
+ TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
ConsumeToken();
} else if (Tok.is(tok::kw_operator)) {
if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType,
- TemplateName))
+ TemplateName)) {
+ TPA.Commit();
break;
+ }
if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId) {
Diag(TemplateName.getSourceRange().getBegin(),
diag::err_id_after_template_in_nested_name_spec)
<< TemplateName.getSourceRange();
- break;
- } else if (Tok.isNot(tok::less)) {
- std::string OperatorName = "operator ";
- OperatorName += getOperatorSpelling(
- TemplateName.OperatorFunctionId.Operator);
- Diag(Tok.getLocation(),
- diag::err_less_after_template_name_in_nested_name_spec)
- << OperatorName
- << TemplateName.getSourceRange();
+ TPA.Commit();
break;
}
} else {
- Diag(Tok.getLocation(),
- diag::err_id_after_template_in_nested_name_spec)
- << SourceRange(TemplateKWLoc);
+ TPA.Revert();
break;
}
+ // If the next token is not '<', we have a qualified-id that refers
+ // to a template name, such as T::template apply, but is not a
+ // template-id.
+ if (Tok.isNot(tok::less)) {
+ TPA.Revert();
+ break;
+ }
+
+ // Commit to parsing the template-id.
+ TPA.Commit();
TemplateTy Template
= Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName,
ObjectType);
@@ -381,13 +373,7 @@ Parser::OwningExprResult Parser::ParseCXXCasts() {
OwningExprResult Result = ParseExpression();
// Match the ')'.
- if (Result.isInvalid())
- SkipUntil(tok::r_paren);
-
- if (Tok.is(tok::r_paren))
- RParenLoc = ConsumeParen();
- else
- MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
if (!Result.isInvalid() && !CastTy.isInvalid())
Result = Actions.ActOnCXXNamedCast(OpLoc, Kind,
@@ -820,13 +806,9 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
// Parse the enclosed template argument list.
SourceLocation LAngleLoc, RAngleLoc;
TemplateArgList TemplateArgs;
- TemplateArgIsTypeList TemplateArgIsType;
- TemplateArgLocationList TemplateArgLocations;
if (ParseTemplateIdAfterTemplateName(Template, Id.StartLocation,
&SS, true, LAngleLoc,
TemplateArgs,
- TemplateArgIsType,
- TemplateArgLocations,
RAngleLoc))
return true;
@@ -851,15 +833,10 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
TemplateId->Kind = TNK;
TemplateId->LAngleLoc = LAngleLoc;
TemplateId->RAngleLoc = RAngleLoc;
- void **Args = TemplateId->getTemplateArgs();
- bool *ArgIsType = TemplateId->getTemplateArgIsType();
- SourceLocation *ArgLocs = TemplateId->getTemplateArgLocations();
+ ParsedTemplateArgument *Args = TemplateId->getTemplateArgs();
for (unsigned Arg = 0, ArgEnd = TemplateArgs.size();
- Arg != ArgEnd; ++Arg) {
+ Arg != ArgEnd; ++Arg)
Args[Arg] = TemplateArgs[Arg];
- ArgIsType[Arg] = TemplateArgIsType[Arg];
- ArgLocs[Arg] = TemplateArgLocations[Arg];
- }
Id.setTemplateId(TemplateId);
return false;
@@ -867,14 +844,12 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
// Bundle the template arguments together.
ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(),
- TemplateArgIsType.data(),
TemplateArgs.size());
// Constructor and destructor names.
Action::TypeResult Type
= Actions.ActOnTemplateIdType(Template, NameLoc,
LAngleLoc, TemplateArgsPtr,
- &TemplateArgLocations[0],
RAngleLoc);
if (Type.isInvalid())
return true;
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index b043dd99..65bd79d 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -61,6 +61,8 @@ Parser::DeclPtrTy Parser::ParseObjCAtDirectives() {
Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
ConsumeToken(); // the identifier "class"
llvm::SmallVector<IdentifierInfo *, 8> ClassNames;
+ llvm::SmallVector<SourceLocation, 8> ClassLocs;
+
while (1) {
if (Tok.isNot(tok::identifier)) {
@@ -69,6 +71,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
return DeclPtrTy();
}
ClassNames.push_back(Tok.getIdentifierInfo());
+ ClassLocs.push_back(Tok.getLocation());
ConsumeToken();
if (Tok.isNot(tok::comma))
@@ -81,8 +84,9 @@ Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class"))
return DeclPtrTy();
- return Actions.ActOnForwardClassDeclaration(atLoc,
- &ClassNames[0], ClassNames.size());
+ return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
+ ClassLocs.data(),
+ ClassNames.size());
}
///
@@ -123,6 +127,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
Diag(Tok, diag::err_expected_ident); // missing class or category name.
return DeclPtrTy();
}
+
// We have a class or category name - consume it.
IdentifierInfo *nameId = Tok.getIdentifierInfo();
SourceLocation nameLoc = ConsumeToken();
@@ -829,6 +834,12 @@ ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &Protocols,
llvm::SmallVector<IdentifierLocPair, 8> ProtocolIdents;
while (1) {
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents.data(),
+ ProtocolIdents.size());
+ ConsumeToken();
+ }
+
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
SkipUntil(tok::greater);
@@ -895,7 +906,8 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
// Check for extraneous top-level semicolon.
if (Tok.is(tok::semi)) {
- Diag(Tok, diag::ext_extra_struct_semi);
+ Diag(Tok, diag::ext_extra_struct_semi)
+ << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation()));
ConsumeToken();
continue;
}
@@ -982,6 +994,11 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
"ParseObjCAtProtocolDeclaration(): Expected @protocol");
ConsumeToken(); // the "protocol" identifier
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteObjCProtocolDecl(CurScope);
+ ConsumeToken();
+ }
+
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); // missing protocol name.
return DeclPtrTy();
@@ -1092,6 +1109,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
atLoc, nameId, nameLoc, categoryId,
categoryLoc);
ObjCImpDecl = ImplCatType;
+ PendingObjCImpDecl.push_back(ObjCImpDecl);
return DeclPtrTy();
}
// We have a class implementation
@@ -1114,7 +1132,8 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
if (Tok.is(tok::l_brace)) // we have ivars
ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/, atLoc);
ObjCImpDecl = ImplClsType;
-
+ PendingObjCImpDecl.push_back(ObjCImpDecl);
+
return DeclPtrTy();
}
@@ -1126,12 +1145,21 @@ Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceLocation atLoc) {
if (ObjCImpDecl) {
Actions.ActOnAtEnd(atLoc, ObjCImpDecl);
ObjCImpDecl = DeclPtrTy();
+ PendingObjCImpDecl.pop_back();
}
else
Diag(atLoc, diag::warn_expected_implementation); // missing @implementation
return Result;
}
+Parser::DeclGroupPtrTy Parser::RetrievePendingObjCImpDecl() {
+ if (PendingObjCImpDecl.empty())
+ return Actions.ConvertDeclToDeclGroup(DeclPtrTy());
+ DeclPtrTy ImpDecl = PendingObjCImpDecl.pop_back_val();
+ Actions.ActOnAtEnd(SourceLocation(), ImpDecl);
+ return Actions.ConvertDeclToDeclGroup(ImpDecl);
+}
+
/// compatibility-alias-decl:
/// @compatibility_alias alias-name class-name ';'
///
@@ -1201,6 +1229,8 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
}
if (Tok.isNot(tok::semi))
Diag(Tok, diag::err_expected_semi_after) << "@synthesize";
+ else
+ ConsumeToken(); // consume ';'
return DeclPtrTy();
}
@@ -1406,8 +1436,10 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() {
// parse optional ';'
if (Tok.is(tok::semi)) {
- if (ObjCImpDecl)
- Diag(Tok, diag::warn_semicolon_before_method_nody);
+ if (ObjCImpDecl) {
+ Diag(Tok, diag::warn_semicolon_before_method_body)
+ << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation()));
+ }
ConsumeToken();
}
@@ -1546,6 +1578,13 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
SourceLocation NameLoc,
IdentifierInfo *ReceiverName,
ExprArg ReceiverExpr) {
+ if (Tok.is(tok::code_completion)) {
+ if (ReceiverName)
+ Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverName, NameLoc);
+ else
+ Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get());
+ ConsumeToken();
+ }
// Parse objc-selector
SourceLocation Loc;
IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc);
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 9957883..16b1c80 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -15,6 +15,7 @@
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
+#include "clang/Parse/Template.h"
#include "llvm/Support/Compiler.h"
using namespace clang;
@@ -484,12 +485,17 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
// Get the a default value, if given.
if (Tok.is(tok::equal)) {
SourceLocation EqualLoc = ConsumeToken();
- OwningExprResult DefaultExpr = ParseCXXIdExpression();
- if (DefaultExpr.isInvalid())
+ ParsedTemplateArgument Default = ParseTemplateTemplateArgument();
+ if (Default.isInvalid()) {
+ Diag(Tok.getLocation(),
+ diag::err_default_template_template_parameter_not_template);
+ static tok::TokenKind EndToks[] = {
+ tok::comma, tok::greater, tok::greatergreater
+ };
+ SkipUntil(EndToks, 3, true, true);
return Param;
- else if (Param)
- Actions.ActOnTemplateTemplateParameterDefault(Param, EqualLoc,
- move(DefaultExpr));
+ } else if (Param)
+ Actions.ActOnTemplateTemplateParameterDefault(Param, EqualLoc, Default);
}
return Param;
@@ -582,8 +588,6 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
bool ConsumeLastToken,
SourceLocation &LAngleLoc,
TemplateArgList &TemplateArgs,
- TemplateArgIsTypeList &TemplateArgIsType,
- TemplateArgLocationList &TemplateArgLocations,
SourceLocation &RAngleLoc) {
assert(Tok.is(tok::less) && "Must have already parsed the template-name");
@@ -595,8 +599,7 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
{
GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
if (Tok.isNot(tok::greater))
- Invalid = ParseTemplateArgumentList(TemplateArgs, TemplateArgIsType,
- TemplateArgLocations);
+ Invalid = ParseTemplateArgumentList(TemplateArgs);
if (Invalid) {
// Try to find the closing '>'.
@@ -688,14 +691,10 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
// Parse the enclosed template argument list.
SourceLocation LAngleLoc, RAngleLoc;
TemplateArgList TemplateArgs;
- TemplateArgIsTypeList TemplateArgIsType;
- TemplateArgLocationList TemplateArgLocations;
bool Invalid = ParseTemplateIdAfterTemplateName(Template,
TemplateNameLoc,
SS, false, LAngleLoc,
TemplateArgs,
- TemplateArgIsType,
- TemplateArgLocations,
RAngleLoc);
if (Invalid) {
@@ -707,7 +706,6 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
}
ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(),
- TemplateArgIsType.data(),
TemplateArgs.size());
// Build the annotation token.
@@ -715,7 +713,6 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
Action::TypeResult Type
= Actions.ActOnTemplateIdType(Template, TemplateNameLoc,
LAngleLoc, TemplateArgsPtr,
- &TemplateArgLocations[0],
RAngleLoc);
if (Type.isInvalid()) {
// If we failed to parse the template ID but skipped ahead to a >, we're not
@@ -751,14 +748,9 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
TemplateId->Kind = TNK;
TemplateId->LAngleLoc = LAngleLoc;
TemplateId->RAngleLoc = RAngleLoc;
- void **Args = TemplateId->getTemplateArgs();
- bool *ArgIsType = TemplateId->getTemplateArgIsType();
- SourceLocation *ArgLocs = TemplateId->getTemplateArgLocations();
- for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) {
+ ParsedTemplateArgument *Args = TemplateId->getTemplateArgs();
+ for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg)
Args[Arg] = TemplateArgs[Arg];
- ArgIsType[Arg] = TemplateArgIsType[Arg];
- ArgLocs[Arg] = TemplateArgLocations[Arg];
- }
Tok.setAnnotationValue(TemplateId);
if (TemplateKWLoc.isValid())
Tok.setLocation(TemplateKWLoc);
@@ -794,7 +786,6 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) {
ASTTemplateArgsPtr TemplateArgsPtr(Actions,
TemplateId->getTemplateArgs(),
- TemplateId->getTemplateArgIsType(),
TemplateId->NumArgs);
Action::TypeResult Type
@@ -802,7 +793,6 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) {
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
- TemplateId->getTemplateArgLocations(),
TemplateId->RAngleLoc);
// Create the new "type" annotation token.
Tok.setKind(tok::annot_typename);
@@ -817,33 +807,125 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) {
TemplateId->Destroy();
}
+/// \brief Determine whether the given token can end a template argument.
+static bool isEndOfTemplateArgument(Token Tok) {
+ return Tok.is(tok::comma) || Tok.is(tok::greater) ||
+ Tok.is(tok::greatergreater);
+}
+
+/// \brief Parse a C++ template template argument.
+ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
+ if (!Tok.is(tok::identifier) && !Tok.is(tok::coloncolon) &&
+ !Tok.is(tok::annot_cxxscope))
+ return ParsedTemplateArgument();
+
+ // C++0x [temp.arg.template]p1:
+ // A template-argument for a template template-parameter shall be the name
+ // of a class template or a template alias, expressed as id-expression.
+ //
+ // We parse an id-expression that refers to a class template or template
+ // alias. The grammar we parse is:
+ //
+ // nested-name-specifier[opt] template[opt] identifier
+ //
+ // followed by a token that terminates a template argument, such as ',',
+ // '>', or (in some cases) '>>'.
+ CXXScopeSpec SS; // nested-name-specifier, if present
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0,
+ /*EnteringContext=*/false);
+
+ if (SS.isSet() && Tok.is(tok::kw_template)) {
+ // Parse the optional 'template' keyword following the
+ // nested-name-specifier.
+ SourceLocation TemplateLoc = ConsumeToken();
+
+ if (Tok.is(tok::identifier)) {
+ // We appear to have a dependent template name.
+ UnqualifiedId Name;
+ Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
+ ConsumeToken(); // the identifier
+
+ // If the next token signals the end of a template argument,
+ // then we have a dependent template name that could be a template
+ // template argument.
+ if (isEndOfTemplateArgument(Tok)) {
+ TemplateTy Template
+ = Actions.ActOnDependentTemplateName(TemplateLoc, SS, Name,
+ /*ObjectType=*/0);
+ if (Template.get())
+ return ParsedTemplateArgument(SS, Template, Name.StartLocation);
+ }
+ }
+ } else if (Tok.is(tok::identifier)) {
+ // We may have a (non-dependent) template name.
+ TemplateTy Template;
+ UnqualifiedId Name;
+ Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
+ ConsumeToken(); // the identifier
+
+ if (isEndOfTemplateArgument(Tok)) {
+ TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS, Name,
+ /*ObjectType=*/0,
+ /*EnteringContext=*/false,
+ Template);
+ if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) {
+ // We have an id-expression that refers to a class template or
+ // (C++0x) template alias.
+ return ParsedTemplateArgument(SS, Template, Name.StartLocation);
+ }
+ }
+ }
+
+ // We don't have a template template argument.
+ return ParsedTemplateArgument();
+}
+
/// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]).
///
/// template-argument: [C++ 14.2]
/// constant-expression
/// type-id
/// id-expression
-void *Parser::ParseTemplateArgument(bool &ArgIsType) {
+ParsedTemplateArgument Parser::ParseTemplateArgument() {
// C++ [temp.arg]p2:
// In a template-argument, an ambiguity between a type-id and an
// expression is resolved to a type-id, regardless of the form of
// the corresponding template-parameter.
//
- // Therefore, we initially try to parse a type-id.
+ // Therefore, we initially try to parse a type-id.
if (isCXXTypeId(TypeIdAsTemplateArgument)) {
- ArgIsType = true;
+ SourceLocation Loc = Tok.getLocation();
TypeResult TypeArg = ParseTypeName();
if (TypeArg.isInvalid())
- return 0;
- return TypeArg.get();
+ return ParsedTemplateArgument();
+
+ return ParsedTemplateArgument(ParsedTemplateArgument::Type, TypeArg.get(),
+ Loc);
}
+
+ // Try to parse a template template argument.
+ {
+ TentativeParsingAction TPA(*this);
+ ParsedTemplateArgument TemplateTemplateArgument
+ = ParseTemplateTemplateArgument();
+ if (!TemplateTemplateArgument.isInvalid()) {
+ TPA.Commit();
+ return TemplateTemplateArgument;
+ }
+
+ // Revert this tentative parse to parse a non-type template argument.
+ TPA.Revert();
+ }
+
+ // Parse a non-type template argument.
+ SourceLocation Loc = Tok.getLocation();
OwningExprResult ExprArg = ParseConstantExpression();
if (ExprArg.isInvalid() || !ExprArg.get())
- return 0;
+ return ParsedTemplateArgument();
- ArgIsType = false;
- return ExprArg.release();
+ return ParsedTemplateArgument(ParsedTemplateArgument::NonType,
+ ExprArg.release(), Loc);
}
/// ParseTemplateArgumentList - Parse a C++ template-argument-list
@@ -853,22 +935,17 @@ void *Parser::ParseTemplateArgument(bool &ArgIsType) {
/// template-argument
/// template-argument-list ',' template-argument
bool
-Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
- TemplateArgIsTypeList &TemplateArgIsType,
- TemplateArgLocationList &TemplateArgLocations) {
+Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
while (true) {
- bool IsType = false;
- SourceLocation Loc = Tok.getLocation();
- void *Arg = ParseTemplateArgument(IsType);
- if (Arg) {
- TemplateArgs.push_back(Arg);
- TemplateArgIsType.push_back(IsType);
- TemplateArgLocations.push_back(Loc);
- } else {
+ ParsedTemplateArgument Arg = ParseTemplateArgument();
+ if (Arg.isInvalid()) {
SkipUntil(tok::comma, tok::greater, true, true);
return true;
}
+ // Save this template argument.
+ TemplateArgs.push_back(Arg);
+
// If the next token is a comma, consume it and keep reading
// arguments.
if (Tok.isNot(tok::comma)) break;
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 335a6cf..a915274 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -15,6 +15,7 @@
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
+#include "clang/Parse/Template.h"
#include "llvm/Support/raw_ostream.h"
#include "ExtensionRAIIObject.h"
#include "ParsePragma.h"
diff --git a/lib/Rewrite/DeltaTree.cpp b/lib/Rewrite/DeltaTree.cpp
index a94444b..101cf93 100644
--- a/lib/Rewrite/DeltaTree.cpp
+++ b/lib/Rewrite/DeltaTree.cpp
@@ -19,12 +19,6 @@ using namespace clang;
using llvm::cast;
using llvm::dyn_cast;
-namespace {
- struct SourceDelta;
- class DeltaTreeNode;
- class DeltaTreeInteriorNode;
-}
-
/// The DeltaTree class is a multiway search tree (BTree) structure with some
/// fancy features. B-Trees are are generally more memory and cache efficient
/// than binary trees, because they store multiple keys/values in each node.
@@ -55,21 +49,17 @@ namespace {
return Delta;
}
};
-} // end anonymous namespace
-
-
-namespace {
- struct InsertResult {
- DeltaTreeNode *LHS, *RHS;
- SourceDelta Split;
- };
-} // end anonymous namespace
-
-
-namespace {
+
/// DeltaTreeNode - The common part of all nodes.
///
class DeltaTreeNode {
+ public:
+ struct InsertResult {
+ DeltaTreeNode *LHS, *RHS;
+ SourceDelta Split;
+ };
+
+ private:
friend class DeltaTreeInteriorNode;
/// WidthFactor - This controls the number of K/V slots held in the BTree:
@@ -473,7 +463,7 @@ void DeltaTree::AddDelta(unsigned FileIndex, int Delta) {
assert(Delta && "Adding a noop?");
DeltaTreeNode *MyRoot = getRoot(Root);
- InsertResult InsertRes;
+ DeltaTreeNode::InsertResult InsertRes;
if (MyRoot->DoInsertion(FileIndex, Delta, &InsertRes)) {
Root = MyRoot = new DeltaTreeInteriorNode(InsertRes);
}
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index 9b24d55..88ac4e4 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -16,28 +16,79 @@
#include "clang/Lex/Preprocessor.h"
#include "Sema.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstring>
#include <functional>
+
using namespace clang;
+using llvm::StringRef;
//===----------------------------------------------------------------------===//
// Code completion string implementation
//===----------------------------------------------------------------------===//
-CodeCompletionString::Chunk::Chunk(ChunkKind Kind, const char *Text)
- : Kind(Kind), Text(0)
+CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text)
+ : Kind(Kind), Text("")
{
- assert((Kind == CK_Text || Kind == CK_Placeholder || Kind == CK_Informative)
- && "Invalid text chunk kind");
- char *New = new char [std::strlen(Text) + 1];
- std::strcpy(New, Text);
- this->Text = New;
+ switch (Kind) {
+ case CK_TypedText:
+ case CK_Text:
+ case CK_Placeholder:
+ case CK_Informative:
+ case CK_CurrentParameter: {
+ char *New = new char [Text.size() + 1];
+ std::memcpy(New, Text.data(), Text.size());
+ New[Text.size()] = '\0';
+ this->Text = New;
+ break;
+ }
+
+ case CK_Optional:
+ llvm::llvm_unreachable("Optional strings cannot be created from text");
+ break;
+
+ case CK_LeftParen:
+ this->Text = "(";
+ break;
+
+ case CK_RightParen:
+ this->Text = ")";
+ break;
+
+ case CK_LeftBracket:
+ this->Text = "[";
+ break;
+
+ case CK_RightBracket:
+ this->Text = "]";
+ break;
+
+ case CK_LeftBrace:
+ this->Text = "{";
+ break;
+
+ case CK_RightBrace:
+ this->Text = "}";
+ break;
+
+ case CK_LeftAngle:
+ this->Text = "<";
+ break;
+
+ case CK_RightAngle:
+ this->Text = ">";
+ break;
+
+ case CK_Comma:
+ this->Text = ", ";
+ break;
+ }
}
CodeCompletionString::Chunk
-CodeCompletionString::Chunk::CreateText(const char *Text) {
+CodeCompletionString::Chunk::CreateText(StringRef Text) {
return Chunk(CK_Text, Text);
}
@@ -51,15 +102,22 @@ CodeCompletionString::Chunk::CreateOptional(
}
CodeCompletionString::Chunk
-CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) {
+CodeCompletionString::Chunk::CreatePlaceholder(StringRef Placeholder) {
return Chunk(CK_Placeholder, Placeholder);
}
CodeCompletionString::Chunk
-CodeCompletionString::Chunk::CreateInformative(const char *Informative) {
+CodeCompletionString::Chunk::CreateInformative(StringRef Informative) {
return Chunk(CK_Informative, Informative);
}
+CodeCompletionString::Chunk
+CodeCompletionString::Chunk::CreateCurrentParameter(
+ StringRef CurrentParameter) {
+ return Chunk(CK_CurrentParameter, CurrentParameter);
+}
+
+
void
CodeCompletionString::Chunk::Destroy() {
switch (Kind) {
@@ -67,10 +125,23 @@ CodeCompletionString::Chunk::Destroy() {
delete Optional;
break;
+ case CK_TypedText:
case CK_Text:
case CK_Placeholder:
case CK_Informative:
- delete [] Text;
+ case CK_CurrentParameter:
+ delete [] Text;
+ break;
+
+ case CK_LeftParen:
+ case CK_RightParen:
+ case CK_LeftBracket:
+ case CK_RightBracket:
+ case CK_LeftBrace:
+ case CK_RightBrace:
+ case CK_LeftAngle:
+ case CK_RightAngle:
+ case CK_Comma:
break;
}
}
@@ -86,16 +157,322 @@ std::string CodeCompletionString::getAsString() const {
for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
switch (C->Kind) {
- case CK_Text: OS << C->Text; break;
case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break;
case CK_Placeholder: OS << "<#" << C->Text << "#>"; break;
case CK_Informative: OS << "[#" << C->Text << "#]"; break;
+ case CK_CurrentParameter: OS << "<#" << C->Text << "#>"; break;
+ default: OS << C->Text; break;
}
}
OS.flush();
return Result;
}
+
+namespace {
+ // Escape a string for XML-like formatting.
+ struct EscapedString {
+ EscapedString(llvm::StringRef Str) : Str(Str) { }
+
+ llvm::StringRef Str;
+ };
+
+ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, EscapedString EStr) {
+ llvm::StringRef Str = EStr.Str;
+ while (!Str.empty()) {
+ // Find the next escaped character.
+ llvm::StringRef::size_type Pos = Str.find_first_of("<>&\"'");
+
+ // Print everything before that escaped character.
+ OS << Str.substr(0, Pos);
+
+ // If we didn't find any escaped characters, we're done.
+ if (Pos == llvm::StringRef::npos)
+ break;
+
+ // Print the appropriate escape sequence.
+ switch (Str[Pos]) {
+ case '<': OS << "&lt;"; break;
+ case '>': OS << "&gt;"; break;
+ case '&': OS << "&amp;"; break;
+ case '"': OS << "&quot;"; break;
+ case '\'': OS << "&apos;"; break;
+ }
+
+ // Remove everything up to and including that escaped character.
+ Str = Str.substr(Pos + 1);
+ }
+
+ return OS;
+ }
+
+ /// \brief Remove XML-like escaping from a string.
+ std::string UnescapeString(llvm::StringRef Str) {
+ using llvm::StringRef;
+
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+
+ while (!Str.empty()) {
+ StringRef::size_type Amp = Str.find('&');
+ OS << Str.substr(0, Amp);
+
+ if (Amp == StringRef::npos)
+ break;
+
+ StringRef::size_type Semi = Str.substr(Amp).find(';');
+ if (Semi == StringRef::npos) {
+ // Malformed input; do the best we can.
+ OS << '&';
+ Str = Str.substr(Amp + 1);
+ continue;
+ }
+
+ char Unescaped = llvm::StringSwitch<char>(Str.substr(Amp + 1, Semi - 1))
+ .Case("lt", '<')
+ .Case("gt", '>')
+ .Case("amp", '&')
+ .Case("quot", '"')
+ .Case("apos", '\'')
+ .Default('\0');
+
+ if (Unescaped)
+ OS << Unescaped;
+ else
+ OS << Str.substr(Amp, Semi + 1);
+ Str = Str.substr(Amp + Semi + 1);
+ }
+
+ return OS.str();
+ }
+}
+
+void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const {
+ for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
+ switch (C->Kind) {
+ case CK_TypedText:
+ OS << "<typed-text>" << EscapedString(C->Text) << "</>";
+ break;
+ case CK_Text:
+ OS << "<text>" << EscapedString(C->Text) << "</>";
+ break;
+ case CK_Optional:
+ OS << "<optional>";
+ C->Optional->Serialize(OS);
+ OS << "</>";
+ break;
+ case CK_Placeholder:
+ OS << "<placeholder>" << EscapedString(C->Text) << "</>";
+ break;
+ case CK_Informative:
+ OS << "<informative>" << EscapedString(C->Text) << "</>";
+ break;
+ case CK_CurrentParameter:
+ OS << "<current-parameter>" << EscapedString(C->Text) << "</>";
+ break;
+ case CK_LeftParen:
+ OS << "<lparen/>";
+ break;
+ case CK_RightParen:
+ OS << "<rparen/>";
+ break;
+ case CK_LeftBracket:
+ OS << "<lbracket/>";
+ break;
+ case CK_RightBracket:
+ OS << "<rbracket/>";
+ break;
+ case CK_LeftBrace:
+ OS << "<lbrace/>";
+ break;
+ case CK_RightBrace:
+ OS << "<rbrace/>";
+ break;
+ case CK_LeftAngle:
+ OS << "<langle/>";
+ break;
+ case CK_RightAngle:
+ OS << "<rangle/>";
+ break;
+ case CK_Comma:
+ OS << "<comma/>";
+ break;
+ }
+ }
+}
+
+/// \brief Parse the next XML-ish tag of the form <blah>.
+///
+/// \param Str the string in which we're looking for the next tag.
+///
+/// \param TagPos if successful, will be set to the start of the tag we found.
+///
+/// \param Standalone will indicate whether this is a "standalone" tag that
+/// has no associated data, e.g., <comma/>.
+///
+/// \param Terminator will indicate whether this is a terminating tag (that is
+/// or starts with '/').
+///
+/// \returns the tag itself, without the angle brackets.
+static llvm::StringRef ParseNextTag(llvm::StringRef Str,
+ llvm::StringRef::size_type &StartTag,
+ llvm::StringRef::size_type &AfterTag,
+ bool &Standalone, bool &Terminator) {
+ using llvm::StringRef;
+
+ Standalone = false;
+ Terminator = false;
+ AfterTag = StringRef::npos;
+
+ // Find the starting '<'.
+ StartTag = Str.find('<');
+ if (StartTag == StringRef::npos)
+ return llvm::StringRef();
+
+ // Find the corresponding '>'.
+ llvm::StringRef::size_type EndTag = Str.substr(StartTag).find('>');
+ if (EndTag == StringRef::npos)
+ return llvm::StringRef();
+ AfterTag = StartTag + EndTag + 1;
+
+ // Determine whether this is a terminating tag.
+ if (Str[StartTag + 1] == '/') {
+ Terminator = true;
+ Str = Str.substr(1);
+ --EndTag;
+ }
+
+ // Determine whether this is a standalone tag.
+ if (!Terminator && Str[StartTag + EndTag - 1] == '/') {
+ Standalone = true;
+ if (EndTag > 1)
+ --EndTag;
+ }
+
+ return Str.substr(StartTag + 1, EndTag - 1);
+}
+
+CodeCompletionString *CodeCompletionString::Deserialize(llvm::StringRef &Str) {
+ using llvm::StringRef;
+
+ CodeCompletionString *Result = new CodeCompletionString;
+
+ do {
+ // Parse the next tag.
+ StringRef::size_type StartTag, AfterTag;
+ bool Standalone, Terminator;
+ StringRef Tag = ParseNextTag(Str, StartTag, AfterTag, Standalone,
+ Terminator);
+
+ if (StartTag == StringRef::npos)
+ break;
+
+ // Figure out what kind of chunk we have.
+ const unsigned UnknownKind = 10000;
+ unsigned Kind = llvm::StringSwitch<unsigned>(Tag)
+ .Case("typed-text", CK_TypedText)
+ .Case("text", CK_Text)
+ .Case("optional", CK_Optional)
+ .Case("placeholder", CK_Placeholder)
+ .Case("informative", CK_Informative)
+ .Case("current-parameter", CK_CurrentParameter)
+ .Case("lparen", CK_LeftParen)
+ .Case("rparen", CK_RightParen)
+ .Case("lbracket", CK_LeftBracket)
+ .Case("rbracket", CK_RightBracket)
+ .Case("lbrace", CK_LeftBrace)
+ .Case("rbrace", CK_RightBrace)
+ .Case("langle", CK_LeftAngle)
+ .Case("rangle", CK_RightAngle)
+ .Case("comma", CK_Comma)
+ .Default(UnknownKind);
+
+ // If we've hit a terminator tag, we're done.
+ if (Terminator)
+ break;
+
+ // Consume the tag.
+ Str = Str.substr(AfterTag);
+
+ // Handle standalone tags now, since they don't need to be matched to
+ // anything.
+ if (Standalone) {
+ // Ignore anything we don't know about.
+ if (Kind == UnknownKind)
+ continue;
+
+ switch ((ChunkKind)Kind) {
+ case CK_TypedText:
+ case CK_Text:
+ case CK_Optional:
+ case CK_Placeholder:
+ case CK_Informative:
+ case CK_CurrentParameter:
+ // There is no point in creating empty chunks of these kinds.
+ break;
+
+ case CK_LeftParen:
+ case CK_RightParen:
+ case CK_LeftBracket:
+ case CK_RightBracket:
+ case CK_LeftBrace:
+ case CK_RightBrace:
+ case CK_LeftAngle:
+ case CK_RightAngle:
+ case CK_Comma:
+ Result->AddChunk(Chunk((ChunkKind)Kind));
+ break;
+ }
+
+ continue;
+ }
+
+ if (Kind == CK_Optional) {
+ // Deserialize the optional code-completion string.
+ std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str));
+ Result->AddOptionalChunk(Optional);
+ }
+
+ StringRef EndTag = ParseNextTag(Str, StartTag, AfterTag, Standalone,
+ Terminator);
+ if (StartTag == StringRef::npos || !Terminator || Standalone)
+ break; // Parsing failed; just give up.
+
+ if (EndTag.empty() || Tag == EndTag) {
+ // Found the matching end tag. Add this chunk based on the text
+ // between the tags, then consume that input.
+ StringRef Text = Str.substr(0, StartTag);
+ switch ((ChunkKind)Kind) {
+ case CK_TypedText:
+ case CK_Text:
+ case CK_Placeholder:
+ case CK_Informative:
+ case CK_CurrentParameter:
+ case CK_LeftParen:
+ case CK_RightParen:
+ case CK_LeftBracket:
+ case CK_RightBracket:
+ case CK_LeftBrace:
+ case CK_RightBrace:
+ case CK_LeftAngle:
+ case CK_RightAngle:
+ case CK_Comma:
+ Result->AddChunk(Chunk((ChunkKind)Kind, UnescapeString(Text)));
+ break;
+
+ case CK_Optional:
+ // We've already added the optional chunk.
+ break;
+ }
+ }
+
+ // Remove this tag.
+ Str = Str.substr(AfterTag);
+ } while (!Str.empty());
+
+ return Result;
+}
+
//===----------------------------------------------------------------------===//
// Code completion overload candidate implementation
//===----------------------------------------------------------------------===//
@@ -133,7 +510,8 @@ CodeCompleteConsumer::OverloadCandidate::getFunctionType() const {
CodeCompleteConsumer::~CodeCompleteConsumer() { }
void
-PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results,
+PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
+ Result *Results,
unsigned NumResults) {
// Print the results.
for (unsigned I = 0; I != NumResults; ++I) {
@@ -177,7 +555,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results,
}
void
-PrintingCodeCompleteConsumer::ProcessOverloadCandidates(unsigned CurrentArg,
+PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
+ unsigned CurrentArg,
OverloadCandidate *Candidates,
unsigned NumCandidates) {
for (unsigned I = 0; I != NumCandidates; ++I) {
@@ -193,3 +572,87 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(unsigned CurrentArg,
// FIXME: Move this somewhere else!
SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
}
+
+void
+CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
+ Result *Results,
+ unsigned NumResults) {
+ // Print the results.
+ for (unsigned I = 0; I != NumResults; ++I) {
+ OS << "COMPLETION:" << Results[I].Rank << ":";
+ switch (Results[I].Kind) {
+ case Result::RK_Declaration:
+ if (RecordDecl *Record = dyn_cast<RecordDecl>(Results[I].Declaration)) {
+ if (Record->isStruct())
+ OS << "Struct:";
+ else if (Record->isUnion())
+ OS << "Union:";
+ else
+ OS << "Class:";
+ } else if (ObjCMethodDecl *Method
+ = dyn_cast<ObjCMethodDecl>(Results[I].Declaration)) {
+ if (Method->isInstanceMethod())
+ OS << "ObjCInstanceMethod:";
+ else
+ OS << "ObjCClassMethod:";
+ } else {
+ OS << Results[I].Declaration->getDeclKindName() << ":";
+ }
+ if (CodeCompletionString *CCS
+ = Results[I].CreateCodeCompletionString(SemaRef)) {
+ CCS->Serialize(OS);
+ delete CCS;
+ } else {
+ OS << "<typed-text>"
+ << Results[I].Declaration->getNameAsString()
+ << "</>";
+ }
+
+ OS << '\n';
+ break;
+
+ case Result::RK_Keyword:
+ OS << "Keyword:<typed-text>" << Results[I].Keyword << "</>\n";
+ break;
+
+ case Result::RK_Macro: {
+ OS << "Macro:";
+ if (CodeCompletionString *CCS
+ = Results[I].CreateCodeCompletionString(SemaRef)) {
+ CCS->Serialize(OS);
+ delete CCS;
+ } else {
+ OS << "<typed-text>" << Results[I].Macro->getName() << "</>";
+ }
+ OS << '\n';
+ break;
+ }
+ }
+ }
+
+ // Once we've printed the code-completion results, suppress remaining
+ // diagnostics.
+ // FIXME: Move this somewhere else!
+ SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
+}
+
+void
+CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
+ unsigned CurrentArg,
+ OverloadCandidate *Candidates,
+ unsigned NumCandidates) {
+ for (unsigned I = 0; I != NumCandidates; ++I) {
+ if (CodeCompletionString *CCS
+ = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) {
+ OS << "OVERLOAD:";
+ CCS->Serialize(OS);
+ OS << '\n';
+ delete CCS;
+ }
+ }
+
+ // Once we've printed the code-completion results, suppress remaining
+ // diagnostics.
+ // FIXME: Move this somewhere else!
+ SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
+}
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index a8e31d2..2b37e9d 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -325,5 +325,5 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To,
}
void Sema::DiagnoseInvalidJumps(Stmt *Body) {
- JumpScopeChecker(Body, *this);
+ (void)JumpScopeChecker(Body, *this);
}
diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h
new file mode 100644
index 0000000..6e72dce
--- /dev/null
+++ b/lib/Sema/Lookup.h
@@ -0,0 +1,392 @@
+//===--- Lookup.h - Classes for name lookup ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the LookupResult class, which is integral to
+// Sema's name-lookup subsystem.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_LOOKUP_H
+#define LLVM_CLANG_SEMA_LOOKUP_H
+
+#include "Sema.h"
+
+namespace clang {
+
+/// @brief Represents the results of name lookup.
+///
+/// An instance of the LookupResult class captures the results of a
+/// single name lookup, which can return no result (nothing found),
+/// a single declaration, a set of overloaded functions, or an
+/// ambiguity. Use the getKind() method to determine which of these
+/// results occurred for a given lookup.
+///
+/// Any non-ambiguous lookup can be converted into a single
+/// (possibly NULL) @c NamedDecl* via the getAsSingleDecl() method.
+/// This permits the common-case usage in C and Objective-C where
+/// name lookup will always return a single declaration. Use of
+/// this is largely deprecated; callers should handle the possibility
+/// of multiple declarations.
+class LookupResult {
+public:
+ enum LookupResultKind {
+ /// @brief No entity found met the criteria.
+ NotFound = 0,
+
+ /// @brief Name lookup found a single declaration that met the
+ /// criteria. getAsDecl will return this declaration.
+ Found,
+
+ /// @brief Name lookup found a set of overloaded functions that
+ /// met the criteria. getAsDecl will turn this set of overloaded
+ /// functions into an OverloadedFunctionDecl.
+ FoundOverloaded,
+
+ /// @brief Name lookup found an unresolvable value declaration
+ /// and cannot yet complete. This only happens in C++ dependent
+ /// contexts with dependent using declarations.
+ FoundUnresolvedValue,
+
+ /// @brief Name lookup results in an ambiguity; use
+ /// getAmbiguityKind to figure out what kind of ambiguity
+ /// we have.
+ Ambiguous
+ };
+
+ enum AmbiguityKind {
+ /// Name lookup results in an ambiguity because multiple
+ /// entities that meet the lookup criteria were found in
+ /// subobjects of different types. For example:
+ /// @code
+ /// struct A { void f(int); }
+ /// struct B { void f(double); }
+ /// struct C : A, B { };
+ /// void test(C c) {
+ /// c.f(0); // error: A::f and B::f come from subobjects of different
+ /// // types. overload resolution is not performed.
+ /// }
+ /// @endcode
+ AmbiguousBaseSubobjectTypes,
+
+ /// Name lookup results in an ambiguity because multiple
+ /// nonstatic entities that meet the lookup criteria were found
+ /// in different subobjects of the same type. For example:
+ /// @code
+ /// struct A { int x; };
+ /// struct B : A { };
+ /// struct C : A { };
+ /// struct D : B, C { };
+ /// int test(D d) {
+ /// return d.x; // error: 'x' is found in two A subobjects (of B and C)
+ /// }
+ /// @endcode
+ AmbiguousBaseSubobjects,
+
+ /// Name lookup results in an ambiguity because multiple definitions
+ /// of entity that meet the lookup criteria were found in different
+ /// declaration contexts.
+ /// @code
+ /// namespace A {
+ /// int i;
+ /// namespace B { int i; }
+ /// int test() {
+ /// using namespace B;
+ /// return i; // error 'i' is found in namespace A and A::B
+ /// }
+ /// }
+ /// @endcode
+ AmbiguousReference,
+
+ /// Name lookup results in an ambiguity because an entity with a
+ /// tag name was hidden by an entity with an ordinary name from
+ /// a different context.
+ /// @code
+ /// namespace A { struct Foo {}; }
+ /// namespace B { void Foo(); }
+ /// namespace C {
+ /// using namespace A;
+ /// using namespace B;
+ /// }
+ /// void test() {
+ /// C::Foo(); // error: tag 'A::Foo' is hidden by an object in a
+ /// // different namespace
+ /// }
+ /// @endcode
+ AmbiguousTagHiding
+ };
+
+ /// A little identifier for flagging temporary lookup results.
+ enum TemporaryToken {
+ Temporary
+ };
+
+ typedef llvm::SmallVector<NamedDecl*, 4> DeclsTy;
+ typedef DeclsTy::const_iterator iterator;
+
+ LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc,
+ Sema::LookupNameKind LookupKind,
+ Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration)
+ : ResultKind(NotFound),
+ Paths(0),
+ SemaRef(SemaRef),
+ Name(Name),
+ NameLoc(NameLoc),
+ LookupKind(LookupKind),
+ IDNS(0),
+ Redecl(Redecl != Sema::NotForRedeclaration),
+ HideTags(true),
+ Diagnose(Redecl == Sema::NotForRedeclaration)
+ {}
+
+ /// Creates a temporary lookup result, initializing its core data
+ /// using the information from another result. Diagnostics are always
+ /// disabled.
+ LookupResult(TemporaryToken _, const LookupResult &Other)
+ : ResultKind(NotFound),
+ Paths(0),
+ SemaRef(Other.SemaRef),
+ Name(Other.Name),
+ NameLoc(Other.NameLoc),
+ LookupKind(Other.LookupKind),
+ IDNS(Other.IDNS),
+ Redecl(Other.Redecl),
+ HideTags(Other.HideTags),
+ Diagnose(false)
+ {}
+
+ ~LookupResult() {
+ if (Diagnose) diagnose();
+ if (Paths) deletePaths(Paths);
+ }
+
+ /// Gets the name to look up.
+ DeclarationName getLookupName() const {
+ return Name;
+ }
+
+ /// Gets the kind of lookup to perform.
+ Sema::LookupNameKind getLookupKind() const {
+ return LookupKind;
+ }
+
+ /// True if this lookup is just looking for an existing declaration.
+ bool isForRedeclaration() const {
+ return Redecl;
+ }
+
+ /// Sets whether tag declarations should be hidden by non-tag
+ /// declarations during resolution. The default is true.
+ void setHideTags(bool Hide) {
+ HideTags = Hide;
+ }
+
+ /// The identifier namespace of this lookup. This information is
+ /// private to the lookup routines.
+ unsigned getIdentifierNamespace() const {
+ assert(IDNS);
+ return IDNS;
+ }
+
+ void setIdentifierNamespace(unsigned NS) {
+ IDNS = NS;
+ }
+
+ bool isAmbiguous() const {
+ return getResultKind() == Ambiguous;
+ }
+
+ LookupResultKind getResultKind() const {
+ sanity();
+ return ResultKind;
+ }
+
+ AmbiguityKind getAmbiguityKind() const {
+ assert(isAmbiguous());
+ return Ambiguity;
+ }
+
+ iterator begin() const { return Decls.begin(); }
+ iterator end() const { return Decls.end(); }
+
+ /// \brief Return true if no decls were found
+ bool empty() const { return Decls.empty(); }
+
+ /// \brief Return the base paths structure that's associated with
+ /// these results, or null if none is.
+ CXXBasePaths *getBasePaths() const {
+ return Paths;
+ }
+
+ /// \brief Add a declaration to these results.
+ void addDecl(NamedDecl *D) {
+ Decls.push_back(D);
+ ResultKind = Found;
+ }
+
+ /// \brief Add all the declarations from another set of lookup
+ /// results.
+ void addAllDecls(const LookupResult &Other) {
+ Decls.append(Other.begin(), Other.end());
+ ResultKind = Found;
+ }
+
+ /// \brief Hides a set of declarations.
+ template <class NamedDeclSet> void hideDecls(const NamedDeclSet &Set) {
+ unsigned I = 0, N = Decls.size();
+ while (I < N) {
+ if (Set.count(Decls[I]))
+ Decls[I] = Decls[--N];
+ else
+ I++;
+ }
+ Decls.set_size(N);
+ }
+
+ /// \brief Resolves the kind of the lookup, possibly hiding decls.
+ ///
+ /// This should be called in any environment where lookup might
+ /// generate multiple lookup results.
+ void resolveKind();
+
+ /// \brief Fetch this as an unambiguous single declaration
+ /// (possibly an overloaded one).
+ ///
+ /// This is deprecated; users should be written to handle
+ /// ambiguous and overloaded lookups.
+ NamedDecl *getAsSingleDecl(ASTContext &Context) const;
+
+ /// \brief Fetch the unique decl found by this lookup. Asserts
+ /// that one was found.
+ ///
+ /// This is intended for users who have examined the result kind
+ /// and are certain that there is only one result.
+ NamedDecl *getFoundDecl() const {
+ assert(getResultKind() == Found
+ && "getFoundDecl called on non-unique result");
+ return Decls[0]->getUnderlyingDecl();
+ }
+
+ /// \brief Asks if the result is a single tag decl.
+ bool isSingleTagDecl() const {
+ return getResultKind() == Found && isa<TagDecl>(getFoundDecl());
+ }
+
+ /// \brief Make these results show that the name was found in
+ /// base classes of different types.
+ ///
+ /// The given paths object is copied and invalidated.
+ void setAmbiguousBaseSubobjectTypes(CXXBasePaths &P);
+
+ /// \brief Make these results show that the name was found in
+ /// distinct base classes of the same type.
+ ///
+ /// The given paths object is copied and invalidated.
+ void setAmbiguousBaseSubobjects(CXXBasePaths &P);
+
+ /// \brief Make these results show that the name was found in
+ /// different contexts and a tag decl was hidden by an ordinary
+ /// decl in a different context.
+ void setAmbiguousQualifiedTagHiding() {
+ setAmbiguous(AmbiguousTagHiding);
+ }
+
+ /// \brief Clears out any current state.
+ void clear() {
+ ResultKind = NotFound;
+ Decls.clear();
+ if (Paths) deletePaths(Paths);
+ Paths = NULL;
+ }
+
+ /// \brief Clears out any current state and re-initializes for a
+ /// different kind of lookup.
+ void clear(Sema::LookupNameKind Kind) {
+ clear();
+ LookupKind = Kind;
+ }
+
+ void print(llvm::raw_ostream &);
+
+ /// Suppress the diagnostics that would normally fire because of this
+ /// lookup. This happens during (e.g.) redeclaration lookups.
+ void suppressDiagnostics() {
+ Diagnose = false;
+ }
+
+ /// Sets a 'context' source range.
+ void setContextRange(SourceRange SR) {
+ NameContextRange = SR;
+ }
+
+ /// Gets the source range of the context of this name; for C++
+ /// qualified lookups, this is the source range of the scope
+ /// specifier.
+ SourceRange getContextRange() const {
+ return NameContextRange;
+ }
+
+ /// Gets the location of the identifier. This isn't always defined:
+ /// sometimes we're doing lookups on synthesized names.
+ SourceLocation getNameLoc() const {
+ return NameLoc;
+ }
+
+private:
+ void diagnose() {
+ if (isAmbiguous())
+ SemaRef.DiagnoseAmbiguousLookup(*this);
+ }
+
+ void setAmbiguous(AmbiguityKind AK) {
+ ResultKind = Ambiguous;
+ Ambiguity = AK;
+ }
+
+ void addDeclsFromBasePaths(const CXXBasePaths &P);
+
+ // Sanity checks.
+ void sanity() const {
+ assert(ResultKind != NotFound || Decls.size() == 0);
+ assert(ResultKind != Found || Decls.size() == 1);
+ assert(ResultKind == NotFound || ResultKind == Found ||
+ ResultKind == FoundUnresolvedValue ||
+ (ResultKind == Ambiguous && Ambiguity == AmbiguousBaseSubobjects)
+ || Decls.size() > 1);
+ assert((Paths != NULL) == (ResultKind == Ambiguous &&
+ (Ambiguity == AmbiguousBaseSubobjectTypes ||
+ Ambiguity == AmbiguousBaseSubobjects)));
+ }
+
+ static void deletePaths(CXXBasePaths *);
+
+ // Results.
+ LookupResultKind ResultKind;
+ AmbiguityKind Ambiguity; // ill-defined unless ambiguous
+ DeclsTy Decls;
+ CXXBasePaths *Paths;
+
+ // Parameters.
+ Sema &SemaRef;
+ DeclarationName Name;
+ SourceLocation NameLoc;
+ SourceRange NameContextRange;
+ Sema::LookupNameKind LookupKind;
+ unsigned IDNS; // ill-defined until set by lookup
+ bool Redecl;
+
+ /// \brief True if tag declarations should be hidden if non-tags
+ /// are present
+ bool HideTags;
+
+ bool Diagnose;
+};
+
+}
+
+#endif
diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp
index d3f26d8..7b223a8 100644
--- a/lib/Sema/ParseAST.cpp
+++ b/lib/Sema/ParseAST.cpp
@@ -35,15 +35,14 @@ using namespace clang;
void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
ASTContext &Ctx, bool PrintStats,
bool CompleteTranslationUnit,
- CodeCompleteConsumer *(*CreateCodeCompleter)(Sema &, void *Data),
- void *CreateCodeCompleterData) {
+ CodeCompleteConsumer *CompletionConsumer) {
// Collect global stats on Decls/Stmts (until we have a module streamer).
if (PrintStats) {
Decl::CollectingStats(true);
Stmt::CollectingStats(true);
}
- Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit);
+ Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit, CompletionConsumer);
Parser P(PP, S);
PP.EnterMainSourceFile();
@@ -63,12 +62,6 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
External->StartTranslationUnit(Consumer);
}
- CodeCompleteConsumer *CodeCompleter = 0;
- if (CreateCodeCompleter) {
- CodeCompleter = CreateCodeCompleter(S, CreateCodeCompleterData);
- S.setCodeCompleteConsumer(CodeCompleter);
- }
-
Parser::DeclGroupPtrTy ADecl;
while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file.
@@ -78,6 +71,9 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
if (ADecl)
Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>());
};
+ // Check for any pending objective-c implementation decl.
+ while ((ADecl = P.RetrievePendingObjCImpDecl()))
+ Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>());
// process any TopLevelDecls generated by #pragma weak
for (llvm::SmallVector<Decl*,2>::iterator
@@ -87,9 +83,6 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
Consumer->HandleTranslationUnit(Ctx);
- if (CreateCodeCompleter)
- delete CodeCompleter;
-
if (PrintStats) {
fprintf(stderr, "\nSTATISTICS:\n");
P.getActions().PrintStats();
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 8104dd3..b2bbac8 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -14,6 +14,7 @@
#include "Sema.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/APFloat.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
@@ -346,16 +347,18 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
}
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
- bool CompleteTranslationUnit)
+ bool CompleteTranslationUnit,
+ CodeCompleteConsumer *CodeCompleter)
: LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
- ExternalSource(0), CodeCompleter(0), CurContext(0),
+ ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0),
PreDeclaratorDC(0), CurBlock(0), PackContext(0), ParsingDeclDepth(0),
IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0),
GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated),
CompleteTranslationUnit(CompleteTranslationUnit),
- NumSFINAEErrors(0), CurrentInstantiationScope(0) {
-
+ NumSFINAEErrors(0), NonInstantiationEntries(0),
+ CurrentInstantiationScope(0)
+{
TUScope = 0;
if (getLangOptions().CPlusPlus)
FieldCollector.reset(new CXXFieldCollector());
@@ -364,6 +367,322 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
PP.getDiagnostics().SetArgToStringFn(ConvertArgToStringFn, &Context);
}
+/// Retrieves the width and signedness of the given integer type,
+/// or returns false if it is not an integer type.
+///
+/// \param T must be canonical
+static bool getIntProperties(ASTContext &C, const Type *T,
+ unsigned &BitWidth, bool &Signed) {
+ assert(T->isCanonicalUnqualified());
+
+ if (const VectorType *VT = dyn_cast<VectorType>(T))
+ T = VT->getElementType().getTypePtr();
+ if (const ComplexType *CT = dyn_cast<ComplexType>(T))
+ T = CT->getElementType().getTypePtr();
+
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) {
+ if (!BT->isInteger()) return false;
+
+ BitWidth = C.getIntWidth(QualType(T, 0));
+ Signed = BT->isSignedInteger();
+ return true;
+ }
+
+ if (const FixedWidthIntType *FWIT = dyn_cast<FixedWidthIntType>(T)) {
+ BitWidth = FWIT->getWidth();
+ Signed = FWIT->isSigned();
+ return true;
+ }
+
+ return false;
+}
+
+/// Checks whether the given value will have the same value if it it
+/// is truncated to the given width, then extended back to the
+/// original width.
+static bool IsSameIntAfterCast(const llvm::APSInt &value,
+ unsigned TargetWidth) {
+ unsigned SourceWidth = value.getBitWidth();
+ llvm::APSInt truncated = value;
+ truncated.trunc(TargetWidth);
+ truncated.extend(SourceWidth);
+ return (truncated == value);
+}
+
+/// Checks whether the given value will have the same value if it
+/// is truncated to the given width, then extended back to the original
+/// width.
+///
+/// The value might be a vector or a complex.
+static bool IsSameIntAfterCast(const APValue &value, unsigned TargetWidth) {
+ if (value.isInt())
+ return IsSameIntAfterCast(value.getInt(), TargetWidth);
+
+ if (value.isVector()) {
+ for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i)
+ if (!IsSameIntAfterCast(value.getVectorElt(i), TargetWidth))
+ return false;
+ return true;
+ }
+
+ if (value.isComplexInt()) {
+ return IsSameIntAfterCast(value.getComplexIntReal(), TargetWidth) &&
+ IsSameIntAfterCast(value.getComplexIntImag(), TargetWidth);
+ }
+
+ // This can happen with lossless casts to intptr_t of "based" lvalues.
+ // Assume it might use arbitrary bits.
+ assert(value.isLValue());
+ return false;
+}
+
+
+/// Checks whether the given value, which currently has the given
+/// source semantics, has the same value when coerced through the
+/// target semantics.
+static bool IsSameFloatAfterCast(const llvm::APFloat &value,
+ const llvm::fltSemantics &Src,
+ const llvm::fltSemantics &Tgt) {
+ llvm::APFloat truncated = value;
+
+ bool ignored;
+ truncated.convert(Src, llvm::APFloat::rmNearestTiesToEven, &ignored);
+ truncated.convert(Tgt, llvm::APFloat::rmNearestTiesToEven, &ignored);
+
+ return truncated.bitwiseIsEqual(value);
+}
+
+/// Checks whether the given value, which currently has the given
+/// source semantics, has the same value when coerced through the
+/// target semantics.
+///
+/// The value might be a vector of floats (or a complex number).
+static bool IsSameFloatAfterCast(const APValue &value,
+ const llvm::fltSemantics &Src,
+ const llvm::fltSemantics &Tgt) {
+ if (value.isFloat())
+ return IsSameFloatAfterCast(value.getFloat(), Src, Tgt);
+
+ if (value.isVector()) {
+ for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i)
+ if (!IsSameFloatAfterCast(value.getVectorElt(i), Src, Tgt))
+ return false;
+ return true;
+ }
+
+ assert(value.isComplexFloat());
+ return (IsSameFloatAfterCast(value.getComplexFloatReal(), Src, Tgt) &&
+ IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
+}
+
+/// Determines if it's reasonable for the given expression to be truncated
+/// down to the given integer width.
+/// * Boolean expressions are automatically white-listed.
+/// * Arithmetic operations on implicitly-promoted operands of the
+/// target width or less are okay --- not because the results are
+/// actually guaranteed to fit within the width, but because the
+/// user is effectively pretending that the operations are closed
+/// within the implicitly-promoted type.
+static bool IsExprValueWithinWidth(ASTContext &C, Expr *E, unsigned Width) {
+ E = E->IgnoreParens();
+
+#ifndef NDEBUG
+ {
+ const Type *ETy = E->getType()->getCanonicalTypeInternal().getTypePtr();
+ unsigned EWidth;
+ bool ESigned;
+
+ if (!getIntProperties(C, ETy, EWidth, ESigned))
+ assert(0 && "expression not of integer type");
+
+ // The caller should never let this happen.
+ assert(EWidth > Width && "called on expr whose type is too small");
+ }
+#endif
+
+ // Strip implicit casts off.
+ while (isa<ImplicitCastExpr>(E)) {
+ E = cast<ImplicitCastExpr>(E)->getSubExpr();
+
+ const Type *ETy = E->getType()->getCanonicalTypeInternal().getTypePtr();
+
+ unsigned EWidth;
+ bool ESigned;
+ if (!getIntProperties(C, ETy, EWidth, ESigned))
+ return false;
+
+ if (EWidth <= Width)
+ return true;
+ }
+
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ switch (BO->getOpcode()) {
+
+ // Boolean-valued operations are white-listed.
+ case BinaryOperator::LAnd:
+ case BinaryOperator::LOr:
+ case BinaryOperator::LT:
+ case BinaryOperator::GT:
+ case BinaryOperator::LE:
+ case BinaryOperator::GE:
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ return true;
+
+ // Operations with opaque sources are black-listed.
+ case BinaryOperator::PtrMemD:
+ case BinaryOperator::PtrMemI:
+ return false;
+
+ // Left shift gets black-listed based on a judgement call.
+ case BinaryOperator::Shl:
+ return false;
+
+ // Various special cases.
+ case BinaryOperator::Shr:
+ return IsExprValueWithinWidth(C, BO->getLHS(), Width);
+ case BinaryOperator::Comma:
+ return IsExprValueWithinWidth(C, BO->getRHS(), Width);
+ case BinaryOperator::Sub:
+ if (BO->getLHS()->getType()->isPointerType())
+ return false;
+ // fallthrough
+
+ // Any other operator is okay if the operands are
+ // promoted from expressions of appropriate size.
+ default:
+ return IsExprValueWithinWidth(C, BO->getLHS(), Width) &&
+ IsExprValueWithinWidth(C, BO->getRHS(), Width);
+ }
+ }
+
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ switch (UO->getOpcode()) {
+ // Boolean-valued operations are white-listed.
+ case UnaryOperator::LNot:
+ return true;
+
+ // Operations with opaque sources are black-listed.
+ case UnaryOperator::Deref:
+ case UnaryOperator::AddrOf: // should be impossible
+ return false;
+
+ case UnaryOperator::OffsetOf:
+ return false;
+
+ default:
+ return IsExprValueWithinWidth(C, UO->getSubExpr(), Width);
+ }
+ }
+
+ // Don't diagnose if the expression is an integer constant
+ // whose value in the target type is the same as it was
+ // in the original type.
+ Expr::EvalResult result;
+ if (E->Evaluate(result, C))
+ if (IsSameIntAfterCast(result.Val, Width))
+ return true;
+
+ return false;
+}
+
+/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion.
+static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) {
+ S.Diag(E->getExprLoc(), diag) << E->getType() << T << E->getSourceRange();
+}
+
+/// Implements -Wconversion.
+static void CheckImplicitConversion(Sema &S, Expr *E, QualType T) {
+ // Don't diagnose in unevaluated contexts.
+ if (S.ExprEvalContext == Sema::Unevaluated)
+ return;
+
+ // Don't diagnose for value-dependent expressions.
+ if (E->isValueDependent())
+ return;
+
+ const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr();
+ const Type *Target = S.Context.getCanonicalType(T).getTypePtr();
+
+ // Never diagnose implicit casts to bool.
+ if (Target->isSpecificBuiltinType(BuiltinType::Bool))
+ return;
+
+ // Strip vector types.
+ if (isa<VectorType>(Source)) {
+ if (!isa<VectorType>(Target))
+ return DiagnoseImpCast(S, E, T, diag::warn_impcast_vector_scalar);
+
+ Source = cast<VectorType>(Source)->getElementType().getTypePtr();
+ Target = cast<VectorType>(Target)->getElementType().getTypePtr();
+ }
+
+ // Strip complex types.
+ if (isa<ComplexType>(Source)) {
+ if (!isa<ComplexType>(Target))
+ return DiagnoseImpCast(S, E, T, diag::warn_impcast_complex_scalar);
+
+ Source = cast<ComplexType>(Source)->getElementType().getTypePtr();
+ Target = cast<ComplexType>(Target)->getElementType().getTypePtr();
+ }
+
+ const BuiltinType *SourceBT = dyn_cast<BuiltinType>(Source);
+ const BuiltinType *TargetBT = dyn_cast<BuiltinType>(Target);
+
+ // If the source is floating point...
+ if (SourceBT && SourceBT->isFloatingPoint()) {
+ // ...and the target is floating point...
+ if (TargetBT && TargetBT->isFloatingPoint()) {
+ // ...then warn if we're dropping FP rank.
+
+ // Builtin FP kinds are ordered by increasing FP rank.
+ if (SourceBT->getKind() > TargetBT->getKind()) {
+ // Don't warn about float constants that are precisely
+ // representable in the target type.
+ Expr::EvalResult result;
+ if (E->Evaluate(result, S.Context)) {
+ // Value might be a float, a float vector, or a float complex.
+ if (IsSameFloatAfterCast(result.Val,
+ S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)),
+ S.Context.getFloatTypeSemantics(QualType(SourceBT, 0))))
+ return;
+ }
+
+ DiagnoseImpCast(S, E, T, diag::warn_impcast_float_precision);
+ }
+ return;
+ }
+
+ // If the target is integral, always warn.
+ if ((TargetBT && TargetBT->isInteger()) ||
+ isa<FixedWidthIntType>(Target))
+ // TODO: don't warn for integer values?
+ return DiagnoseImpCast(S, E, T, diag::warn_impcast_float_integer);
+
+ return;
+ }
+
+ unsigned SourceWidth, TargetWidth;
+ bool SourceSigned, TargetSigned;
+
+ if (!getIntProperties(S.Context, Source, SourceWidth, SourceSigned) ||
+ !getIntProperties(S.Context, Target, TargetWidth, TargetSigned))
+ return;
+
+ if (SourceWidth > TargetWidth) {
+ if (IsExprValueWithinWidth(S.Context, E, TargetWidth))
+ return;
+
+ // People want to build with -Wshorten-64-to-32 and not -Wconversion
+ // and by god we'll let them.
+ if (SourceWidth == 64 && TargetWidth == 32)
+ return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_64_32);
+ return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_precision);
+ }
+
+ return;
+}
+
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
/// If there is already an implicit cast, merge into the existing one.
/// If isLvalue, the result of the cast is an lvalue.
@@ -375,18 +694,17 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty,
if (ExprTy == TypeTy)
return;
- if (Expr->getType().getTypePtr()->isPointerType() &&
- Ty.getTypePtr()->isPointerType()) {
- QualType ExprBaseType =
- cast<PointerType>(ExprTy.getUnqualifiedType())->getPointeeType();
- QualType BaseType =
- cast<PointerType>(TypeTy.getUnqualifiedType())->getPointeeType();
+ if (Expr->getType()->isPointerType() && Ty->isPointerType()) {
+ QualType ExprBaseType = cast<PointerType>(ExprTy)->getPointeeType();
+ QualType BaseType = cast<PointerType>(TypeTy)->getPointeeType();
if (ExprBaseType.getAddressSpace() != BaseType.getAddressSpace()) {
Diag(Expr->getExprLoc(), diag::err_implicit_pointer_address_space_cast)
<< Expr->getSourceRange();
}
}
+ CheckImplicitConversion(*this, Expr, Ty);
+
if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {
if (ImpCast->getCastKind() == Kind) {
ImpCast->setType(Ty);
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index c4de6be..3e186b2 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -93,6 +93,7 @@ namespace clang {
class FunctionProtoType;
class CXXBasePaths;
class CXXTemporary;
+ class LookupResult;
/// BlockSemaInfo - When a block is being parsed, this contains information
/// about the block. It is pointed to from Sema::CurBlock.
@@ -373,7 +374,8 @@ public:
bool isSelfExpr(Expr *RExpr);
public:
Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
- bool CompleteTranslationUnit = true);
+ bool CompleteTranslationUnit = true,
+ CodeCompleteConsumer *CompletionConsumer = 0);
~Sema() {
if (PackContext) FreePackedContext();
}
@@ -804,13 +806,15 @@ public:
QualType& ConvertedType, bool &IncompatibleObjC);
bool isObjCPointerConversion(QualType FromType, QualType ToType,
QualType& ConvertedType, bool &IncompatibleObjC);
- bool CheckPointerConversion(Expr *From, QualType ToType,
- CastExpr::CastKind &Kind);
+ bool CheckPointerConversion(Expr *From, QualType ToType,
+ CastExpr::CastKind &Kind,
+ bool IgnoreBaseAccess);
bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType,
bool InOverloadResolution,
QualType &ConvertedType);
bool CheckMemberPointerConversion(Expr *From, QualType ToType,
- CastExpr::CastKind &Kind);
+ CastExpr::CastKind &Kind,
+ bool IgnoreBaseAccess);
bool IsQualificationConversion(QualType FromType, QualType ToType);
OverloadingResult IsUserDefinedConversion(Expr *From, QualType ToType,
UserDefinedConversionSequence& User,
@@ -870,6 +874,11 @@ public:
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false);
+ void AddMethodCandidate(NamedDecl *Decl,
+ Expr *Object, Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool SuppressUserConversion = false,
+ bool ForceRValue = false);
void AddMethodCandidate(CXXMethodDecl *Method,
Expr *Object, Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
@@ -1073,255 +1082,14 @@ public:
LookupObjCCategoryImplName
};
- /// @brief Represents the results of name lookup.
- ///
- /// An instance of the LookupResult class captures the results of a
- /// single name lookup, which can return no result (nothing found),
- /// a single declaration, a set of overloaded functions, or an
- /// ambiguity. Use the getKind() method to determine which of these
- /// results occurred for a given lookup.
- ///
- /// Any non-ambiguous lookup can be converted into a single
- /// (possibly NULL) @c NamedDecl* via the getAsSingleDecl() method.
- /// This permits the common-case usage in C and Objective-C where
- /// name lookup will always return a single declaration. Use of
- /// this is largely deprecated; callers should handle the possibility
- /// of multiple declarations.
- class LookupResult {
- public:
- enum LookupKind {
- /// @brief No entity found met the criteria.
- NotFound = 0,
-
- /// @brief Name lookup found a single declaration that met the
- /// criteria. getAsDecl will return this declaration.
- Found,
-
- /// @brief Name lookup found a set of overloaded functions that
- /// met the criteria. getAsDecl will turn this set of overloaded
- /// functions into an OverloadedFunctionDecl.
- FoundOverloaded,
-
- /// @brief Name lookup results in an ambiguity; use
- /// getAmbiguityKind to figure out what kind of ambiguity
- /// we have.
- Ambiguous
- };
-
- enum AmbiguityKind {
- /// Name lookup results in an ambiguity because multiple
- /// entities that meet the lookup criteria were found in
- /// subobjects of different types. For example:
- /// @code
- /// struct A { void f(int); }
- /// struct B { void f(double); }
- /// struct C : A, B { };
- /// void test(C c) {
- /// c.f(0); // error: A::f and B::f come from subobjects of different
- /// // types. overload resolution is not performed.
- /// }
- /// @endcode
- AmbiguousBaseSubobjectTypes,
-
- /// Name lookup results in an ambiguity because multiple
- /// nonstatic entities that meet the lookup criteria were found
- /// in different subobjects of the same type. For example:
- /// @code
- /// struct A { int x; };
- /// struct B : A { };
- /// struct C : A { };
- /// struct D : B, C { };
- /// int test(D d) {
- /// return d.x; // error: 'x' is found in two A subobjects (of B and C)
- /// }
- /// @endcode
- AmbiguousBaseSubobjects,
-
- /// Name lookup results in an ambiguity because multiple definitions
- /// of entity that meet the lookup criteria were found in different
- /// declaration contexts.
- /// @code
- /// namespace A {
- /// int i;
- /// namespace B { int i; }
- /// int test() {
- /// using namespace B;
- /// return i; // error 'i' is found in namespace A and A::B
- /// }
- /// }
- /// @endcode
- AmbiguousReference,
-
- /// Name lookup results in an ambiguity because an entity with a
- /// tag name was hidden by an entity with an ordinary name from
- /// a different context.
- /// @code
- /// namespace A { struct Foo {}; }
- /// namespace B { void Foo(); }
- /// namespace C {
- /// using namespace A;
- /// using namespace B;
- /// }
- /// void test() {
- /// C::Foo(); // error: tag 'A::Foo' is hidden by an object in a
- /// // different namespace
- /// }
- /// @endcode
- AmbiguousTagHiding
- };
-
- typedef llvm::SmallVector<NamedDecl*, 4> DeclsTy;
- typedef DeclsTy::const_iterator iterator;
-
- LookupResult()
- : Kind(NotFound),
- Paths(0)
- {}
- ~LookupResult() {
- if (Paths) deletePaths(Paths);
- }
-
- bool isAmbiguous() const {
- return getKind() == Ambiguous;
- }
-
- LookupKind getKind() const {
- sanity();
- return Kind;
- }
-
- AmbiguityKind getAmbiguityKind() const {
- assert(isAmbiguous());
- return Ambiguity;
- }
-
- iterator begin() const { return Decls.begin(); }
- iterator end() const { return Decls.end(); }
-
- /// \brief Return true if no decls were found
- bool empty() const { return Decls.empty(); }
-
- /// \brief Return the base paths structure that's associated with
- /// these results, or null if none is.
- CXXBasePaths *getBasePaths() const {
- return Paths;
- }
-
- /// \brief Add a declaration to these results.
- void addDecl(NamedDecl *D) {
- Decls.push_back(D->getUnderlyingDecl());
- Kind = Found;
- }
-
- /// \brief Add all the declarations from another set of lookup
- /// results.
- void addAllDecls(const LookupResult &Other) {
- Decls.append(Other.begin(), Other.end());
- Kind = Found;
- }
-
- /// \brief Hides a set of declarations.
- template <class NamedDeclSet> void hideDecls(const NamedDeclSet &Set) {
- unsigned I = 0, N = Decls.size();
- while (I < N) {
- if (Set.count(Decls[I]))
- Decls[I] = Decls[--N];
- else
- I++;
- }
- Decls.set_size(N);
- }
-
- /// \brief Resolves the kind of the lookup, possibly hiding decls.
- ///
- /// This should be called in any environment where lookup might
- /// generate multiple lookup results.
- void resolveKind();
-
- /// \brief Fetch this as an unambiguous single declaration
- /// (possibly an overloaded one).
- ///
- /// This is deprecated; users should be written to handle
- /// ambiguous and overloaded lookups.
- NamedDecl *getAsSingleDecl(ASTContext &Context) const;
-
- /// \brief Fetch the unique decl found by this lookup. Asserts
- /// that one was found.
- ///
- /// This is intended for users who have examined the result kind
- /// and are certain that there is only one result.
- NamedDecl *getFoundDecl() const {
- assert(getKind() == Found && "getFoundDecl called on non-unique result");
- return *Decls.begin();
- }
-
- /// \brief Asks if the result is a single tag decl.
- bool isSingleTagDecl() const {
- return getKind() == Found && isa<TagDecl>(getFoundDecl());
- }
-
- /// \brief Make these results show that the name was found in
- /// base classes of different types.
- ///
- /// The given paths object is copied and invalidated.
- void setAmbiguousBaseSubobjectTypes(CXXBasePaths &P);
-
- /// \brief Make these results show that the name was found in
- /// distinct base classes of the same type.
- ///
- /// The given paths object is copied and invalidated.
- void setAmbiguousBaseSubobjects(CXXBasePaths &P);
-
- /// \brief Make these results show that the name was found in
- /// different contexts and a tag decl was hidden by an ordinary
- /// decl in a different context.
- void setAmbiguousQualifiedTagHiding() {
- setAmbiguous(AmbiguousTagHiding);
- }
-
- /// \brief Clears out any current state.
- void clear() {
- Kind = NotFound;
- Decls.clear();
- if (Paths) deletePaths(Paths);
- Paths = NULL;
- }
-
- void print(llvm::raw_ostream &);
-
- private:
- void setAmbiguous(AmbiguityKind AK) {
- Kind = Ambiguous;
- Ambiguity = AK;
- }
-
- void addDeclsFromBasePaths(const CXXBasePaths &P);
-
- // Sanity checks.
- void sanity() const {
- assert(Kind != NotFound || Decls.size() == 0);
- assert(Kind != Found || Decls.size() == 1);
- assert(Kind == NotFound || Kind == Found ||
- (Kind == Ambiguous && Ambiguity == AmbiguousBaseSubobjects)
- || Decls.size() > 1);
- assert((Paths != NULL) == (Kind == Ambiguous &&
- (Ambiguity == AmbiguousBaseSubobjectTypes ||
- Ambiguity == AmbiguousBaseSubobjects)));
- }
-
- static void deletePaths(CXXBasePaths *);
-
- LookupKind Kind;
- AmbiguityKind Ambiguity; // ill-defined unless ambiguous
- DeclsTy Decls;
- CXXBasePaths *Paths;
+ enum RedeclarationKind {
+ NotForRedeclaration,
+ ForRedeclaration
};
private:
- typedef llvm::SmallVector<LookupResult, 3> LookupResultsVecTy;
+ bool CppLookupName(LookupResult &R, Scope *S);
- bool CppLookupName(LookupResult &R, Scope *S, DeclarationName Name,
- LookupNameKind NameKind, bool RedeclarationOnly);
public:
/// Determines whether D is a suitable lookup result according to the
/// lookup criteria.
@@ -1360,27 +1128,13 @@ public:
/// ambiguity and overloaded.
NamedDecl *LookupSingleName(Scope *S, DeclarationName Name,
LookupNameKind NameKind,
- bool RedeclarationOnly = false) {
- LookupResult R;
- LookupName(R, S, Name, NameKind, RedeclarationOnly);
- return R.getAsSingleDecl(Context);
- }
+ RedeclarationKind Redecl
+ = NotForRedeclaration);
bool LookupName(LookupResult &R, Scope *S,
- DeclarationName Name,
- LookupNameKind NameKind,
- bool RedeclarationOnly = false,
- bool AllowBuiltinCreation = false,
- SourceLocation Loc = SourceLocation());
- bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
- DeclarationName Name,
- LookupNameKind NameKind,
- bool RedeclarationOnly = false);
+ bool AllowBuiltinCreation = false);
+ bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx);
bool LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
- DeclarationName Name,
- LookupNameKind NameKind,
- bool RedeclarationOnly = false,
bool AllowBuiltinCreation = false,
- SourceLocation Loc = SourceLocation(),
bool EnteringContext = false);
ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II);
@@ -1398,9 +1152,7 @@ public:
AssociatedNamespaceSet &AssociatedNamespaces,
AssociatedClassSet &AssociatedClasses);
- bool DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
- SourceLocation NameLoc,
- SourceRange LookupRange = SourceRange());
+ bool DiagnoseAmbiguousLookup(LookupResult &Result);
//@}
ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id);
@@ -1447,6 +1199,12 @@ public:
void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
ObjCContainerDecl* IDecl,
bool IncompleteImpl = false);
+
+ /// AtomicPropertySetterGetterRules - This routine enforces the rule (via
+ /// warning) when atomic property has one but not the other user-declared
+ /// setter or getter.
+ void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl* IDecl);
/// MatchTwoMethodDeclarations - Checks if two methods' type match and returns
/// true, or false, accordingly.
@@ -1610,7 +1368,8 @@ public:
Expr **Args, unsigned NumArgs);
void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc,
- const PartialDiagnostic &PD);
+ const PartialDiagnostic &PD,
+ bool Equality = false);
virtual ExpressionEvaluationContext
PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext);
@@ -1746,11 +1505,6 @@ public:
const FunctionProtoType *Proto,
Expr **Args, unsigned NumArgs,
SourceLocation RParenLoc);
- void BuildBaseOrMemberInitializers(ASTContext &C,
- CXXConstructorDecl *Constructor,
- CXXBaseOrMemberInitializer **Initializers,
- unsigned NumInitializers
- );
void DeconstructCallFunction(Expr *FnExpr,
NamedDecl *&Function,
@@ -1890,12 +1644,15 @@ public:
SourceLocation IdentLoc,
IdentifierInfo *Ident);
- NamedDecl *BuildUsingDeclaration(SourceLocation UsingLoc,
+ NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
+ SourceLocation UsingLoc,
const CXXScopeSpec &SS,
SourceLocation IdentLoc,
DeclarationName Name,
AttributeList *AttrList,
- bool IsTypeName);
+ bool IsInstantiation,
+ bool IsTypeName,
+ SourceLocation TypenameLoc);
virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope,
AccessSpecifier AS,
@@ -1903,7 +1660,8 @@ public:
const CXXScopeSpec &SS,
UnqualifiedId &Name,
AttributeList *AttrList,
- bool IsTypeName);
+ bool IsTypeName,
+ SourceLocation TypenameLoc);
/// AddCXXDirectInitializerToDecl - This action is called immediately after
/// ActOnDeclarator, when a C++ direct initializer is present.
@@ -1997,6 +1755,12 @@ public:
};
CXXConstructorDecl *
+ TryInitializationByConstructor(QualType ClassType,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation Loc,
+ InitializationKind Kind);
+
+ CXXConstructorDecl *
PerformInitializationByConstructor(QualType ClassType,
MultiExprArg ArgsPtr,
SourceLocation Loc, SourceRange Range,
@@ -2088,6 +1852,9 @@ public:
void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return,
QualType Argument);
+ bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
+ DeclarationName Name, FunctionDecl* &Operator);
+
/// ActOnCXXDelete - Parsed a C++ 'delete' expression
virtual OwningExprResult ActOnCXXDelete(SourceLocation StartLoc,
bool UseGlobal, bool ArrayForm,
@@ -2276,17 +2043,15 @@ public:
SourceLocation RParenLoc,
CXXRecordDecl *ClassDecl);
- void SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
+ bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
CXXBaseOrMemberInitializer **Initializers,
unsigned NumInitializers,
- llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases,
- llvm::SmallVectorImpl<FieldDecl *>&Members);
+ bool IsImplicitConstructor);
- /// computeBaseOrMembersToDestroy - Compute information in current
- /// destructor decl's AST of bases and non-static data members which will be
- /// implicitly destroyed. We are storing the destruction in the order that
- /// they should occur (which is the reverse of construction order).
- void computeBaseOrMembersToDestroy(CXXDestructorDecl *Destructor);
+ /// MarkBaseAndMemberDestructorsReferenced - Given a destructor decl,
+ /// mark all its non-trivial member and base destructor declarations
+ /// as referenced.
+ void MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor);
void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl);
@@ -2320,6 +2085,7 @@ public:
void CheckConstructor(CXXConstructorDecl *Constructor);
QualType CheckDestructorDeclarator(Declarator &D,
FunctionDecl::StorageClass& SC);
+ void CheckDestructor(CXXDestructorDecl *Destructor);
void CheckConversionDeclarator(Declarator &D, QualType &R,
FunctionDecl::StorageClass& SC);
DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion);
@@ -2353,7 +2119,8 @@ public:
bool IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths);
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
- SourceLocation Loc, SourceRange Range);
+ SourceLocation Loc, SourceRange Range,
+ bool IgnoreAccess = false);
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
unsigned InaccessibleBaseID,
unsigned AmbigiousBaseConvID,
@@ -2451,7 +2218,7 @@ public:
unsigned Position);
virtual void ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParam,
SourceLocation EqualLoc,
- ExprArg Default);
+ const ParsedTemplateArgument &Default);
virtual TemplateParamsTy *
ActOnTemplateParameterList(unsigned Depth,
@@ -2477,8 +2244,7 @@ public:
AccessSpecifier AS);
void translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
- SourceLocation *TemplateArgLocsIn,
- llvm::SmallVector<TemplateArgumentLoc, 16> &TempArgs);
+ llvm::SmallVectorImpl<TemplateArgumentLoc> &TempArgs);
QualType CheckTemplateIdType(TemplateName Template,
SourceLocation TemplateLoc,
@@ -2491,7 +2257,6 @@ public:
ActOnTemplateIdType(TemplateTy Template, SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgs,
- SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc);
virtual TypeResult ActOnTagTemplateIdType(TypeResult Type,
@@ -2513,7 +2278,6 @@ public:
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgs,
- SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc);
virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
@@ -2534,7 +2298,6 @@ public:
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgs,
- SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc,
AttributeList *Attr,
MultiTemplateParamsArg TemplateParameterLists);
@@ -2575,7 +2338,6 @@ public:
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgs,
- SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc,
AttributeList *Attr);
@@ -2595,6 +2357,13 @@ public:
SourceLocation TemplateLoc,
Declarator &D);
+ bool CheckTemplateArgument(NamedDecl *Param,
+ const TemplateArgumentLoc &Arg,
+ TemplateDecl *Template,
+ SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc,
+ TemplateArgumentListBuilder &Converted);
+
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
@@ -2612,17 +2381,54 @@ public:
DeclaratorInfo *Arg);
bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
NamedDecl *&Entity);
- bool CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member);
+ bool CheckTemplateArgumentPointerToMember(Expr *Arg,
+ TemplateArgument &Converted);
bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType InstantiatedParamType, Expr *&Arg,
TemplateArgument &Converted);
- bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg);
+ bool CheckTemplateArgument(TemplateTemplateParmDecl *Param,
+ const TemplateArgumentLoc &Arg);
+
+ /// \brief Enumeration describing how template parameter lists are compared
+ /// for equality.
+ enum TemplateParameterListEqualKind {
+ /// \brief We are matching the template parameter lists of two templates
+ /// that might be redeclarations.
+ ///
+ /// \code
+ /// template<typename T> struct X;
+ /// template<typename T> struct X;
+ /// \endcode
+ TPL_TemplateMatch,
+
+ /// \brief We are matching the template parameter lists of two template
+ /// template parameters as part of matching the template parameter lists
+ /// of two templates that might be redeclarations.
+ ///
+ /// \code
+ /// template<template<int I> class TT> struct X;
+ /// template<template<int Value> class Other> struct X;
+ /// \endcode
+ TPL_TemplateTemplateParmMatch,
+
+ /// \brief We are matching the template parameter lists of a template
+ /// template argument against the template parameter lists of a template
+ /// template parameter.
+ ///
+ /// \code
+ /// template<template<int Value> class Metafun> struct X;
+ /// template<int Value> struct integer_c;
+ /// X<integer_c> xic;
+ /// \endcode
+ TPL_TemplateTemplateArgumentMatch
+ };
+
bool TemplateParameterListsAreEqual(TemplateParameterList *New,
TemplateParameterList *Old,
bool Complain,
- bool IsTemplateTemplateParm = false,
+ TemplateParameterListEqualKind Kind,
SourceLocation TemplateArgLoc
- = SourceLocation());
+ = SourceLocation());
bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams);
@@ -2659,6 +2465,11 @@ public:
std::string
getTemplateArgumentBindingsText(const TemplateParameterList *Params,
const TemplateArgumentList &Args);
+
+ std::string
+ getTemplateArgumentBindingsText(const TemplateParameterList *Params,
+ const TemplateArgument *Args,
+ unsigned NumArgs);
/// \brief Describes the result of template argument deduction.
///
@@ -2849,7 +2660,8 @@ public:
// C++ Template Instantiation
//
- MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D);
+ MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D,
+ const TemplateArgumentList *Innermost = 0);
/// \brief A template instantiation that is currently in progress.
struct ActiveTemplateInstantiation {
@@ -2880,17 +2692,30 @@ public:
/// partial specialization or a function template. The
/// Entity is either a ClassTemplatePartialSpecializationDecl or
/// a FunctionTemplateDecl.
- DeducedTemplateArgumentSubstitution
+ DeducedTemplateArgumentSubstitution,
+
+ /// We are substituting prior template arguments into a new
+ /// template parameter. The template parameter itself is either a
+ /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl.
+ PriorTemplateArgumentSubstitution,
+
+ /// We are checking the validity of a default template argument that
+ /// has been used when naming a template-id.
+ DefaultTemplateArgumentChecking
} Kind;
/// \brief The point of instantiation within the source code.
SourceLocation PointOfInstantiation;
+ /// \brief The template in which we are performing the instantiation,
+ /// for substitutions of prior template arguments.
+ TemplateDecl *Template;
+
/// \brief The entity that is being instantiated.
uintptr_t Entity;
- // \brief If this the instantiation of a default template
- // argument, the list of template arguments.
+ /// \brief The list of template arguments we are substituting, if they
+ /// are not part of the entity.
const TemplateArgument *TemplateArgs;
/// \brief The number of template arguments in TemplateArgs.
@@ -2901,9 +2726,14 @@ public:
/// template instantiation.
SourceRange InstantiationRange;
- ActiveTemplateInstantiation() : Kind(TemplateInstantiation), Entity(0),
- TemplateArgs(0), NumTemplateArgs(0) {}
+ ActiveTemplateInstantiation()
+ : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0),
+ NumTemplateArgs(0) {}
+ /// \brief Determines whether this template is an actual instantiation
+ /// that should be counted toward the maximum instantiation depth.
+ bool isInstantiationRecord() const;
+
friend bool operator==(const ActiveTemplateInstantiation &X,
const ActiveTemplateInstantiation &Y) {
if (X.Kind != Y.Kind)
@@ -2916,6 +2746,13 @@ public:
case TemplateInstantiation:
return true;
+ case PriorTemplateArgumentSubstitution:
+ case DefaultTemplateArgumentChecking:
+ if (X.Template != Y.Template)
+ return false;
+
+ // Fall through
+
case DefaultTemplateArgumentInstantiation:
case ExplicitTemplateArgumentSubstitution:
case DeducedTemplateArgumentSubstitution:
@@ -2942,6 +2779,11 @@ public:
llvm::SmallVector<ActiveTemplateInstantiation, 16>
ActiveTemplateInstantiations;
+ /// \brief The number of ActiveTemplateInstantiation entries in
+ /// \c ActiveTemplateInstantiations that are not actual instantiations and,
+ /// therefore, should not be counted as part of the instantiation depth.
+ unsigned NonInstantiationEntries;
+
/// \brief The last template from which a template instantiation
/// error or warning was produced.
///
@@ -3001,6 +2843,32 @@ public:
unsigned NumTemplateArgs,
SourceRange InstantiationRange = SourceRange());
+ /// \brief Note that we are substituting prior template arguments into a
+ /// non-type or template template parameter.
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ TemplateDecl *Template,
+ NonTypeTemplateParmDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange);
+
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ TemplateDecl *Template,
+ TemplateTemplateParmDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange);
+
+ /// \brief Note that we are checking the default template argument
+ /// against the template parameter for a given template-id.
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ TemplateDecl *Template,
+ NamedDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange);
+
+
/// \brief Note that we have finished instantiating this template.
void Clear();
@@ -3273,8 +3141,9 @@ public:
SourceLocation CatLoc);
virtual DeclPtrTy ActOnForwardClassDeclaration(SourceLocation Loc,
- IdentifierInfo **IdentList,
- unsigned NumElts);
+ IdentifierInfo **IdentList,
+ SourceLocation *IdentLocs,
+ unsigned NumElts);
virtual DeclPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
const IdentifierLocPair *IdentList,
@@ -3484,6 +3353,12 @@ public:
/// CompatiblePointerDiscardsQualifiers - The assignment discards
/// c/v/r qualifiers, which we accept as an extension.
CompatiblePointerDiscardsQualifiers,
+
+ /// IncompatibleNestedPointerQualifiers - The assignment is between two
+ /// nested pointer types, and the qualifiers other than the first two
+ /// levels differ e.g. char ** -> const char **, but we accept them as an
+ /// extension.
+ IncompatibleNestedPointerQualifiers,
/// IncompatibleVectors - The assignment is between two vector types that
/// have the same size, which we accept as an extension.
@@ -3555,10 +3430,11 @@ public:
ImplicitConversionSequence& ICS);
bool PerformImplicitConversion(Expr *&From, QualType ToType,
const ImplicitConversionSequence& ICS,
- const char *Flavor);
+ const char *Flavor,
+ bool IgnoreBaseAccess = false);
bool PerformImplicitConversion(Expr *&From, QualType ToType,
const StandardConversionSequence& SCS,
- const char *Flavor);
+ const char *Flavor, bool IgnoreBaseAccess);
bool BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind,
const ImplicitConversionSequence& ICS,
@@ -3660,7 +3536,8 @@ public:
bool SuppressUserConversions,
bool AllowExplicit,
bool ForceRValue,
- ImplicitConversionSequence *ICS = 0);
+ ImplicitConversionSequence *ICS = 0,
+ bool IgnoreBaseAccess = false);
/// CheckCastTypes - Check type constraints for casting between types under
/// C semantics, or forward to CXXCheckCStyleCast in C++.
@@ -3745,7 +3622,6 @@ public:
/// \name Code completion
//@{
- void setCodeCompleteConsumer(CodeCompleteConsumer *CCC);
virtual void CodeCompleteOrdinaryName(Scope *S);
virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base,
SourceLocation OpLoc,
@@ -3763,7 +3639,13 @@ public:
virtual void CodeCompleteOperatorName(Scope *S);
virtual void CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS);
- //@}
+ virtual void CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName,
+ SourceLocation FNameLoc);
+ virtual void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver);
+ virtual void CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols,
+ unsigned NumProtocols);
+ virtual void CodeCompleteObjCProtocolDecl(Scope *S);
+ //@}
//===--------------------------------------------------------------------===//
// Extra semantic analysis beyond the C type system
@@ -3808,7 +3690,6 @@ private:
void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
};
-
//===--------------------------------------------------------------------===//
// Typed version of Parser::ExprArg (smart pointer for wrapping Expr pointers).
template <typename T>
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 0a5335a..5769716 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "Lookup.h"
#include "clang/AST/Expr.h"
using namespace clang;
@@ -179,10 +180,8 @@ void Sema::ActOnPragmaUnused(const Token *Identifiers, unsigned NumIdentifiers,
for (unsigned i = 0; i < NumIdentifiers; ++i) {
const Token &Tok = Identifiers[i];
IdentifierInfo *Name = Tok.getIdentifierInfo();
- LookupResult Lookup;
- LookupParsedName(Lookup, curScope, NULL, Name,LookupOrdinaryName,
- false, true, Tok.getLocation());
- // FIXME: Handle Lookup.isAmbiguous?
+ LookupResult Lookup(*this, Name, Tok.getLocation(), LookupOrdinaryName);
+ LookupParsedName(Lookup, curScope, NULL, true);
NamedDecl *ND = Lookup.getAsSingleDecl(Context);
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 76faddaa..e5ad338 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -70,28 +70,31 @@ static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
- unsigned &msg);
+ unsigned &msg,
+ CastExpr::CastKind &Kind);
static TryCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
- unsigned &msg);
-static TryCastResult TryStaticDowncast(Sema &Self, QualType SrcType,
- QualType DestType, bool CStyle,
+ unsigned &msg,
+ CastExpr::CastKind &Kind);
+static TryCastResult TryStaticDowncast(Sema &Self, CanQualType SrcType,
+ CanQualType DestType, bool CStyle,
const SourceRange &OpRange,
QualType OrigSrcType,
- QualType OrigDestType, unsigned &msg);
+ QualType OrigDestType, unsigned &msg,
+ CastExpr::CastKind &Kind);
static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType,
QualType DestType,bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
CastExpr::CastKind &Kind);
-static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *SrcExpr,
+static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
CastExpr::CastKind &Kind,
CXXMethodDecl *&ConversionDecl);
-static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr,
+static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
@@ -187,7 +190,8 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
assert((DestType->isPointerType() || DestType->isMemberPointerType()) &&
"Destination type is not pointer or pointer to member.");
- QualType UnwrappedSrcType = SrcType, UnwrappedDestType = DestType;
+ QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType),
+ UnwrappedDestType = Self.Context.getCanonicalType(DestType);
llvm::SmallVector<Qualifiers, 8> cv1, cv2;
// Find the qualifications.
@@ -385,14 +389,15 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
// a non-lvalue-reference target type does not lead to decay.
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
if (DestType->isVoidType()) {
+ Kind = CastExpr::CK_ToVoid;
return;
}
- if (!DestType->isLValueReferenceType())
+ if (!DestType->isLValueReferenceType() && !DestType->isRecordType())
Self.DefaultFunctionArrayConversion(SrcExpr);
unsigned msg = diag::err_bad_cxx_cast_generic;
- if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false,OpRange, msg,
+ if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
Kind, ConversionDecl)
!= TC_Success && msg != 0)
Self.Diag(OpRange.getBegin(), msg) << CT_Static
@@ -402,7 +407,7 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
/// TryStaticCast - Check if a static cast can be performed, and do so if
/// possible. If @p CStyle, ignore access restrictions on hierarchy casting
/// and casting away constness.
-static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr,
+static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange, unsigned &msg,
CastExpr::CastKind &Kind,
@@ -427,15 +432,18 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr,
// C++ 5.2.9p5, reference downcast.
// See the function for details.
// DR 427 specifies that this is to be applied before paragraph 2.
- tcr = TryStaticReferenceDowncast(Self, SrcExpr, DestType, CStyle,OpRange,msg);
+ tcr = TryStaticReferenceDowncast(Self, SrcExpr, DestType, CStyle, OpRange,
+ msg, Kind);
if (tcr != TC_NotApplicable)
return tcr;
// N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue
// reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1".
tcr = TryLValueToRValueCast(Self, SrcExpr, DestType, msg);
- if (tcr != TC_NotApplicable)
+ if (tcr != TC_NotApplicable) {
+ Kind = CastExpr::CK_NoOp;
return tcr;
+ }
// C++ 5.2.9p2: An expression e can be explicitly converted to a type T
// [...] if the declaration "T t(e);" is well-formed, [...].
@@ -467,13 +475,16 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr,
if (DestType->isEnumeralType()) {
if (SrcType->isComplexType() || SrcType->isVectorType()) {
// Fall through - these cannot be converted.
- } else if (SrcType->isArithmeticType() || SrcType->isEnumeralType())
+ } else if (SrcType->isArithmeticType() || SrcType->isEnumeralType()) {
+ Kind = CastExpr::CK_IntegralCast;
return TC_Success;
+ }
}
// Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast.
// C++ 5.2.9p8 additionally disallows a cast path through virtual inheritance.
- tcr = TryStaticPointerDowncast(Self, SrcType, DestType, CStyle, OpRange, msg);
+ tcr = TryStaticPointerDowncast(Self, SrcType, DestType, CStyle, OpRange, msg,
+ Kind);
if (tcr != TC_NotApplicable)
return tcr;
@@ -500,6 +511,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr,
msg = diag::err_bad_cxx_cast_const_away;
return TC_Failed;
}
+ Kind = CastExpr::CK_BitCast;
return TC_Success;
}
}
@@ -544,7 +556,7 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
TryCastResult
TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType,
bool CStyle, const SourceRange &OpRange,
- unsigned &msg) {
+ unsigned &msg, CastExpr::CastKind &Kind) {
// C++ 5.2.9p5: An lvalue of type "cv1 B", where B is a class type, can be
// cast to type "reference to cv2 D", where D is a class derived from B,
// if a valid standard conversion from "pointer to D" to "pointer to B"
@@ -567,15 +579,17 @@ TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType,
QualType DestPointee = DestReference->getPointeeType();
- return TryStaticDowncast(Self, SrcExpr->getType(), DestPointee, CStyle,
- OpRange, SrcExpr->getType(), DestType, msg);
+ return TryStaticDowncast(Self,
+ Self.Context.getCanonicalType(SrcExpr->getType()),
+ Self.Context.getCanonicalType(DestPointee), CStyle,
+ OpRange, SrcExpr->getType(), DestType, msg, Kind);
}
/// Tests whether a conversion according to C++ 5.2.9p8 is valid.
TryCastResult
TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType,
bool CStyle, const SourceRange &OpRange,
- unsigned &msg) {
+ unsigned &msg, CastExpr::CastKind &Kind) {
// C++ 5.2.9p8: An rvalue of type "pointer to cv1 B", where B is a class
// type, can be converted to an rvalue of type "pointer to cv2 D", where D
// is a class derived from B, if a valid standard conversion from "pointer
@@ -595,25 +609,27 @@ TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType,
return TC_NotApplicable;
}
- return TryStaticDowncast(Self, SrcPointer->getPointeeType(),
- DestPointer->getPointeeType(), CStyle,
- OpRange, SrcType, DestType, msg);
+ return TryStaticDowncast(Self,
+ Self.Context.getCanonicalType(SrcPointer->getPointeeType()),
+ Self.Context.getCanonicalType(DestPointer->getPointeeType()),
+ CStyle, OpRange, SrcType, DestType, msg, Kind);
}
/// TryStaticDowncast - Common functionality of TryStaticReferenceDowncast and
/// TryStaticPointerDowncast. Tests whether a static downcast from SrcType to
-/// DestType, both of which must be canonical, is possible and allowed.
+/// DestType is possible and allowed.
TryCastResult
-TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType,
+TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
bool CStyle, const SourceRange &OpRange, QualType OrigSrcType,
- QualType OrigDestType, unsigned &msg) {
+ QualType OrigDestType, unsigned &msg,
+ CastExpr::CastKind &Kind) {
// We can only work with complete types. But don't complain if it doesn't work
if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, PDiag(0)) ||
Self.RequireCompleteType(OpRange.getBegin(), DestType, PDiag(0)))
return TC_NotApplicable;
// Downcast can only happen in class hierarchies, so we need classes.
- if (!DestType->isRecordType() || !SrcType->isRecordType()) {
+ if (!DestType->getAs<RecordType>() || !SrcType->getAs<RecordType>()) {
return TC_NotApplicable;
}
@@ -669,12 +685,13 @@ TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType,
EE = PI->rend();
EI != EE; ++EI)
PathDisplayStr += EI->Base->getType().getAsString() + " -> ";
- PathDisplayStr += DestType.getAsString();
+ PathDisplayStr += QualType(DestType).getAsString();
}
}
Self.Diag(OpRange.getBegin(), diag::err_ambiguous_base_to_derived_cast)
- << SrcType.getUnqualifiedType() << DestType.getUnqualifiedType()
+ << QualType(SrcType).getUnqualifiedType()
+ << QualType(DestType).getUnqualifiedType()
<< PathDisplayStr << OpRange;
msg = 0;
return TC_Failed;
@@ -695,6 +712,7 @@ TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType,
return TC_Failed;
}
+ Kind = CastExpr::CK_BaseToDerived;
return TC_Success;
}
@@ -719,10 +737,8 @@ TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType,
}
// T == T, modulo cv
- if (Self.Context.getCanonicalType(
- SrcMemPtr->getPointeeType().getUnqualifiedType()) !=
- Self.Context.getCanonicalType(DestMemPtr->getPointeeType().
- getUnqualifiedType()))
+ if (!Self.Context.hasSameUnqualifiedType(SrcMemPtr->getPointeeType(),
+ DestMemPtr->getPointeeType()))
return TC_NotApplicable;
// B base of D
@@ -772,7 +788,7 @@ TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType,
/// An expression e can be explicitly converted to a type T using a
/// @c static_cast if the declaration "T t(e);" is well-formed [...].
TryCastResult
-TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType,
+TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
bool CStyle, const SourceRange &OpRange, unsigned &msg,
CastExpr::CastKind &Kind,
CXXMethodDecl *&ConversionDecl) {
@@ -785,27 +801,49 @@ TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType,
}
if (DestType->isReferenceType()) {
+ // All reference bindings insert implicit casts above that do the actual
+ // casting.
+ Kind = CastExpr::CK_NoOp;
+
// At this point of CheckStaticCast, if the destination is a reference,
// this has to work. There is no other way that works.
// On the other hand, if we're checking a C-style cast, we've still got
- // the reinterpret_cast way. In that case, we pass an ICS so we don't
- // get error messages.
- ImplicitConversionSequence ICS;
- bool failed = Self.CheckReferenceInit(SrcExpr, DestType,
- OpRange.getBegin(),
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- CStyle ? &ICS : 0);
- if (!failed)
+ // the reinterpret_cast way. So in C-style mode, we first try the call
+ // with an ICS to suppress errors.
+ if (CStyle) {
+ ImplicitConversionSequence ICS;
+ if(Self.CheckReferenceInit(SrcExpr, DestType, OpRange.getBegin(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false, /*ForceRValue=*/false,
+ &ICS))
+ return TC_NotApplicable;
+ }
+ // Now we're committed either way.
+ if(!Self.CheckReferenceInit(SrcExpr, DestType, OpRange.getBegin(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false, 0,
+ /*IgnoreBaseAccess=*/CStyle))
return TC_Success;
- if (CStyle)
- return TC_NotApplicable;
- // If we didn't pass the ICS, we already got an error message.
+
+ // We already got an error message.
msg = 0;
return TC_Failed;
}
+ if (DestType->isRecordType()) {
+ if (CXXConstructorDecl *Constructor
+ = Self.TryInitializationByConstructor(DestType, &SrcExpr, 1,
+ OpRange.getBegin(),
+ Sema::IK_Direct)) {
+ ConversionDecl = Constructor;
+ Kind = CastExpr::CK_ConstructorConversion;
+ return TC_Success;
+ }
+
+ return TC_NotApplicable;
+ }
+
// FIXME: To get a proper error from invalid conversions here, we need to
// reimplement more of this.
// FIXME: This does not actually perform the conversion, and thus does not
@@ -821,18 +859,12 @@ TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType,
if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion)
return TC_NotApplicable;
- if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion) {
- ConversionDecl = cast<CXXMethodDecl>(ICS.UserDefined.ConversionFunction);
- if (isa<CXXConstructorDecl>(ConversionDecl))
- Kind = CastExpr::CK_ConstructorConversion;
- else if (isa<CXXConversionDecl>(ConversionDecl))
- Kind = CastExpr::CK_UserDefinedConversion;
- } else if (ICS.ConversionKind ==
- ImplicitConversionSequence::StandardConversion) {
- // FIXME: Set the cast kind depending on which types of conversions we have.
- }
-
- return TC_Success;
+ // The conversion is possible, so commit to it.
+ Kind = CastExpr::CK_NoOp;
+ msg = 0;
+ return Self.PerformImplicitConversion(SrcExpr, DestType, ICS, "casting",
+ /*IgnoreBaseAccess*/CStyle) ?
+ TC_Failed : TC_Success;
}
/// TryConstCast - See if a const_cast from source to destination is allowed,
@@ -1104,7 +1136,7 @@ bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
if (CastTy->isDependentType() || CastExpr->isTypeDependent())
return false;
- if (!CastTy->isLValueReferenceType())
+ if (!CastTy->isLValueReferenceType() && !CastTy->isRecordType())
DefaultFunctionArrayConversion(CastExpr);
// C++ [expr.cast]p5: The conversions performed by
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index ce3fb5f..34a5b78 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "Lookup.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
@@ -307,8 +308,9 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
if (NNS->getKind() != NestedNameSpecifier::Identifier)
return 0;
- LookupResult Found;
- LookupName(Found, S, NNS->getAsIdentifier(), LookupNestedNameSpecifierName);
+ LookupResult Found(*this, NNS->getAsIdentifier(), SourceLocation(),
+ LookupNestedNameSpecifierName);
+ LookupName(Found, S);
assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet");
NamedDecl *Result = Found.getAsSingleDecl(Context);
@@ -336,6 +338,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
NestedNameSpecifier *Prefix
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ LookupResult Found(*this, &II, IdLoc, LookupNestedNameSpecifierName);
+
// Determine where to perform name lookup
DeclContext *LookupCtx = 0;
bool isDependent = false;
@@ -350,9 +354,10 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
// so long into the context associated with the prior nested-name-specifier.
LookupCtx = computeDeclContext(SS, EnteringContext);
isDependent = isDependentScopeSpecifier(SS);
+ Found.setContextRange(SS.getRange());
}
- LookupResult Found;
+
bool ObjectTypeSearchedInScope = false;
if (LookupCtx) {
// Perform "qualified" name lookup into the declaration context we
@@ -364,10 +369,9 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS))
return 0;
- LookupQualifiedName(Found, LookupCtx, &II, LookupNestedNameSpecifierName,
- false);
+ LookupQualifiedName(Found, LookupCtx);
- if (!ObjectType.isNull() && Found.getKind() == LookupResult::NotFound) {
+ if (!ObjectType.isNull() && Found.empty()) {
// C++ [basic.lookup.classref]p4:
// If the id-expression in a class member access is a qualified-id of
// the form
@@ -389,7 +393,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
// reconstruct the result from when name lookup was performed at template
// definition time.
if (S)
- LookupName(Found, S, &II, LookupNestedNameSpecifierName);
+ LookupName(Found, S);
else if (ScopeLookupResult)
Found.addDecl(ScopeLookupResult);
@@ -406,7 +410,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
return NestedNameSpecifier::Create(Context, Prefix, &II);
} else {
// Perform unqualified name lookup in the current scope.
- LookupName(Found, S, &II, LookupNestedNameSpecifierName);
+ LookupName(Found, S);
}
// FIXME: Deal with ambiguities cleanly.
@@ -423,9 +427,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
// scope, reconstruct the result from the template instantiation itself.
NamedDecl *OuterDecl;
if (S) {
- LookupResult FoundOuter;
- LookupName(FoundOuter, S, &II, LookupNestedNameSpecifierName);
- // FIXME: Handle ambiguities!
+ LookupResult FoundOuter(*this, &II, IdLoc, LookupNestedNameSpecifierName);
+ LookupName(FoundOuter, S);
OuterDecl = FoundOuter.getAsSingleDecl(Context);
} else
OuterDecl = ScopeLookupResult;
@@ -467,8 +470,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
// ordinary name lookup, which can help us produce better error
// messages.
if (!SD) {
- Found.clear();
- LookupName(Found, S, &II, LookupOrdinaryName);
+ Found.clear(LookupOrdinaryName);
+ LookupName(Found, S);
SD = Found.getAsSingleDecl(Context);
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 38b6ebe..9060fe6 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -91,6 +91,12 @@ bool Sema::CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall) {
if (Format->getType() == "printf0") {
// printf0 allows null "format" string; if so don't check format/args
unsigned format_idx = Format->getFormatIdx() - 1;
+ // Does the index refer to the implicit object argument?
+ if (isa<CXXMemberCallExpr>(TheCall)) {
+ if (format_idx == 0)
+ return false;
+ --format_idx;
+ }
if (format_idx < TheCall->getNumArgs()) {
Expr *Format = TheCall->getArg(format_idx)->IgnoreParenCasts();
if (!Format->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
@@ -204,7 +210,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
if (!HasVAListArg) {
if (const FunctionProtoType *Proto
= FDecl->getType()->getAs<FunctionProtoType>())
- HasVAListArg = !Proto->isVariadic();
+ HasVAListArg = !Proto->isVariadic();
}
CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1,
HasVAListArg ? 0 : Format->getFirstArg() - 1);
@@ -628,8 +634,7 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
return ExprError();
}
- if (Context.getCanonicalType(FAType).getUnqualifiedType() !=
- Context.getCanonicalType(SAType).getUnqualifiedType()) {
+ if (!Context.hasSameUnqualifiedType(FAType, SAType)) {
Diag(TheCall->getLocStart(), diag::err_shufflevector_incompatible_vector)
<< SourceRange(TheCall->getArg(0)->getLocStart(),
TheCall->getArg(1)->getLocEnd());
@@ -971,6 +976,18 @@ Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg,
unsigned format_idx, unsigned firstDataArg) {
const Expr *Fn = TheCall->getCallee();
+ // The way the format attribute works in GCC, the implicit this argument
+ // of member functions is counted. However, it doesn't appear in our own
+ // lists, so decrement format_idx in that case.
+ if (isa<CXXMemberCallExpr>(TheCall)) {
+ // Catch a format attribute mistakenly referring to the object argument.
+ if (format_idx == 0)
+ return;
+ --format_idx;
+ if(firstDataArg != 0)
+ --firstDataArg;
+ }
+
// CHECK: printf-like function is called with no format string.
if (format_idx >= TheCall->getNumArgs()) {
Diag(TheCall->getRParenLoc(), diag::warn_printf_missing_format_string)
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index e9df17d..9cecdad 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -13,6 +13,7 @@
#include "Sema.h"
#include "clang/Sema/CodeCompleteConsumer.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -23,13 +24,6 @@
using namespace clang;
-/// \brief Set the code-completion consumer for semantic analysis.
-void Sema::setCodeCompleteConsumer(CodeCompleteConsumer *CCC) {
- assert(((CodeCompleter != 0) != (CCC != 0)) &&
- "Already set or cleared a code-completion consumer?");
- CodeCompleter = CCC;
-}
-
namespace {
/// \brief A container of code-completion results.
class ResultBuilder {
@@ -101,6 +95,9 @@ namespace {
/// \brief Exit from the current scope.
void ExitScope();
+ /// \brief Ignore this declaration, if it is seen again.
+ void Ignore(Decl *D) { AllDeclsFound.insert(D->getCanonicalDecl()); }
+
/// \name Name lookup predicates
///
/// These predicates can be passed to the name lookup functions to filter the
@@ -187,8 +184,7 @@ getRequiredQualification(ASTContext &Context,
Context.getTypeDeclType(TD).getTypePtr());
else
assert(Parent->isTranslationUnit());
- }
-
+ }
return Result;
}
@@ -206,7 +202,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
return;
// Look through using declarations.
- if (UsingDecl *Using = dyn_cast<UsingDecl>(R.Declaration))
+ if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration))
MaybeAddResult(Result(Using->getTargetDecl(), R.Rank, R.Qualifier),
CurContext);
@@ -474,17 +470,24 @@ static unsigned CollectMemberLookupResults(DeclContext *Ctx,
for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx;
CurCtx = CurCtx->getNextContext()) {
for (DeclContext::decl_iterator D = CurCtx->decls_begin(),
- DEnd = CurCtx->decls_end();
+ DEnd = CurCtx->decls_end();
D != DEnd; ++D) {
if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
Results.MaybeAddResult(Result(ND, Rank, 0, InBaseClass), CurContext);
+
+ // Visit transparent contexts inside this context.
+ if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) {
+ if (InnerCtx->isTransparentContext())
+ CollectMemberLookupResults(InnerCtx, Rank, CurContext, Visited,
+ Results, InBaseClass);
+ }
}
}
// Traverse the contexts of inherited classes.
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(),
- BEnd = Record->bases_end();
+ BEnd = Record->bases_end();
B != BEnd; ++B) {
QualType BaseType = B->getType();
@@ -674,6 +677,8 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank,
static void AddFunctionParameterChunks(ASTContext &Context,
FunctionDecl *Function,
CodeCompletionString *Result) {
+ typedef CodeCompletionString::Chunk Chunk;
+
CodeCompletionString *CCStr = Result;
for (unsigned P = 0, N = Function->getNumParams(); P != N; ++P) {
@@ -688,7 +693,7 @@ static void AddFunctionParameterChunks(ASTContext &Context,
}
if (P != 0)
- CCStr->AddTextChunk(", ");
+ CCStr->AddChunk(Chunk(CodeCompletionString::CK_Comma));
// Format the placeholder string.
std::string PlaceholderStr;
@@ -713,6 +718,8 @@ static void AddTemplateParameterChunks(ASTContext &Context,
TemplateDecl *Template,
CodeCompletionString *Result,
unsigned MaxParameters = 0) {
+ typedef CodeCompletionString::Chunk Chunk;
+
CodeCompletionString *CCStr = Result;
bool FirstParameter = true;
@@ -768,7 +775,7 @@ static void AddTemplateParameterChunks(ASTContext &Context,
if (FirstParameter)
FirstParameter = false;
else
- CCStr->AddTextChunk(", ");
+ CCStr->AddChunk(Chunk(CodeCompletionString::CK_Comma));
// Add the placeholder string.
CCStr->AddPlaceholderChunk(PlaceholderStr.c_str());
@@ -803,6 +810,8 @@ void AddQualifierToCompletionString(CodeCompletionString *Result,
/// result is all that is needed.
CodeCompletionString *
CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
+ typedef CodeCompletionString::Chunk Chunk;
+
if (Kind == RK_Keyword)
return 0;
@@ -813,12 +822,12 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
// Format a function-like macro with placeholders for the arguments.
CodeCompletionString *Result = new CodeCompletionString;
- Result->AddTextChunk(Macro->getName().str().c_str());
- Result->AddTextChunk("(");
+ Result->AddTypedTextChunk(Macro->getName().str().c_str());
+ Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
for (MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end();
A != AEnd; ++A) {
if (A != MI->arg_begin())
- Result->AddTextChunk(", ");
+ Result->AddChunk(Chunk(CodeCompletionString::CK_Comma));
if (!MI->isVariadic() || A != AEnd - 1) {
// Non-variadic argument.
@@ -837,21 +846,28 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
Result->AddPlaceholderChunk(Arg.c_str());
}
}
- Result->AddTextChunk(")");
+ Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen));
return Result;
}
assert(Kind == RK_Declaration && "Missed a macro kind?");
NamedDecl *ND = Declaration;
+ if (StartsNestedNameSpecifier) {
+ CodeCompletionString *Result = new CodeCompletionString;
+ Result->AddTypedTextChunk(ND->getNameAsString().c_str());
+ Result->AddTextChunk("::");
+ return Result;
+ }
+
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
CodeCompletionString *Result = new CodeCompletionString;
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
S.Context);
- Result->AddTextChunk(Function->getNameAsString().c_str());
- Result->AddTextChunk("(");
+ Result->AddTypedTextChunk(Function->getNameAsString().c_str());
+ Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
AddFunctionParameterChunks(S.Context, Function, Result);
- Result->AddTextChunk(")");
+ Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen));
return Result;
}
@@ -860,7 +876,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
S.Context);
FunctionDecl *Function = FunTmpl->getTemplatedDecl();
- Result->AddTextChunk(Function->getNameAsString().c_str());
+ Result->AddTypedTextChunk(Function->getNameAsString().c_str());
// Figure out which template parameters are deduced (or have default
// arguments).
@@ -884,7 +900,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
else {
assert(isa<TemplateTemplateParmDecl>(Param));
HasDefaultArg
- = cast<TemplateTemplateParmDecl>(Param)->hasDefaultArgument();
+ = cast<TemplateTemplateParmDecl>(Param)->hasDefaultArgument();
}
if (!HasDefaultArg)
@@ -896,16 +912,16 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
// Some of the function template arguments cannot be deduced from a
// function call, so we introduce an explicit template argument list
// containing all of the arguments up to the first deducible argument.
- Result->AddTextChunk("<");
+ Result->AddChunk(Chunk(CodeCompletionString::CK_LeftAngle));
AddTemplateParameterChunks(S.Context, FunTmpl, Result,
LastDeducibleArgument);
- Result->AddTextChunk(">");
+ Result->AddChunk(Chunk(CodeCompletionString::CK_RightAngle));
}
// Add the function parameters
- Result->AddTextChunk("(");
+ Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
AddFunctionParameterChunks(S.Context, Function, Result);
- Result->AddTextChunk(")");
+ Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen));
return Result;
}
@@ -913,20 +929,51 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
CodeCompletionString *Result = new CodeCompletionString;
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
S.Context);
- Result->AddTextChunk(Template->getNameAsString().c_str());
- Result->AddTextChunk("<");
+ Result->AddTypedTextChunk(Template->getNameAsString().c_str());
+ Result->AddChunk(Chunk(CodeCompletionString::CK_LeftAngle));
AddTemplateParameterChunks(S.Context, Template, Result);
- Result->AddTextChunk(">");
+ Result->AddChunk(Chunk(CodeCompletionString::CK_RightAngle));
return Result;
}
- if (Qualifier || StartsNestedNameSpecifier) {
+ if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) {
+ CodeCompletionString *Result = new CodeCompletionString;
+ Selector Sel = Method->getSelector();
+ if (Sel.isUnarySelector()) {
+ Result->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName());
+ return Result;
+ }
+
+ Result->AddTypedTextChunk(
+ Sel.getIdentifierInfoForSlot(0)->getName().str() + std::string(":"));
+ unsigned Idx = 0;
+ for (ObjCMethodDecl::param_iterator P = Method->param_begin(),
+ PEnd = Method->param_end();
+ P != PEnd; (void)++P, ++Idx) {
+ if (Idx > 0) {
+ std::string Keyword = " ";
+ if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx))
+ Keyword += II->getName().str();
+ Keyword += ":";
+ Result->AddTextChunk(Keyword);
+ }
+
+ std::string Arg;
+ (*P)->getType().getAsStringInternal(Arg, S.Context.PrintingPolicy);
+ Arg = "(" + Arg + ")";
+ if (IdentifierInfo *II = (*P)->getIdentifier())
+ Arg += II->getName().str();
+ Result->AddPlaceholderChunk(Arg);
+ }
+
+ return Result;
+ }
+
+ if (Qualifier) {
CodeCompletionString *Result = new CodeCompletionString;
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
S.Context);
- Result->AddTextChunk(ND->getNameAsString().c_str());
- if (StartsNestedNameSpecifier)
- Result->AddTextChunk("::");
+ Result->AddTypedTextChunk(ND->getNameAsString().c_str());
return Result;
}
@@ -937,6 +984,8 @@ CodeCompletionString *
CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
unsigned CurrentArg,
Sema &S) const {
+ typedef CodeCompletionString::Chunk Chunk;
+
CodeCompletionString *Result = new CodeCompletionString;
FunctionDecl *FDecl = getFunction();
const FunctionProtoType *Proto
@@ -947,9 +996,9 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
const FunctionType *FT = getFunctionType();
Result->AddTextChunk(
FT->getResultType().getAsString(S.Context.PrintingPolicy).c_str());
- Result->AddTextChunk("(");
- Result->AddPlaceholderChunk("...");
- Result->AddTextChunk("(");
+ Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
+ Result->AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, "..."));
+ Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen));
return Result;
}
@@ -959,11 +1008,11 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
Result->AddTextChunk(
Proto->getResultType().getAsString(S.Context.PrintingPolicy).c_str());
- Result->AddTextChunk("(");
+ Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
unsigned NumParams = FDecl? FDecl->getNumParams() : Proto->getNumArgs();
for (unsigned I = 0; I != NumParams; ++I) {
if (I)
- Result->AddTextChunk(", ");
+ Result->AddChunk(Chunk(CodeCompletionString::CK_Comma));
std::string ArgString;
QualType ArgType;
@@ -978,19 +1027,20 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
ArgType.getAsStringInternal(ArgString, S.Context.PrintingPolicy);
if (I == CurrentArg)
- Result->AddPlaceholderChunk(ArgString.c_str());
+ Result->AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter,
+ ArgString.c_str()));
else
Result->AddTextChunk(ArgString.c_str());
}
if (Proto && Proto->isVariadic()) {
- Result->AddTextChunk(", ");
+ Result->AddChunk(Chunk(CodeCompletionString::CK_Comma));
if (CurrentArg < NumParams)
Result->AddTextChunk("...");
else
- Result->AddPlaceholderChunk("...");
+ Result->AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, "..."));
}
- Result->AddTextChunk(")");
+ Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen));
return Result;
}
@@ -1000,7 +1050,9 @@ namespace {
typedef CodeCompleteConsumer::Result Result;
bool isEarlierDeclarationName(DeclarationName X, DeclarationName Y) const {
- if (X.getNameKind() != Y.getNameKind())
+ if (!X.getObjCSelector().isNull() && !Y.getObjCSelector().isNull()) {
+ // Consider all selector kinds to be equivalent.
+ } else if (X.getNameKind() != Y.getNameKind())
return X.getNameKind() < Y.getNameKind();
return llvm::LowercaseString(X.getAsString())
@@ -1049,32 +1101,77 @@ namespace {
};
}
-// Add all of the known macros as code-completion results.
static void AddMacroResults(Preprocessor &PP, unsigned Rank,
ResultBuilder &Results) {
Results.EnterNewScope();
- for (Preprocessor::macro_iterator M = PP.macro_begin(), MEnd = PP.macro_end();
+ for (Preprocessor::macro_iterator M = PP.macro_begin(),
+ MEnd = PP.macro_end();
M != MEnd; ++M)
Results.MaybeAddResult(CodeCompleteConsumer::Result(M->first, Rank));
Results.ExitScope();
}
-static void HandleCodeCompleteResults(CodeCompleteConsumer *CodeCompleter,
- CodeCompleteConsumer::Result *Results,
- unsigned NumResults) {
+static void HandleCodeCompleteResults(Sema *S,
+ CodeCompleteConsumer *CodeCompleter,
+ CodeCompleteConsumer::Result *Results,
+ unsigned NumResults) {
// Sort the results by rank/kind/etc.
std::stable_sort(Results, Results + NumResults, SortCodeCompleteResult());
if (CodeCompleter)
- CodeCompleter->ProcessCodeCompleteResults(Results, NumResults);
+ CodeCompleter->ProcessCodeCompleteResults(*S, Results, NumResults);
}
void Sema::CodeCompleteOrdinaryName(Scope *S) {
ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName);
unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
0, CurContext, Results);
- AddMacroResults(PP, NextRank, Results);
- HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+ if (CodeCompleter->includeMacros())
+ AddMacroResults(PP, NextRank, Results);
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}
+
+static void AddObjCProperties(ObjCContainerDecl *Container,
+ DeclContext *CurContext,
+ ResultBuilder &Results) {
+ typedef CodeCompleteConsumer::Result Result;
+
+ // Add properties in this container.
+ for (ObjCContainerDecl::prop_iterator P = Container->prop_begin(),
+ PEnd = Container->prop_end();
+ P != PEnd;
+ ++P)
+ Results.MaybeAddResult(Result(*P, 0), CurContext);
+
+ // Add properties in referenced protocols.
+ if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
+ for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(),
+ PEnd = Protocol->protocol_end();
+ P != PEnd; ++P)
+ AddObjCProperties(*P, CurContext, Results);
+ } else if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)){
+ // Look through categories.
+ for (ObjCCategoryDecl *Category = IFace->getCategoryList();
+ Category; Category = Category->getNextClassCategory())
+ AddObjCProperties(Category, CurContext, Results);
+
+ // Look through protocols.
+ for (ObjCInterfaceDecl::protocol_iterator I = IFace->protocol_begin(),
+ E = IFace->protocol_end();
+ I != E; ++I)
+ AddObjCProperties(*I, CurContext, Results);
+
+ // Look in the superclass.
+ if (IFace->getSuperClass())
+ AddObjCProperties(IFace->getSuperClass(), CurContext, Results);
+ } else if (const ObjCCategoryDecl *Category
+ = dyn_cast<ObjCCategoryDecl>(Container)) {
+ // Look through protocols.
+ for (ObjCInterfaceDecl::protocol_iterator P = Category->protocol_begin(),
+ PEnd = Category->protocol_end();
+ P != PEnd; ++P)
+ AddObjCProperties(*P, CurContext, Results);
+ }
}
void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
@@ -1099,11 +1196,13 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
ResultBuilder Results(*this, &ResultBuilder::IsMember);
unsigned NextRank = 0;
-
+
+ Results.EnterNewScope();
if (const RecordType *Record = BaseType->getAs<RecordType>()) {
- NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank,
+ // Access to a C/C++ class, struct, or union.
+ NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank,
Record->getDecl(), Results);
-
+
if (getLangOptions().CPlusPlus) {
if (!Results.empty()) {
// The "template" keyword can follow "->" or "." in the grammar.
@@ -1117,27 +1216,63 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
break;
}
}
-
+
if (IsDependent)
Results.MaybeAddResult(Result("template", NextRank++));
}
-
+
// We could have the start of a nested-name-specifier. Add those
// results as well.
Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
- CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank,
+ CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank,
CurContext, Results);
}
+ } else if (!IsArrow && BaseType->getAsObjCInterfacePointerType()) {
+ // Objective-C property reference.
- // Add macros
- AddMacroResults(PP, NextRank, Results);
+ // Add property results based on our interface.
+ const ObjCObjectPointerType *ObjCPtr
+ = BaseType->getAsObjCInterfacePointerType();
+ assert(ObjCPtr && "Non-NULL pointer guaranteed above!");
+ AddObjCProperties(ObjCPtr->getInterfaceDecl(), CurContext, Results);
- // Hand off the results found for code completion.
- HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+ // Add properties from the protocols in a qualified interface.
+ for (ObjCObjectPointerType::qual_iterator I = ObjCPtr->qual_begin(),
+ E = ObjCPtr->qual_end();
+ I != E; ++I)
+ AddObjCProperties(*I, CurContext, Results);
- // We're done!
- return;
+ // FIXME: We could (should?) also look for "implicit" properties, identified
+ // only by the presence of nullary and unary selectors.
+ } else if ((IsArrow && BaseType->isObjCObjectPointerType()) ||
+ (!IsArrow && BaseType->isObjCInterfaceType())) {
+ // Objective-C instance variable access.
+ ObjCInterfaceDecl *Class = 0;
+ if (const ObjCObjectPointerType *ObjCPtr
+ = BaseType->getAs<ObjCObjectPointerType>())
+ Class = ObjCPtr->getInterfaceDecl();
+ else
+ Class = BaseType->getAs<ObjCInterfaceType>()->getDecl();
+
+ // Add all ivars from this class and its superclasses.
+ for (; Class; Class = Class->getSuperClass()) {
+ for (ObjCInterfaceDecl::ivar_iterator IVar = Class->ivar_begin(),
+ IVarEnd = Class->ivar_end();
+ IVar != IVarEnd; ++IVar)
+ Results.MaybeAddResult(Result(*IVar, 0), CurContext);
+ }
}
+
+ // FIXME: How do we cope with isa?
+
+ Results.ExitScope();
+
+ // Add macros
+ if (CodeCompleter->includeMacros())
+ AddMacroResults(PP, NextRank, Results);
+
+ // Hand off the results found for code completion.
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
@@ -1177,8 +1312,9 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
NextRank, CurContext, Results);
}
- AddMacroResults(PP, NextRank, Results);
- HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+ if (CodeCompleter->includeMacros())
+ AddMacroResults(PP, NextRank, Results);
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
void Sema::CodeCompleteCase(Scope *S) {
@@ -1255,8 +1391,9 @@ void Sema::CodeCompleteCase(Scope *S) {
}
Results.ExitScope();
- AddMacroResults(PP, 1, Results);
- HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+ if (CodeCompleter->includeMacros())
+ AddMacroResults(PP, 1, Results);
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
namespace {
@@ -1328,7 +1465,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
if (Cand->Viable)
Results.push_back(ResultCandidate(Cand->Function));
}
- CodeCompleter->ProcessOverloadCandidates(NumArgs, Results.data(),
+ CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(),
Results.size());
}
@@ -1350,8 +1487,9 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
if (!Results.empty() && NNS->isDependent())
Results.MaybeAddResult(CodeCompleteConsumer::Result("template", NextRank));
- AddMacroResults(PP, NextRank + 1, Results);
- HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+ if (CodeCompleter->includeMacros())
+ AddMacroResults(PP, NextRank + 1, Results);
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
void Sema::CodeCompleteUsing(Scope *S) {
@@ -1371,8 +1509,9 @@ void Sema::CodeCompleteUsing(Scope *S) {
0, CurContext, Results);
Results.ExitScope();
- AddMacroResults(PP, NextRank, Results);
- HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+ if (CodeCompleter->includeMacros())
+ AddMacroResults(PP, NextRank, Results);
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
void Sema::CodeCompleteUsingDirective(Scope *S) {
@@ -1386,8 +1525,9 @@ void Sema::CodeCompleteUsingDirective(Scope *S) {
unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
0, CurContext, Results);
Results.ExitScope();
- AddMacroResults(PP, NextRank, Results);
- HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+ if (CodeCompleter->includeMacros())
+ AddMacroResults(PP, NextRank, Results);
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
void Sema::CodeCompleteNamespaceDecl(Scope *S) {
@@ -1421,8 +1561,9 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) {
Results.ExitScope();
}
- AddMacroResults(PP, 1, Results);
- HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+ if (CodeCompleter->includeMacros())
+ AddMacroResults(PP, 1, Results);
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) {
@@ -1433,8 +1574,9 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) {
ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias);
unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
0, CurContext, Results);
- AddMacroResults(PP, NextRank, Results);
- HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+ if (CodeCompleter->includeMacros())
+ AddMacroResults(PP, NextRank, Results);
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
void Sema::CodeCompleteOperatorName(Scope *S) {
@@ -1464,8 +1606,9 @@ void Sema::CodeCompleteOperatorName(Scope *S) {
NextRank + 1, CurContext, Results);
Results.ExitScope();
- AddMacroResults(PP, NextRank, Results);
- HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+ if (CodeCompleter->includeMacros())
+ AddMacroResults(PP, NextRank, Results);
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
void Sema::CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) {
@@ -1493,5 +1636,252 @@ void Sema::CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) {
if (!(Attributes & ObjCDeclSpec::DQ_PR_getter))
Results.MaybeAddResult(CodeCompleteConsumer::Result("getter", 0));
Results.ExitScope();
- HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}
+
+/// \brief Add all of the Objective-C methods in the given Objective-C
+/// container to the set of results.
+///
+/// The container will be a class, protocol, category, or implementation of
+/// any of the above. This mether will recurse to include methods from
+/// the superclasses of classes along with their categories, protocols, and
+/// implementations.
+///
+/// \param Container the container in which we'll look to find methods.
+///
+/// \param WantInstance whether to add instance methods (only); if false, this
+/// routine will add factory methods (only).
+///
+/// \param CurContext the context in which we're performing the lookup that
+/// finds methods.
+///
+/// \param Results the structure into which we'll add results.
+static void AddObjCMethods(ObjCContainerDecl *Container,
+ bool WantInstanceMethods,
+ DeclContext *CurContext,
+ ResultBuilder &Results) {
+ typedef CodeCompleteConsumer::Result Result;
+ for (ObjCContainerDecl::method_iterator M = Container->meth_begin(),
+ MEnd = Container->meth_end();
+ M != MEnd; ++M) {
+ if ((*M)->isInstanceMethod() == WantInstanceMethods)
+ Results.MaybeAddResult(Result(*M, 0), CurContext);
+ }
+
+ ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container);
+ if (!IFace)
+ return;
+
+ // Add methods in protocols.
+ const ObjCList<ObjCProtocolDecl> &Protocols= IFace->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end();
+ I != E; ++I)
+ AddObjCMethods(*I, WantInstanceMethods, CurContext, Results);
+
+ // Add methods in categories.
+ for (ObjCCategoryDecl *CatDecl = IFace->getCategoryList(); CatDecl;
+ CatDecl = CatDecl->getNextClassCategory()) {
+ AddObjCMethods(CatDecl, WantInstanceMethods, CurContext, Results);
+
+ // Add a categories protocol methods.
+ const ObjCList<ObjCProtocolDecl> &Protocols
+ = CatDecl->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end();
+ I != E; ++I)
+ AddObjCMethods(*I, WantInstanceMethods, CurContext, Results);
+
+ // Add methods in category implementations.
+ if (ObjCCategoryImplDecl *Impl = CatDecl->getImplementation())
+ AddObjCMethods(Impl, WantInstanceMethods, CurContext, Results);
+ }
+
+ // Add methods in superclass.
+ if (IFace->getSuperClass())
+ AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, CurContext,
+ Results);
+
+ // Add methods in our implementation, if any.
+ if (ObjCImplementationDecl *Impl = IFace->getImplementation())
+ AddObjCMethods(Impl, WantInstanceMethods, CurContext, Results);
+}
+
+void Sema::CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName,
+ SourceLocation FNameLoc) {
+ typedef CodeCompleteConsumer::Result Result;
+ ObjCInterfaceDecl *CDecl = 0;
+
+ if (FName->isStr("super")) {
+ // We're sending a message to "super".
+ if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) {
+ // Figure out which interface we're in.
+ CDecl = CurMethod->getClassInterface();
+ if (!CDecl)
+ return;
+
+ // Find the superclass of this class.
+ CDecl = CDecl->getSuperClass();
+ if (!CDecl)
+ return;
+
+ if (CurMethod->isInstanceMethod()) {
+ // We are inside an instance method, which means that the message
+ // send [super ...] is actually calling an instance method on the
+ // current object. Build the super expression and handle this like
+ // an instance method.
+ QualType SuperTy = Context.getObjCInterfaceType(CDecl);
+ SuperTy = Context.getObjCObjectPointerType(SuperTy);
+ OwningExprResult Super
+ = Owned(new (Context) ObjCSuperExpr(FNameLoc, SuperTy));
+ return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get());
+ }
+
+ // Okay, we're calling a factory method in our superclass.
+ }
+ }
+
+ // If the given name refers to an interface type, retrieve the
+ // corresponding declaration.
+ if (!CDecl)
+ if (TypeTy *Ty = getTypeName(*FName, FNameLoc, S, 0, false)) {
+ QualType T = GetTypeFromParser(Ty, 0);
+ if (!T.isNull())
+ if (const ObjCInterfaceType *Interface = T->getAs<ObjCInterfaceType>())
+ CDecl = Interface->getDecl();
+ }
+
+ if (!CDecl && FName->isStr("super")) {
+ // "super" may be the name of a variable, in which case we are
+ // probably calling an instance method.
+ OwningExprResult Super = ActOnDeclarationNameExpr(S, FNameLoc, FName,
+ false, 0, false);
+ return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get());
+ }
+
+ // Add all of the factory methods in this Objective-C class, its protocols,
+ // superclasses, categories, implementation, etc.
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+ AddObjCMethods(CDecl, false, CurContext, Results);
+ Results.ExitScope();
+
+ // This also suppresses remaining diagnostics.
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}
+
+void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver) {
+ typedef CodeCompleteConsumer::Result Result;
+
+ Expr *RecExpr = static_cast<Expr *>(Receiver);
+ QualType RecType = RecExpr->getType();
+
+ // If necessary, apply function/array conversion to the receiver.
+ // C99 6.7.5.3p[7,8].
+ DefaultFunctionArrayConversion(RecExpr);
+ QualType ReceiverType = RecExpr->getType();
+
+ if (ReceiverType->isObjCIdType() || ReceiverType->isBlockPointerType()) {
+ // FIXME: We're messaging 'id'. Do we actually want to look up every method
+ // in the universe?
+ return;
+ }
+
+ // Build the set of methods we can see.
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+
+ // Handle messages to Class. This really isn't a message to an instance
+ // method, so we treat it the same way we would treat a message send to a
+ // class method.
+ if (ReceiverType->isObjCClassType() ||
+ ReceiverType->isObjCQualifiedClassType()) {
+ if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) {
+ if (ObjCInterfaceDecl *ClassDecl = CurMethod->getClassInterface())
+ AddObjCMethods(ClassDecl, false, CurContext, Results);
+ }
+ }
+ // Handle messages to a qualified ID ("id<foo>").
+ else if (const ObjCObjectPointerType *QualID
+ = ReceiverType->getAsObjCQualifiedIdType()) {
+ // Search protocols for instance methods.
+ for (ObjCObjectPointerType::qual_iterator I = QualID->qual_begin(),
+ E = QualID->qual_end();
+ I != E; ++I)
+ AddObjCMethods(*I, true, CurContext, Results);
+ }
+ // Handle messages to a pointer to interface type.
+ else if (const ObjCObjectPointerType *IFacePtr
+ = ReceiverType->getAsObjCInterfacePointerType()) {
+ // Search the class, its superclasses, etc., for instance methods.
+ AddObjCMethods(IFacePtr->getInterfaceDecl(), true, CurContext, Results);
+
+ // Search protocols for instance methods.
+ for (ObjCObjectPointerType::qual_iterator I = IFacePtr->qual_begin(),
+ E = IFacePtr->qual_end();
+ I != E; ++I)
+ AddObjCMethods(*I, true, CurContext, Results);
+ }
+
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}
+
+/// \brief Add all of the protocol declarations that we find in the given
+/// (translation unit) context.
+static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext,
+ bool OnlyForwardDeclarations,
+ ResultBuilder &Results) {
+ typedef CodeCompleteConsumer::Result Result;
+
+ for (DeclContext::decl_iterator D = Ctx->decls_begin(),
+ DEnd = Ctx->decls_end();
+ D != DEnd; ++D) {
+ // Record any protocols we find.
+ if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(*D))
+ if (!OnlyForwardDeclarations || Proto->isForwardDecl())
+ Results.MaybeAddResult(Result(Proto, 0), CurContext);
+
+ // Record any forward-declared protocols we find.
+ if (ObjCForwardProtocolDecl *Forward
+ = dyn_cast<ObjCForwardProtocolDecl>(*D)) {
+ for (ObjCForwardProtocolDecl::protocol_iterator
+ P = Forward->protocol_begin(),
+ PEnd = Forward->protocol_end();
+ P != PEnd; ++P)
+ if (!OnlyForwardDeclarations || (*P)->isForwardDecl())
+ Results.MaybeAddResult(Result(*P, 0), CurContext);
+ }
+ }
+}
+
+void Sema::CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols,
+ unsigned NumProtocols) {
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+
+ // Tell the result set to ignore all of the protocols we have
+ // already seen.
+ for (unsigned I = 0; I != NumProtocols; ++I)
+ if (ObjCProtocolDecl *Protocol = LookupProtocol(Protocols[I].first))
+ Results.Ignore(Protocol);
+
+ // Add all protocols.
+ AddProtocolResults(Context.getTranslationUnitDecl(), CurContext, false,
+ Results);
+
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}
+
+void Sema::CodeCompleteObjCProtocolDecl(Scope *) {
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+
+ // Add all protocols.
+ AddProtocolResults(Context.getTranslationUnitDecl(), CurContext, true,
+ Results);
+
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index d89cb5f..57c101b 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "Lookup.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -24,6 +25,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Template.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -86,13 +88,14 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
II, SS->getRange()).getAsOpaquePtr();
}
- LookupResult Result;
- LookupParsedName(Result, S, SS, &II, LookupOrdinaryName, false, false);
+ LookupResult Result(*this, &II, NameLoc, LookupOrdinaryName);
+ LookupParsedName(Result, S, SS, false);
NamedDecl *IIDecl = 0;
- switch (Result.getKind()) {
+ switch (Result.getResultKind()) {
case LookupResult::NotFound:
case LookupResult::FoundOverloaded:
+ case LookupResult::FoundUnresolvedValue:
return 0;
case LookupResult::Ambiguous:
@@ -101,8 +104,10 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
// diagnose the error then. If we don't do this, then the error
// about hiding the type will be immediately followed by an error
// that only makes sense if the identifier was treated like a type.
- if (Result.getAmbiguityKind() == LookupResult::AmbiguousTagHiding)
+ if (Result.getAmbiguityKind() == LookupResult::AmbiguousTagHiding) {
+ Result.suppressDiagnostics();
return 0;
+ }
// Look to see if we have a type anywhere in the list of results.
for (LookupResult::iterator Res = Result.begin(), ResEnd = Result.end();
@@ -122,6 +127,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
// perform this lookup again (e.g., as an object name), which
// will produce the ambiguity, or will complain that it expected
// a type name.
+ Result.suppressDiagnostics();
return 0;
}
@@ -129,7 +135,6 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
// ambiguity and then return that type. This might be the right
// answer, or it might not be, but it suppresses any attempt to
// perform the name lookup again.
- DiagnoseAmbiguousLookup(Result, DeclarationName(&II), NameLoc);
break;
case LookupResult::Found:
@@ -142,7 +147,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
QualType T;
if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) {
DiagnoseUseOfDecl(IIDecl, NameLoc);
-
+
// C++ [temp.local]p2:
// Within the scope of a class template specialization or
// partial specialization, when the injected-class-name is
@@ -162,10 +167,16 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
T = getQualifiedNameType(*SS, T);
} else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) {
- DiagnoseUseOfDecl(IIDecl, NameLoc);
T = Context.getObjCInterfaceType(IDecl);
- } else
+ } else if (UnresolvedUsingTypenameDecl *UUDecl =
+ dyn_cast<UnresolvedUsingTypenameDecl>(IIDecl)) {
+ // FIXME: preserve source structure information.
+ T = Context.getTypenameType(UUDecl->getTargetNestedNameSpecifier(), &II);
+ } else {
+ // If it's not plausibly a type, suppress diagnostics.
+ Result.suppressDiagnostics();
return 0;
+ }
return T.getAsOpaquePtr();
}
@@ -177,9 +188,10 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
/// where the user forgot to specify the tag.
DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
// Do a tag name lookup in this scope.
- LookupResult R;
- LookupName(R, S, &II, LookupTagName, false, false);
- if (R.getKind() == LookupResult::Found)
+ LookupResult R(*this, &II, SourceLocation(), LookupTagName);
+ LookupName(R, S, false);
+ R.suppressDiagnostics();
+ if (R.getResultKind() == LookupResult::Found)
if (const TagDecl *TD = dyn_cast<TagDecl>(R.getAsSingleDecl(Context))) {
switch (TD->getTagKind()) {
case TagDecl::TK_struct: return DeclSpec::TST_struct;
@@ -384,6 +396,26 @@ bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S) {
return IdResolver.isDeclInScope(D, Ctx, Context, S);
}
+static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
+ if (D->isUsed() || D->hasAttr<UnusedAttr>())
+ return false;
+
+ if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
+ if (const RecordType *RT = VD->getType()->getAs<RecordType>()) {
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ if (!RD->hasTrivialConstructor())
+ return false;
+ if (!RD->hasTrivialDestructor())
+ return false;
+ }
+ }
+ }
+
+ return (isa<VarDecl>(D) && !isa<ParmVarDecl>(D) &&
+ !isa<ImplicitParamDecl>(D) &&
+ D->getDeclContext()->isFunctionOrMethod());
+}
+
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
if (S->decl_empty()) return;
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
@@ -400,10 +432,8 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
if (!D->getDeclName()) continue;
// Diagnose unused variables in this scope.
- if (!D->isUsed() && !D->hasAttr<UnusedAttr>() && isa<VarDecl>(D) &&
- !isa<ParmVarDecl>(D) && !isa<ImplicitParamDecl>(D) &&
- D->getDeclContext()->isFunctionOrMethod())
- Diag(D->getLocation(), diag::warn_unused_variable) << D->getDeclName();
+ if (ShouldDiagnoseUnusedDecl(D))
+ Diag(D->getLocation(), diag::warn_unused_variable) << D->getDeclName();
// Remove this name from our lexical scope.
IdResolver.RemoveDecl(D);
@@ -1396,9 +1426,9 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
FEnd = AnonRecord->field_end();
F != FEnd; ++F) {
if ((*F)->getDeclName()) {
- LookupResult R;
- LookupQualifiedName(R, Owner, (*F)->getDeclName(),
- LookupOrdinaryName, true);
+ LookupResult R(*this, (*F)->getDeclName(), SourceLocation(),
+ LookupOrdinaryName, ForRedeclaration);
+ LookupQualifiedName(R, Owner);
NamedDecl *PrevDecl = R.getAsSingleDecl(Context);
if (PrevDecl && !isa<TagDecl>(PrevDecl)) {
// C++ [class.union]p2:
@@ -1651,7 +1681,7 @@ DeclarationName Sema::GetNameFromUnqualifiedId(UnqualifiedId &Name) {
case UnqualifiedId::IK_TemplateId: {
TemplateName TName
- = TemplateName::getFromVoidPointer(Name.TemplateId->Template);
+ = TemplateName::getFromVoidPointer(Name.TemplateId->Template);
if (TemplateDecl *Template = TName.getAsTemplateDecl())
return Template->getDeclName();
if (OverloadedFunctionDecl *Ovl = TName.getAsOverloadedFunctionDecl())
@@ -1679,9 +1709,8 @@ static bool isNearlyMatchingFunction(ASTContext &Context,
QualType DeclParamTy = Declaration->getParamDecl(Idx)->getType();
QualType DefParamTy = Definition->getParamDecl(Idx)->getType();
- DeclParamTy = Context.getCanonicalType(DeclParamTy.getNonReferenceType());
- DefParamTy = Context.getCanonicalType(DefParamTy.getNonReferenceType());
- if (DeclParamTy.getUnqualifiedType() != DefParamTy.getUnqualifiedType())
+ if (!Context.hasSameUnqualifiedType(DeclParamTy.getNonReferenceType(),
+ DefParamTy.getNonReferenceType()))
return false;
}
@@ -1766,10 +1795,10 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
NameKind = LookupRedeclarationWithLinkage;
DC = CurContext;
- LookupResult R;
- LookupName(R, S, Name, NameKind, true,
- NameKind == LookupRedeclarationWithLinkage,
- D.getIdentifierLoc());
+ LookupResult R(*this, Name, D.getIdentifierLoc(), NameKind,
+ ForRedeclaration);
+
+ LookupName(R, S, NameKind == LookupRedeclarationWithLinkage);
PrevDecl = R.getAsSingleDecl(Context);
} else { // Something like "int foo::x;"
DC = computeDeclContext(D.getCXXScopeSpec(), true);
@@ -1790,8 +1819,9 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
RequireCompleteDeclContext(D.getCXXScopeSpec()))
return DeclPtrTy();
- LookupResult Res;
- LookupQualifiedName(Res, DC, Name, LookupOrdinaryName, true);
+ LookupResult Res(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName,
+ ForRedeclaration);
+ LookupQualifiedName(Res, DC);
PrevDecl = Res.getAsSingleDecl(Context);
// C++ 7.3.1.2p2:
@@ -1821,17 +1851,22 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
if (isa<TranslationUnitDecl>(DC)) {
Diag(D.getIdentifierLoc(), diag::err_invalid_declarator_global_scope)
<< Name << D.getCXXScopeSpec().getRange();
- } else if (!CurContext->Encloses(DC)) {
- // The qualifying scope doesn't enclose the original declaration.
- // Emit diagnostic based on current scope.
- SourceLocation L = D.getIdentifierLoc();
- SourceRange R = D.getCXXScopeSpec().getRange();
- if (isa<FunctionDecl>(CurContext))
- Diag(L, diag::err_invalid_declarator_in_function) << Name << R;
- else
- Diag(L, diag::err_invalid_declarator_scope)
- << Name << cast<NamedDecl>(DC) << R;
- D.setInvalidType();
+ } else {
+ DeclContext *Cur = CurContext;
+ while (isa<LinkageSpecDecl>(Cur))
+ Cur = Cur->getParent();
+ if (!Cur->Encloses(DC)) {
+ // The qualifying scope doesn't enclose the original declaration.
+ // Emit diagnostic based on current scope.
+ SourceLocation L = D.getIdentifierLoc();
+ SourceRange R = D.getCXXScopeSpec().getRange();
+ if (isa<FunctionDecl>(Cur))
+ Diag(L, diag::err_invalid_declarator_in_function) << Name << R;
+ else
+ Diag(L, diag::err_invalid_declarator_scope)
+ << Name << cast<NamedDecl>(DC) << R;
+ D.setInvalidType();
+ }
}
}
@@ -2417,7 +2452,9 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
}
static bool isUsingDecl(Decl *D) {
- return isa<UsingDecl>(D) || isa<UnresolvedUsingDecl>(D);
+ return isa<UsingDecl>(D) ||
+ isa<UnresolvedUsingTypenameDecl>(D) ||
+ isa<UnresolvedUsingValueDecl>(D);
}
/// \brief Data used with FindOverriddenMethod
@@ -2429,7 +2466,7 @@ struct FindOverriddenMethodData {
/// \brief Member lookup function that determines whether a given C++
/// method overrides a method in a base class, to be used with
/// CXXRecordDecl::lookupInBases().
-static bool FindOverriddenMethod(CXXBaseSpecifier *Specifier,
+static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *UserData) {
RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
@@ -2588,12 +2625,27 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
return 0;
}
+ bool isStatic = SC == FunctionDecl::Static;
+
+ // [class.free]p1:
+ // Any allocation function for a class T is a static member
+ // (even if not explicitly declared static).
+ if (Name.getCXXOverloadedOperator() == OO_New ||
+ Name.getCXXOverloadedOperator() == OO_Array_New)
+ isStatic = true;
+
+ // [class.free]p6 Any deallocation function for a class X is a static member
+ // (even if not explicitly declared static).
+ if (Name.getCXXOverloadedOperator() == OO_Delete ||
+ Name.getCXXOverloadedOperator() == OO_Array_Delete)
+ isStatic = true;
+
// This is a C++ method declaration.
NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
D.getIdentifierLoc(), Name, R, DInfo,
- (SC == FunctionDecl::Static), isInline);
+ isStatic, isInline);
- isVirtualOkay = (SC != FunctionDecl::Static);
+ isVirtualOkay = !isStatic;
} else {
// Determine whether the function was written with a
// prototype. This true when:
@@ -2812,10 +2864,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
ASTTemplateArgsPtr TemplateArgsPtr(*this,
TemplateId->getTemplateArgs(),
- TemplateId->getTemplateArgIsType(),
TemplateId->NumArgs);
translateTemplateArguments(TemplateArgsPtr,
- TemplateId->getTemplateArgLocations(),
TemplateArgs);
TemplateArgsPtr.release();
@@ -2887,8 +2937,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
<< Name << DC << D.getCXXScopeSpec().getRange();
NewFD->setInvalidDecl();
- LookupResult Prev;
- LookupQualifiedName(Prev, DC, Name, LookupOrdinaryName, true);
+ LookupResult Prev(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName,
+ ForRedeclaration);
+ LookupQualifiedName(Prev, DC);
assert(!Prev.isAmbiguous() &&
"Cannot have an ambiguity in previous-declaration lookup");
for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
@@ -3068,9 +3119,13 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
// C++-specific checks.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) {
CheckConstructor(Constructor);
- } else if (isa<CXXDestructorDecl>(NewFD)) {
- CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent());
+ } else if (CXXDestructorDecl *Destructor =
+ dyn_cast<CXXDestructorDecl>(NewFD)) {
+ CXXRecordDecl *Record = Destructor->getParent();
QualType ClassType = Context.getTypeDeclType(Record);
+
+ // FIXME: Shouldn't we be able to perform thisc heck even when the class
+ // type is dependent? Both gcc and edg can handle that.
if (!ClassType->isDependentType()) {
DeclarationName Name
= Context.DeclarationNames.getCXXDestructorName(
@@ -3079,7 +3134,10 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
Diag(NewFD->getLocation(), diag::err_destructor_name);
return NewFD->setInvalidDecl();
}
+
+ CheckDestructor(Destructor);
}
+
Record->setUserDeclaredDestructor(true);
// C++ [class]p4: A POD-struct is an aggregate class that has [...] no
// user-defined destructor.
@@ -3257,8 +3315,13 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
return;
}
- if (!VDecl->getType()->isArrayType() &&
- RequireCompleteType(VDecl->getLocation(), VDecl->getType(),
+ // A definition must end up with a complete type, which means it must be
+ // complete with the restriction that an array type might be completed by the
+ // initializer; note that later code assumes this restriction.
+ QualType BaseDeclType = VDecl->getType();
+ if (const ArrayType *Array = Context.getAsIncompleteArrayType(BaseDeclType))
+ BaseDeclType = Array->getElementType();
+ if (RequireCompleteType(VDecl->getLocation(), BaseDeclType,
diag::err_typecheck_decl_incomplete_type)) {
RealDecl->setInvalidDecl();
return;
@@ -3433,6 +3496,16 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl,
return;
}
+ // An array without size is an incomplete type, and there are no special
+ // rules in C++ to make such a definition acceptable.
+ if (getLangOptions().CPlusPlus && Type->isIncompleteArrayType() &&
+ !Var->hasExternalStorage()) {
+ Diag(Var->getLocation(),
+ diag::err_typecheck_incomplete_array_needs_initializer);
+ Var->setInvalidDecl();
+ return;
+ }
+
// C++ [temp.expl.spec]p15:
// An explicit specialization of a static data member of a template is a
// definition if the declaration includes an initializer; otherwise, it
@@ -3563,7 +3636,7 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
// template <typename... Args> void f(Args... args) {
// int vals[] = { args };
// }
- const IncompleteArrayType *IAT = T->getAs<IncompleteArrayType>();
+ const IncompleteArrayType *IAT = Context.getAsIncompleteArrayType(T);
Expr *Init = IDecl->getInit();
if (IAT && Init &&
(Init->isTypeDependent() || Init->isValueDependent())) {
@@ -3987,7 +4060,15 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl))
- computeBaseOrMembersToDestroy(Destructor);
+ MarkBaseAndMemberDestructorsReferenced(Destructor);
+
+ // If any errors have occurred, clear out any temporaries that may have
+ // been leftover. This ensures that these temporaries won't be picked up for
+ // deletion in some later function.
+ if (PP.getDiagnostics().hasErrorOccurred())
+ ExprTemporaries.clear();
+
+ assert(ExprTemporaries.empty() && "Leftover temporaries in function");
return D;
}
@@ -4236,7 +4317,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
bool isStdBadAlloc = false;
bool Invalid = false;
- bool RedeclarationOnly = (TUK != TUK_Reference);
+ RedeclarationKind Redecl = (RedeclarationKind) (TUK != TUK_Reference);
if (Name && SS.isNotEmpty()) {
// We have a nested-name tag ('struct foo::bar').
@@ -4263,15 +4344,13 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
DC = computeDeclContext(SS, true);
SearchDC = DC;
// Look-up name inside 'foo::'.
- LookupResult R;
- LookupQualifiedName(R, DC, Name, LookupTagName, RedeclarationOnly);
+ LookupResult R(*this, Name, NameLoc, LookupTagName, Redecl);
+ LookupQualifiedName(R, DC);
- if (R.isAmbiguous()) {
- DiagnoseAmbiguousLookup(R, Name, NameLoc, SS.getRange());
+ if (R.isAmbiguous())
return DeclPtrTy();
- }
- if (R.getKind() == LookupResult::Found)
+ if (R.getResultKind() == LookupResult::Found)
PrevDecl = dyn_cast<TagDecl>(R.getFoundDecl());
// A tag 'foo::bar' must already exist.
@@ -4287,10 +4366,9 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// FIXME: We're looking into outer scopes here, even when we
// shouldn't be. Doing so can result in ambiguities that we
// shouldn't be diagnosing.
- LookupResult R;
- LookupName(R, S, Name, LookupTagName, RedeclarationOnly);
+ LookupResult R(*this, Name, NameLoc, LookupTagName, Redecl);
+ LookupName(R, S);
if (R.isAmbiguous()) {
- DiagnoseAmbiguousLookup(R, Name, NameLoc);
// FIXME: This is not best way to recover from case like:
//
// struct S s;
@@ -4552,8 +4630,9 @@ CreateNewDecl:
// shall not be declared with the same name as a typedef-name
// that is declared in that scope and refers to a type other
// than the class or enumeration itself.
- LookupResult Lookup;
- LookupName(Lookup, S, Name, LookupOrdinaryName, true);
+ LookupResult Lookup(*this, Name, NameLoc, LookupOrdinaryName,
+ ForRedeclaration);
+ LookupName(Lookup, S);
TypedefDecl *PrevTypedef = 0;
if (NamedDecl *Prev = Lookup.getAsSingleDecl(Context))
PrevTypedef = dyn_cast<TypedefDecl>(Prev);
@@ -4772,7 +4851,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
- NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, true);
+ NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName,
+ ForRedeclaration);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
@@ -5157,7 +5237,8 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S,
DInfo, ac, (Expr *)BitfieldWidth);
if (II) {
- NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, true);
+ NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName,
+ ForRedeclaration);
if (PrevDecl && isDeclInScope(PrevDecl, EnclosingContext, S)
&& !isa<TagDecl>(PrevDecl)) {
Diag(Loc, diag::err_duplicate_member) << II;
@@ -5352,21 +5433,25 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
llvm::APSInt EnumVal(32);
QualType EltTy;
- if (Val && !Val->isTypeDependent()) {
- // Make sure to promote the operand type to int.
- UsualUnaryConversions(Val);
- if (Val != val.get()) {
- val.release();
- val = Val;
- }
+ if (Val) {
+ if (Val->isTypeDependent())
+ EltTy = Context.DependentTy;
+ else {
+ // Make sure to promote the operand type to int.
+ UsualUnaryConversions(Val);
+ if (Val != val.get()) {
+ val.release();
+ val = Val;
+ }
- // C99 6.7.2.2p2: Make sure we have an integer constant expression.
- SourceLocation ExpLoc;
- if (!Val->isValueDependent() &&
- VerifyIntegerConstantExpression(Val, &EnumVal)) {
- Val = 0;
- } else {
- EltTy = Val->getType();
+ // C99 6.7.2.2p2: Make sure we have an integer constant expression.
+ SourceLocation ExpLoc;
+ if (!Val->isValueDependent() &&
+ VerifyIntegerConstantExpression(Val, &EnumVal)) {
+ Val = 0;
+ } else {
+ EltTy = Val->getType();
+ }
}
}
@@ -5388,6 +5473,8 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
}
}
+ assert(!EltTy.isNull() && "Enum constant with NULL type");
+
val.release();
return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy,
Val, EnumVal);
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 18f57da..c96ab46 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -862,7 +862,7 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
} else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D)) {
// We ignore weak import on properties and methods
return;
- } else {
+ } else if (!(S.LangOpts.ObjCNonFragileABI && isa<ObjCInterfaceDecl>(D))) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 2 /*variable and function*/;
return;
@@ -1008,6 +1008,38 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
}
+static void HandleCDeclAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // Attribute has no arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ // Attribute can be applied only to functions.
+ if (!isa<FunctionDecl>(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ // cdecl and fastcall attributes are mutually incompatible.
+ if (d->getAttr<FastCallAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
+ << "cdecl" << "fastcall";
+ return;
+ }
+
+ // cdecl and stdcall attributes are mutually incompatible.
+ if (d->getAttr<StdCallAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
+ << "cdecl" << "stdcall";
+ return;
+ }
+
+ d->addAttr(::new (S.Context) CDeclAttr());
+}
+
+
static void HandleStdCallAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// Attribute has no arguments.
if (Attr.getNumArgs() != 0) {
@@ -1319,7 +1351,14 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// FIXME: Do we need to bounds check?
unsigned ArgIdx = Idx.getZExtValue() - 1;
- if (HasImplicitThisParam) ArgIdx--;
+ if (HasImplicitThisParam) {
+ if (ArgIdx == 0) {
+ S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
+ << "a string type" << IdxExpr->getSourceRange();
+ return;
+ }
+ ArgIdx--;
+ }
// make sure the format string is really a string
QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
@@ -1822,6 +1861,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_analyzer_noreturn:
HandleAnalyzerNoReturnAttr (D, Attr, S); break;
case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break;
+ case AttributeList::AT_cdecl: HandleCDeclAttr (D, Attr, S); break;
case AttributeList::AT_constructor: HandleConstructorAttr(D, Attr, S); break;
case AttributeList::AT_deprecated: HandleDeprecatedAttr(D, Attr, S); break;
case AttributeList::AT_destructor: HandleDestructorAttr(D, Attr, S); break;
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index b8977cf..237a869 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -12,15 +12,17 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "Lookup.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Template.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Lex/Preprocessor.h"
-#include "clang/Parse/DeclSpec.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Compiler.h"
#include <algorithm> // for std::equal
@@ -264,9 +266,18 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
ParmVarDecl *NewParam = New->getParamDecl(p);
if (OldParam->hasDefaultArg() && NewParam->hasDefaultArg()) {
+ // FIXME: If the parameter doesn't have an identifier then the location
+ // points to the '=' which means that the fixit hint won't remove any
+ // extra spaces between the type and the '='.
+ SourceLocation Begin = NewParam->getLocation();
+ if (NewParam->getIdentifier())
+ Begin = PP.getLocForEndOfToken(Begin);
+
Diag(NewParam->getLocation(),
diag::err_param_default_argument_redefinition)
- << NewParam->getDefaultArgRange();
+ << NewParam->getDefaultArgRange()
+ << CodeModificationHint::CreateRemoval(SourceRange(Begin,
+ NewParam->getLocEnd()));
// Look for the function declaration where the default argument was
// actually written, which may be a declaration prior to Old.
@@ -577,7 +588,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
for (unsigned idx = 0; idx < NumBases; ++idx) {
QualType NewBaseType
= Context.getCanonicalType(Bases[idx]->getType());
- NewBaseType = NewBaseType.getUnqualifiedType();
+ NewBaseType = NewBaseType.getLocalUnqualifiedType();
if (KnownBaseTypes[NewBaseType]) {
// C++ [class.mi]p3:
@@ -688,6 +699,8 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
(void)DerivationOkay;
if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
+ if (InaccessibleBaseID == 0)
+ return false;
// Check that the base class can be accessed.
return CheckBaseClassAccess(Derived, Base, InaccessibleBaseID, Paths, Loc,
Name);
@@ -718,9 +731,11 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
bool
Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
- SourceLocation Loc, SourceRange Range) {
+ SourceLocation Loc, SourceRange Range,
+ bool IgnoreAccess) {
return CheckDerivedToBaseConversion(Derived, Base,
- diag::err_conv_to_inaccessible_base,
+ IgnoreAccess ? 0 :
+ diag::err_conv_to_inaccessible_base,
diag::err_ambiguous_derived_to_base_conv,
Loc, Range, DeclarationName());
}
@@ -1018,6 +1033,10 @@ Sema::MemInitResult
Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
unsigned NumArgs, SourceLocation IdLoc,
SourceLocation RParenLoc) {
+ // FIXME: CXXBaseOrMemberInitializer should only contain a single
+ // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
+ ExprTemporaries.clear();
+
// Diagnose value-uses of fields to initialize themselves, e.g.
// foo(foo)
// where foo is not also a parameter to the constructor.
@@ -1088,6 +1107,11 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
return true;
Args[0] = NewExp;
}
+
+ // FIXME: CXXBaseOrMemberInitializer should only contain a single
+ // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
+ ExprTemporaries.clear();
+
// FIXME: Perform direct initialization of the member.
return new (Context) CXXBaseOrMemberInitializer(Member, (Expr **)Args,
NumArgs, C, IdLoc, RParenLoc);
@@ -1117,8 +1141,7 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args,
const CXXBaseSpecifier *DirectBaseSpec = 0;
for (CXXRecordDecl::base_class_const_iterator Base =
ClassDecl->bases_begin(); Base != ClassDecl->bases_end(); ++Base) {
- if (Context.getCanonicalType(BaseType).getUnqualifiedType() ==
- Context.getCanonicalType(Base->getType()).getUnqualifiedType()) {
+ if (Context.hasSameUnqualifiedType(BaseType, Base->getType())) {
// We found a direct base of this type. That's what we're
// initializing.
DirectBaseSpec = &*Base;
@@ -1166,7 +1189,7 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args,
CXXConstructorDecl *C = 0;
if (!BaseType->isDependentType() && !HasDependentArg) {
DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(BaseType));
+ Context.getCanonicalType(BaseType).getUnqualifiedType());
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
C = PerformInitializationByConstructor(BaseType,
@@ -1182,22 +1205,26 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args,
}
}
+ // FIXME: CXXBaseOrMemberInitializer should only contain a single
+ // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
+ ExprTemporaries.clear();
+
return new (Context) CXXBaseOrMemberInitializer(BaseType, (Expr **)Args,
NumArgs, C, IdLoc, RParenLoc);
}
-void
+bool
Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
CXXBaseOrMemberInitializer **Initializers,
unsigned NumInitializers,
- llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases,
- llvm::SmallVectorImpl<FieldDecl *>&Fields) {
+ bool IsImplicitConstructor) {
// We need to build the initializer AST according to order of construction
// and not what user specified in the Initializers list.
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Constructor->getDeclContext());
llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit;
llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields;
bool HasDependentBaseInit = false;
+ bool HadError = false;
for (unsigned i = 0; i < NumInitializers; i++) {
CXXBaseOrMemberInitializer *Member = Initializers[i];
@@ -1239,13 +1266,8 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
if (VBase->getType()->isDependentType())
continue;
- if (CXXBaseOrMemberInitializer *Value =
- AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
- CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
- assert(BaseDecl && "SetBaseOrMemberInitializers - BaseDecl null");
- if (CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context))
- MarkDeclarationReferenced(Value->getSourceLocation(), Ctor);
+ if (CXXBaseOrMemberInitializer *Value
+ = AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
AllToInit.push_back(Value);
}
else {
@@ -1254,7 +1276,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
assert(VBaseDecl && "SetBaseOrMemberInitializers - VBaseDecl null");
CXXConstructorDecl *Ctor = VBaseDecl->getDefaultConstructor(Context);
if (!Ctor) {
- Bases.push_back(VBase);
+ Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
+ << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
+ << 0 << VBase->getType();
+ Diag(VBaseDecl->getLocation(), diag::note_previous_class_decl)
+ << Context.getTagDeclType(VBaseDecl);
+ HadError = true;
continue;
}
@@ -1265,6 +1292,9 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
+ // FIXME: CXXBaseOrMemberInitializer should only contain a single
+ // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
+ ExprTemporaries.clear();
CXXBaseOrMemberInitializer *Member =
new (Context) CXXBaseOrMemberInitializer(VBase->getType(),
CtorArgs.takeAs<Expr>(),
@@ -1284,13 +1314,8 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
// Skip dependent types.
if (Base->getType()->isDependentType())
continue;
- if (CXXBaseOrMemberInitializer *Value =
- AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
- CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- assert(BaseDecl && "SetBaseOrMemberInitializers - BaseDecl null");
- if (CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context))
- MarkDeclarationReferenced(Value->getSourceLocation(), Ctor);
+ if (CXXBaseOrMemberInitializer *Value
+ = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
AllToInit.push_back(Value);
}
else {
@@ -1299,7 +1324,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
assert(BaseDecl && "SetBaseOrMemberInitializers - BaseDecl null");
CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context);
if (!Ctor) {
- Bases.push_back(Base);
+ Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
+ << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
+ << 0 << Base->getType();
+ Diag(BaseDecl->getLocation(), diag::note_previous_class_decl)
+ << Context.getTagDeclType(BaseDecl);
+ HadError = true;
continue;
}
@@ -1310,6 +1340,9 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
+ // FIXME: CXXBaseOrMemberInitializer should only contain a single
+ // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
+ ExprTemporaries.clear();
CXXBaseOrMemberInitializer *Member =
new (Context) CXXBaseOrMemberInitializer(Base->getType(),
CtorArgs.takeAs<Expr>(),
@@ -1328,7 +1361,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
if (const RecordType *FieldClassType =
Field->getType()->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
EA = FieldClassDecl->field_end(); FA != EA; FA++) {
if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*FA)) {
@@ -1345,37 +1378,49 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
continue;
}
if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*Field)) {
- QualType FT = (*Field)->getType();
- if (const RecordType* RT = FT->getAs<RecordType>()) {
- CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RT->getDecl());
- assert(FieldRecDecl && "SetBaseOrMemberInitializers - BaseDecl null");
- if (CXXConstructorDecl *Ctor =
- FieldRecDecl->getDefaultConstructor(Context))
- MarkDeclarationReferenced(Value->getSourceLocation(), Ctor);
- }
AllToInit.push_back(Value);
continue;
}
- if ((*Field)->getType()->isDependentType()) {
- Fields.push_back(*Field);
+ if ((*Field)->getType()->isDependentType())
continue;
- }
QualType FT = Context.getBaseElementType((*Field)->getType());
if (const RecordType* RT = FT->getAs<RecordType>()) {
CXXConstructorDecl *Ctor =
cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(Context);
if (!Ctor) {
- Fields.push_back(*Field);
+ Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
+ << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
+ << 1 << (*Field)->getDeclName();
+ Diag(Field->getLocation(), diag::note_field_decl);
+ Diag(RT->getDecl()->getLocation(), diag::note_previous_class_decl)
+ << Context.getTagDeclType(RT->getDecl());
+ HadError = true;
continue;
}
-
+
+ if (FT.isConstQualified() && Ctor->isTrivial()) {
+ Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
+ << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
+ << 1 << (*Field)->getDeclName();
+ Diag((*Field)->getLocation(), diag::note_declared_at);
+ HadError = true;
+ }
+
+ // Don't create initializers for trivial constructors, since they don't
+ // actually need to be run.
+ if (Ctor->isTrivial())
+ continue;
+
ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this);
if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0),
Constructor->getLocation(), CtorArgs))
continue;
+ // FIXME: CXXBaseOrMemberInitializer should only contain a single
+ // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
+ ExprTemporaries.clear();
CXXBaseOrMemberInitializer *Member =
new (Context) CXXBaseOrMemberInitializer(*Field,CtorArgs.takeAs<Expr>(),
CtorArgs.size(), Ctor,
@@ -1383,23 +1428,21 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
SourceLocation());
AllToInit.push_back(Member);
- if (Ctor)
- MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
- if (FT.isConstQualified() && (!Ctor || Ctor->isTrivial())) {
- Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
- << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName();
- Diag((*Field)->getLocation(), diag::note_declared_at);
- }
+ MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
}
else if (FT->isReferenceType()) {
Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
- << Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getDeclName();
+ << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
+ << 0 << (*Field)->getDeclName();
Diag((*Field)->getLocation(), diag::note_declared_at);
+ HadError = true;
}
else if (FT.isConstQualified()) {
Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
- << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName();
+ << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
+ << 1 << (*Field)->getDeclName();
Diag((*Field)->getLocation(), diag::note_declared_at);
+ HadError = true;
}
}
@@ -1413,29 +1456,8 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
for (unsigned Idx = 0; Idx < NumInitializers; ++Idx)
baseOrMemberInitializers[Idx] = AllToInit[Idx];
}
-}
-
-void
-Sema::BuildBaseOrMemberInitializers(ASTContext &C,
- CXXConstructorDecl *Constructor,
- CXXBaseOrMemberInitializer **Initializers,
- unsigned NumInitializers
- ) {
- llvm::SmallVector<CXXBaseSpecifier *, 4> Bases;
- llvm::SmallVector<FieldDecl *, 4> Members;
- SetBaseOrMemberInitializers(Constructor,
- Initializers, NumInitializers, Bases, Members);
- for (unsigned int i = 0; i < Bases.size(); i++) {
- if (!Bases[i]->getType()->isDependentType())
- Diag(Bases[i]->getSourceRange().getBegin(),
- diag::err_missing_default_constructor) << 0 << Bases[i]->getType();
- }
- for (unsigned int i = 0; i < Members.size(); i++) {
- if (!Members[i]->getType()->isDependentType())
- Diag(Members[i]->getLocation(), diag::err_missing_default_constructor)
- << 1 << Members[i]->getType();
- }
+ return HadError;
}
static void *GetKeyForTopLevelField(FieldDecl *Field) {
@@ -1462,7 +1484,7 @@ static void *GetKeyForMember(CXXBaseOrMemberInitializer *Member,
if (Member->isMemberInitializer()) {
FieldDecl *Field = Member->getMember();
- // After BuildBaseOrMemberInitializers call, Field is the anonymous union
+ // After SetBaseOrMemberInitializers call, Field is the anonymous union
// data member of the class. Data member used in the initializer list is
// in AnonUnionMember field.
if (MemberMaybeAnon && Field->isAnonymousStructOrUnion())
@@ -1527,9 +1549,9 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
return;
}
- BuildBaseOrMemberInitializers(Context, Constructor,
+ SetBaseOrMemberInitializers(Constructor,
reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits),
- NumMemInits);
+ NumMemInits, false);
if (Constructor->isDependentContext())
return;
@@ -1612,77 +1634,63 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
}
void
-Sema::computeBaseOrMembersToDestroy(CXXDestructorDecl *Destructor) {
- CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Destructor->getDeclContext());
- llvm::SmallVector<uintptr_t, 32> AllToDestruct;
+Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) {
+ // Ignore dependent destructors.
+ if (Destructor->isDependentContext())
+ return;
+
+ CXXRecordDecl *ClassDecl = Destructor->getParent();
- for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(),
- E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
- if (VBase->getType()->isDependentType())
+ // Non-static data members.
+ for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
+ E = ClassDecl->field_end(); I != E; ++I) {
+ FieldDecl *Field = *I;
+
+ QualType FieldType = Context.getBaseElementType(Field->getType());
+
+ const RecordType* RT = FieldType->getAs<RecordType>();
+ if (!RT)
continue;
- // Skip over virtual bases which have trivial destructors.
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
- if (BaseClassDecl->hasTrivialDestructor())
+
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (FieldClassDecl->hasTrivialDestructor())
continue;
- if (const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context))
- MarkDeclarationReferenced(Destructor->getLocation(),
- const_cast<CXXDestructorDecl*>(Dtor));
- uintptr_t Member =
- reinterpret_cast<uintptr_t>(VBase->getType().getTypePtr())
- | CXXDestructorDecl::VBASE;
- AllToDestruct.push_back(Member);
+ const CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context);
+ MarkDeclarationReferenced(Destructor->getLocation(),
+ const_cast<CXXDestructorDecl*>(Dtor));
}
- for (CXXRecordDecl::base_class_iterator Base =
- ClassDecl->bases_begin(),
+
+ // Bases.
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
+ // Ignore virtual bases.
if (Base->isVirtual())
continue;
- if (Base->getType()->isDependentType())
- continue;
- // Skip over virtual bases which have trivial destructors.
+
+ // Ignore trivial destructors.
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (BaseClassDecl->hasTrivialDestructor())
continue;
- if (const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context))
- MarkDeclarationReferenced(Destructor->getLocation(),
- const_cast<CXXDestructorDecl*>(Dtor));
- uintptr_t Member =
- reinterpret_cast<uintptr_t>(Base->getType().getTypePtr())
- | CXXDestructorDecl::DRCTNONVBASE;
- AllToDestruct.push_back(Member);
- }
-
- // non-static data members.
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- E = ClassDecl->field_end(); Field != E; ++Field) {
- QualType FieldType = Context.getBaseElementType((*Field)->getType());
-
- if (const RecordType* RT = FieldType->getAs<RecordType>()) {
- // Skip over virtual bases which have trivial destructors.
- CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (FieldClassDecl->hasTrivialDestructor())
- continue;
- if (const CXXDestructorDecl *Dtor =
- FieldClassDecl->getDestructor(Context))
- MarkDeclarationReferenced(Destructor->getLocation(),
- const_cast<CXXDestructorDecl*>(Dtor));
- uintptr_t Member = reinterpret_cast<uintptr_t>(*Field);
- AllToDestruct.push_back(Member);
- }
+
+ const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
+ MarkDeclarationReferenced(Destructor->getLocation(),
+ const_cast<CXXDestructorDecl*>(Dtor));
}
-
- unsigned NumDestructions = AllToDestruct.size();
- if (NumDestructions > 0) {
- Destructor->setNumBaseOrMemberDestructions(NumDestructions);
- uintptr_t *BaseOrMemberDestructions =
- new (Context) uintptr_t [NumDestructions];
- // Insert in reverse order.
- for (int Idx = NumDestructions-1, i=0 ; Idx >= 0; --Idx)
- BaseOrMemberDestructions[i++] = AllToDestruct[Idx];
- Destructor->setBaseOrMemberDestructions(BaseOrMemberDestructions);
+
+ // Virtual bases.
+ for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(),
+ E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
+ // Ignore trivial destructors.
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
+ if (BaseClassDecl->hasTrivialDestructor())
+ continue;
+
+ const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
+ MarkDeclarationReferenced(Destructor->getLocation(),
+ const_cast<CXXDestructorDecl*>(Dtor));
}
}
@@ -1694,9 +1702,7 @@ void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) {
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(CDtorDecl.getAs<Decl>()))
- BuildBaseOrMemberInitializers(Context,
- Constructor,
- (CXXBaseOrMemberInitializer **)0, 0);
+ SetBaseOrMemberInitializers(Constructor, 0, 0, false);
}
namespace {
@@ -1931,7 +1937,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
}
if (RD->isAbstract())
- AbstractClassUsageDiagnoser(*this, RD);
+ (void)AbstractClassUsageDiagnoser(*this, RD);
if (!RD->isDependentType() && !RD->isInvalidDecl())
AddImplicitlyDeclaredMembersToClass(RD);
@@ -2334,13 +2340,18 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
if (!Constructor->isInvalidDecl() &&
((Constructor->getNumParams() == 1) ||
(Constructor->getNumParams() > 1 &&
- Constructor->getParamDecl(1)->hasDefaultArg()))) {
+ Constructor->getParamDecl(1)->hasDefaultArg())) &&
+ Constructor->getTemplateSpecializationKind()
+ != TSK_ImplicitInstantiation) {
QualType ParamType = Constructor->getParamDecl(0)->getType();
QualType ClassTy = Context.getTagDeclType(ClassDecl);
if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) {
SourceLocation ParamLoc = Constructor->getParamDecl(0)->getLocation();
Diag(ParamLoc, diag::err_constructor_byvalue_arg)
<< CodeModificationHint::CreateInsertion(ParamLoc, " const &");
+
+ // FIXME: Rather that making the constructor invalid, we should endeavor
+ // to fix the type.
Constructor->setInvalidDecl();
}
}
@@ -2349,6 +2360,28 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
ClassDecl->addedConstructor(Context, Constructor);
}
+/// CheckDestructor - Checks a fully-formed destructor for
+/// well-formedness, issuing any diagnostics required.
+void Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
+ CXXRecordDecl *RD = Destructor->getParent();
+
+ if (Destructor->isVirtual()) {
+ SourceLocation Loc;
+
+ if (!Destructor->isImplicit())
+ Loc = Destructor->getLocation();
+ else
+ Loc = RD->getLocation();
+
+ // If we have a virtual destructor, look up the deallocation function
+ FunctionDecl *OperatorDelete = 0;
+ DeclarationName Name =
+ Context.DeclarationNames.getCXXOperatorName(OO_Delete);
+ if (!FindDeallocationFunction(Loc, RD, Name, OperatorDelete))
+ Destructor->setOperatorDelete(OperatorDelete);
+ }
+}
+
static inline bool
FTIHasSingleVoidArgument(DeclaratorChunk::FunctionTypeInfo &FTI) {
return (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
@@ -2606,7 +2639,8 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
// in that declarative region, it is treated as an original-namespace-name.
NamedDecl *PrevDecl
- = LookupSingleName(DeclRegionScope, II, LookupOrdinaryName, true);
+ = LookupSingleName(DeclRegionScope, II, LookupOrdinaryName,
+ ForRedeclaration);
if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) {
// This is an extended namespace definition.
@@ -2714,14 +2748,14 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S,
UsingDirectiveDecl *UDir = 0;
// Lookup namespace name.
- LookupResult R;
- LookupParsedName(R, S, &SS, NamespcName, LookupNamespaceName, false);
- if (R.isAmbiguous()) {
- DiagnoseAmbiguousLookup(R, NamespcName, IdentLoc);
+ LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName);
+ LookupParsedName(R, S, &SS);
+ if (R.isAmbiguous())
return DeclPtrTy();
- }
+
if (!R.empty()) {
NamedDecl *NS = R.getFoundDecl();
+ // FIXME: Namespace aliases!
assert(isa<NamespaceDecl>(NS) && "expected namespace decl");
// C++ [namespace.udir]p1:
// A using-directive specifies that the names in the nominated
@@ -2776,7 +2810,8 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
const CXXScopeSpec &SS,
UnqualifiedId &Name,
AttributeList *AttrList,
- bool IsTypeName) {
+ bool IsTypeName,
+ SourceLocation TypenameLoc) {
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
switch (Name.getKind()) {
@@ -2802,9 +2837,11 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
}
DeclarationName TargetName = GetNameFromUnqualifiedId(Name);
- NamedDecl *UD = BuildUsingDeclaration(UsingLoc, SS,
+ NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS,
Name.getSourceRange().getBegin(),
- TargetName, AttrList, IsTypeName);
+ TargetName, AttrList,
+ /* IsInstantiation */ false,
+ IsTypeName, TypenameLoc);
if (UD) {
PushOnScopeChains(UD, S);
UD->setAccess(AS);
@@ -2813,12 +2850,46 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
return DeclPtrTy::make(UD);
}
-NamedDecl *Sema::BuildUsingDeclaration(SourceLocation UsingLoc,
+/// Builds a shadow declaration corresponding to a 'using' declaration.
+static UsingShadowDecl *BuildUsingShadowDecl(Sema &SemaRef, Scope *S,
+ AccessSpecifier AS,
+ UsingDecl *UD, NamedDecl *Orig) {
+ // FIXME: diagnose hiding, collisions
+
+ // If we resolved to another shadow declaration, just coalesce them.
+ if (isa<UsingShadowDecl>(Orig)) {
+ Orig = cast<UsingShadowDecl>(Orig)->getTargetDecl();
+ assert(!isa<UsingShadowDecl>(Orig) && "nested shadow declaration");
+ }
+
+ UsingShadowDecl *Shadow
+ = UsingShadowDecl::Create(SemaRef.Context, SemaRef.CurContext,
+ UD->getLocation(), UD, Orig);
+ UD->addShadowDecl(Shadow);
+
+ if (S)
+ SemaRef.PushOnScopeChains(Shadow, S);
+ else
+ SemaRef.CurContext->addDecl(Shadow);
+ Shadow->setAccess(AS);
+
+ return Shadow;
+}
+
+/// Builds a using declaration.
+///
+/// \param IsInstantiation - Whether this call arises from an
+/// instantiation of an unresolved using declaration. We treat
+/// the lookup differently for these declarations.
+NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
+ SourceLocation UsingLoc,
const CXXScopeSpec &SS,
SourceLocation IdentLoc,
DeclarationName Name,
AttributeList *AttrList,
- bool IsTypeName) {
+ bool IsInstantiation,
+ bool IsTypeName,
+ SourceLocation TypenameLoc) {
assert(!SS.isInvalid() && "Invalid CXXScopeSpec.");
assert(IdentLoc.isValid() && "Invalid TargetName location.");
@@ -2833,14 +2904,20 @@ NamedDecl *Sema::BuildUsingDeclaration(SourceLocation UsingLoc,
NestedNameSpecifier *NNS =
static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- if (isUnknownSpecialization(SS)) {
- return UnresolvedUsingDecl::Create(Context, CurContext, UsingLoc,
- SS.getRange(), NNS,
- IdentLoc, Name, IsTypeName);
+ DeclContext *LookupContext = computeDeclContext(SS);
+ if (!LookupContext) {
+ if (IsTypeName) {
+ return UnresolvedUsingTypenameDecl::Create(Context, CurContext,
+ UsingLoc, TypenameLoc,
+ SS.getRange(), NNS,
+ IdentLoc, Name);
+ } else {
+ return UnresolvedUsingValueDecl::Create(Context, CurContext,
+ UsingLoc, SS.getRange(), NNS,
+ IdentLoc, Name);
+ }
}
- DeclContext *LookupContext = 0;
-
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(CurContext)) {
// C++0x N2914 [namespace.udecl]p3:
// A using-declaration used as a member-declaration shall refer to a member
@@ -2848,37 +2925,36 @@ NamedDecl *Sema::BuildUsingDeclaration(SourceLocation UsingLoc,
// anonymous union that is a member of a base class of the class being
// defined, or shall refer to an enumerator for an enumeration type that is
// a member of a base class of the class being defined.
- const Type *Ty = NNS->getAsType();
- if (!Ty || !IsDerivedFrom(Context.getTagDeclType(RD), QualType(Ty, 0))) {
+
+ CXXRecordDecl *LookupRD = dyn_cast<CXXRecordDecl>(LookupContext);
+ if (!LookupRD || !RD->isDerivedFrom(LookupRD)) {
Diag(SS.getRange().getBegin(),
diag::err_using_decl_nested_name_specifier_is_not_a_base_class)
<< NNS << RD->getDeclName();
return 0;
}
-
- QualType BaseTy = Context.getCanonicalType(QualType(Ty, 0));
- LookupContext = BaseTy->getAs<RecordType>()->getDecl();
} else {
// C++0x N2914 [namespace.udecl]p8:
// A using-declaration for a class member shall be a member-declaration.
- if (NNS->getKind() == NestedNameSpecifier::TypeSpec) {
+ if (isa<CXXRecordDecl>(LookupContext)) {
Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_class_member)
<< SS.getRange();
return 0;
}
-
- // C++0x N2914 [namespace.udecl]p9:
- // In a using-declaration, a prefix :: refers to the global namespace.
- if (NNS->getKind() == NestedNameSpecifier::Global)
- LookupContext = Context.getTranslationUnitDecl();
- else
- LookupContext = NNS->getAsNamespace();
}
+ // Look up the target name. Unlike most lookups, we do not want to
+ // hide tag declarations: tag names are visible through the using
+ // declaration even if hidden by ordinary names.
+ LookupResult R(*this, Name, IdentLoc, LookupOrdinaryName);
- // Lookup target name.
- LookupResult R;
- LookupQualifiedName(R, LookupContext, Name, LookupOrdinaryName);
+ // We don't hide tags behind ordinary decls if we're in a
+ // non-dependent context, but in a dependent context, this is
+ // important for the stability of two-phase lookup.
+ if (!IsInstantiation)
+ R.setHideTags(false);
+
+ LookupQualifiedName(R, LookupContext);
if (R.empty()) {
Diag(IdentLoc, diag::err_no_member)
@@ -2886,24 +2962,49 @@ NamedDecl *Sema::BuildUsingDeclaration(SourceLocation UsingLoc,
return 0;
}
- // FIXME: handle ambiguity?
- NamedDecl *ND = R.getAsSingleDecl(Context);
-
- if (IsTypeName && !isa<TypeDecl>(ND)) {
- Diag(IdentLoc, diag::err_using_typename_non_type);
+ if (R.isAmbiguous())
return 0;
+
+ if (IsTypeName) {
+ // If we asked for a typename and got a non-type decl, error out.
+ if (R.getResultKind() != LookupResult::Found
+ || !isa<TypeDecl>(R.getFoundDecl())) {
+ Diag(IdentLoc, diag::err_using_typename_non_type);
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
+ Diag((*I)->getUnderlyingDecl()->getLocation(),
+ diag::note_using_decl_target);
+ return 0;
+ }
+ } else {
+ // If we asked for a non-typename and we got a type, error out,
+ // but only if this is an instantiation of an unresolved using
+ // decl. Otherwise just silently find the type name.
+ if (IsInstantiation &&
+ R.getResultKind() == LookupResult::Found &&
+ isa<TypeDecl>(R.getFoundDecl())) {
+ Diag(IdentLoc, diag::err_using_dependent_value_is_type);
+ Diag(R.getFoundDecl()->getLocation(), diag::note_using_decl_target);
+ return 0;
+ }
}
// C++0x N2914 [namespace.udecl]p6:
// A using-declaration shall not name a namespace.
- if (isa<NamespaceDecl>(ND)) {
+ if (R.getResultKind() == LookupResult::Found
+ && isa<NamespaceDecl>(R.getFoundDecl())) {
Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_namespace)
<< SS.getRange();
return 0;
}
- return UsingDecl::Create(Context, CurContext, IdentLoc, SS.getRange(),
- ND->getLocation(), UsingLoc, ND, NNS, IsTypeName);
+ UsingDecl *UD = UsingDecl::Create(Context, CurContext, IdentLoc,
+ SS.getRange(), UsingLoc, NNS, Name,
+ IsTypeName);
+
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
+ BuildUsingShadowDecl(*this, S, AS, UD, *I);
+
+ return UD;
}
/// getNamespaceDecl - Returns the namespace a decl represents. If the decl
@@ -2923,12 +3024,12 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
IdentifierInfo *Ident) {
// Lookup the namespace name.
- LookupResult R;
- LookupParsedName(R, S, &SS, Ident, LookupNamespaceName, false);
+ LookupResult R(*this, Ident, IdentLoc, LookupNamespaceName);
+ LookupParsedName(R, S, &SS);
// Check if we have a previous declaration with the same name.
if (NamedDecl *PrevDecl
- = LookupSingleName(S, Alias, LookupOrdinaryName, true)) {
+ = LookupSingleName(S, Alias, LookupOrdinaryName, ForRedeclaration)) {
if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) {
// We already have an alias with the same name that points to the same
// namespace, so don't create a new one.
@@ -2944,10 +3045,8 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
return DeclPtrTy();
}
- if (R.isAmbiguous()) {
- DiagnoseAmbiguousLookup(R, Ident, IdentLoc);
+ if (R.isAmbiguous())
return DeclPtrTy();
- }
if (R.empty()) {
Diag(NamespaceLoc, diag::err_expected_namespace_name) << SS.getRange();
@@ -2973,76 +3072,22 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl
= cast<CXXRecordDecl>(Constructor->getDeclContext());
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
- // Before the implicitly-declared default constructor for a class is
- // implicitly defined, all the implicitly-declared default constructors
- // for its base class and its non-static data members shall have been
- // implicitly defined.
- bool err = false;
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
- E = ClassDecl->bases_end(); Base != E; ++Base) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (!BaseClassDecl->hasTrivialConstructor()) {
- if (CXXConstructorDecl *BaseCtor =
- BaseClassDecl->getDefaultConstructor(Context))
- MarkDeclarationReferenced(CurrentLocation, BaseCtor);
- else {
- Diag(CurrentLocation, diag::err_defining_default_ctor)
- << Context.getTagDeclType(ClassDecl) << 0
- << Context.getTagDeclType(BaseClassDecl);
- Diag(BaseClassDecl->getLocation(), diag::note_previous_class_decl)
- << Context.getTagDeclType(BaseClassDecl);
- err = true;
- }
- }
- }
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- E = ClassDecl->field_end(); Field != E; ++Field) {
- QualType FieldType = Context.getCanonicalType((*Field)->getType());
- if (const ArrayType *Array = Context.getAsArrayType(FieldType))
- FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (!FieldClassDecl->hasTrivialConstructor()) {
- if (CXXConstructorDecl *FieldCtor =
- FieldClassDecl->getDefaultConstructor(Context))
- MarkDeclarationReferenced(CurrentLocation, FieldCtor);
- else {
- Diag(CurrentLocation, diag::err_defining_default_ctor)
- << Context.getTagDeclType(ClassDecl) << 1 <<
- Context.getTagDeclType(FieldClassDecl);
- Diag((*Field)->getLocation(), diag::note_field_decl);
- Diag(FieldClassDecl->getLocation(), diag::note_previous_class_decl)
- << Context.getTagDeclType(FieldClassDecl);
- err = true;
- }
- }
- } else if (FieldType->isReferenceType()) {
- Diag(CurrentLocation, diag::err_unintialized_member)
- << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
- Diag((*Field)->getLocation(), diag::note_declared_at);
- err = true;
- } else if (FieldType.isConstQualified()) {
- Diag(CurrentLocation, diag::err_unintialized_member)
- << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
- Diag((*Field)->getLocation(), diag::note_declared_at);
- err = true;
- }
- }
- if (!err)
- Constructor->setUsed();
- else
+
+ if (SetBaseOrMemberInitializers(Constructor, 0, 0, true)) {
+ Diag(CurrentLocation, diag::note_ctor_synthesized_at)
+ << Context.getTagDeclType(ClassDecl);
Constructor->setInvalidDecl();
+ } else {
+ Constructor->setUsed();
+ }
+ return;
}
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
CXXDestructorDecl *Destructor) {
assert((Destructor->isImplicit() && !Destructor->isUsed()) &&
"DefineImplicitDestructor - call it for implicit default dtor");
-
- CXXRecordDecl *ClassDecl
- = cast<CXXRecordDecl>(Destructor->getDeclContext());
+ CXXRecordDecl *ClassDecl = Destructor->getParent();
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
// C++ [class.dtor] p5
// Before the implicitly-declared default destructor for a class is
@@ -3399,6 +3444,107 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
/*DirectInit=*/true);
}
+/// \brief Add the applicable constructor candidates for an initialization
+/// by constructor.
+static void AddConstructorInitializationCandidates(Sema &SemaRef,
+ QualType ClassType,
+ Expr **Args,
+ unsigned NumArgs,
+ Sema::InitializationKind Kind,
+ OverloadCandidateSet &CandidateSet) {
+ // C++ [dcl.init]p14:
+ // If the initialization is direct-initialization, or if it is
+ // copy-initialization where the cv-unqualified version of the
+ // source type is the same class as, or a derived class of, the
+ // class of the destination, constructors are considered. The
+ // applicable constructors are enumerated (13.3.1.3), and the
+ // best one is chosen through overload resolution (13.3). The
+ // constructor so selected is called to initialize the object,
+ // with the initializer expression(s) as its argument(s). If no
+ // constructor applies, or the overload resolution is ambiguous,
+ // the initialization is ill-formed.
+ const RecordType *ClassRec = ClassType->getAs<RecordType>();
+ assert(ClassRec && "Can only initialize a class type here");
+
+ // FIXME: When we decide not to synthesize the implicitly-declared
+ // constructors, we'll need to make them appear here.
+
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl());
+ DeclarationName ConstructorName
+ = SemaRef.Context.DeclarationNames.getCXXConstructorName(
+ SemaRef.Context.getCanonicalType(ClassType).getUnqualifiedType());
+ DeclContext::lookup_const_iterator Con, ConEnd;
+ for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName);
+ Con != ConEnd; ++Con) {
+ // Find the constructor (which may be a template).
+ CXXConstructorDecl *Constructor = 0;
+ FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con);
+ if (ConstructorTmpl)
+ Constructor
+ = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
+ else
+ Constructor = cast<CXXConstructorDecl>(*Con);
+
+ if ((Kind == Sema::IK_Direct) ||
+ (Kind == Sema::IK_Copy &&
+ Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) ||
+ (Kind == Sema::IK_Default && Constructor->isDefaultConstructor())) {
+ if (ConstructorTmpl)
+ SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0,
+ Args, NumArgs, CandidateSet);
+ else
+ SemaRef.AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
+ }
+ }
+}
+
+/// \brief Attempt to perform initialization by constructor
+/// (C++ [dcl.init]p14), which may occur as part of direct-initialization or
+/// copy-initialization.
+///
+/// This routine determines whether initialization by constructor is possible,
+/// but it does not emit any diagnostics in the case where the initialization
+/// is ill-formed.
+///
+/// \param ClassType the type of the object being initialized, which must have
+/// class type.
+///
+/// \param Args the arguments provided to initialize the object
+///
+/// \param NumArgs the number of arguments provided to initialize the object
+///
+/// \param Kind the type of initialization being performed
+///
+/// \returns the constructor used to initialize the object, if successful.
+/// Otherwise, emits a diagnostic and returns NULL.
+CXXConstructorDecl *
+Sema::TryInitializationByConstructor(QualType ClassType,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation Loc,
+ InitializationKind Kind) {
+ // Build the overload candidate set
+ OverloadCandidateSet CandidateSet;
+ AddConstructorInitializationCandidates(*this, ClassType, Args, NumArgs, Kind,
+ CandidateSet);
+
+ // Determine whether we found a constructor we can use.
+ OverloadCandidateSet::iterator Best;
+ switch (BestViableFunction(CandidateSet, Loc, Best)) {
+ case OR_Success:
+ case OR_Deleted:
+ // We found a constructor. Return it.
+ return cast<CXXConstructorDecl>(Best->Function);
+
+ case OR_No_Viable_Function:
+ case OR_Ambiguous:
+ // Overload resolution failed. Return nothing.
+ return 0;
+ }
+
+ // Silence GCC warning
+ return 0;
+}
+
/// \brief Perform initialization by constructor (C++ [dcl.init]p14), which
/// may occur as part of direct-initialization or copy-initialization.
///
@@ -3428,55 +3574,13 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
DeclarationName InitEntity,
InitializationKind Kind,
ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs) {
- const RecordType *ClassRec = ClassType->getAs<RecordType>();
- assert(ClassRec && "Can only initialize a class type here");
+
+ // Build the overload candidate set
Expr **Args = (Expr **)ArgsPtr.get();
unsigned NumArgs = ArgsPtr.size();
-
- // C++ [dcl.init]p14:
- // If the initialization is direct-initialization, or if it is
- // copy-initialization where the cv-unqualified version of the
- // source type is the same class as, or a derived class of, the
- // class of the destination, constructors are considered. The
- // applicable constructors are enumerated (13.3.1.3), and the
- // best one is chosen through overload resolution (13.3). The
- // constructor so selected is called to initialize the object,
- // with the initializer expression(s) as its argument(s). If no
- // constructor applies, or the overload resolution is ambiguous,
- // the initialization is ill-formed.
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl());
OverloadCandidateSet CandidateSet;
-
- // Add constructors to the overload set.
- DeclarationName ConstructorName
- = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(ClassType.getUnqualifiedType()));
- DeclContext::lookup_const_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName);
- Con != ConEnd; ++Con) {
- // Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = 0;
- FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con);
- if (ConstructorTmpl)
- Constructor
- = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
- else
- Constructor = cast<CXXConstructorDecl>(*Con);
-
- if ((Kind == IK_Direct) ||
- (Kind == IK_Copy &&
- Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) ||
- (Kind == IK_Default && Constructor->isDefaultConstructor())) {
- if (ConstructorTmpl)
- AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0,
- Args, NumArgs, CandidateSet);
- else
- AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
- }
- }
-
- // FIXME: When we decide not to synthesize the implicitly-declared
- // constructors, we'll need to make them appear here.
+ AddConstructorInitializationCandidates(*this, ClassType, Args, NumArgs, Kind,
+ CandidateSet);
OverloadCandidateSet::iterator Best;
switch (BestViableFunction(CandidateSet, Loc, Best)) {
@@ -3613,8 +3717,8 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
QualType T1 = Context.getCanonicalType(OrigT1);
QualType T2 = Context.getCanonicalType(OrigT2);
- QualType UnqualT1 = T1.getUnqualifiedType();
- QualType UnqualT2 = T2.getUnqualifiedType();
+ QualType UnqualT1 = T1.getLocalUnqualifiedType();
+ QualType UnqualT2 = T2.getLocalUnqualifiedType();
// C++ [dcl.init.ref]p4:
// Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
@@ -3663,12 +3767,15 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
/// When @p AllowExplicit, we also permit explicit user-defined
/// conversion functions.
/// When @p ForceRValue, we unconditionally treat the initializer as an rvalue.
+/// When @p IgnoreBaseAccess, we don't do access control on to-base conversion.
+/// This is used when this is called from a C-style cast.
bool
Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
SourceLocation DeclLoc,
bool SuppressUserConversions,
bool AllowExplicit, bool ForceRValue,
- ImplicitConversionSequence *ICS) {
+ ImplicitConversionSequence *ICS,
+ bool IgnoreBaseAccess) {
assert(DeclType->isReferenceType() && "Reference init needs a reference");
QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType();
@@ -3827,6 +3934,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
ICS->UserDefined.Before = Best->Conversions[0].Standard;
ICS->UserDefined.After = Best->FinalConversion;
ICS->UserDefined.ConversionFunction = Best->Function;
+ ICS->UserDefined.EllipsisConversion = false;
assert(ICS->UserDefined.After.ReferenceBinding &&
ICS->UserDefined.After.DirectBinding &&
"Expected a direct reference binding!");
@@ -3882,7 +3990,8 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// actually happens.
if (DerivedToBase)
return CheckDerivedToBaseConversion(T2, T1, DeclLoc,
- Init->getSourceRange());
+ Init->getSourceRange(),
+ IgnoreBaseAccess);
else
return false;
}
@@ -4051,9 +4160,28 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// found in the rest of this subclause do not apply to them unless
// explicitly stated in 3.7.3.
// FIXME: Write a separate routine for checking this. For now, just allow it.
- if (Op == OO_New || Op == OO_Array_New ||
- Op == OO_Delete || Op == OO_Array_Delete)
+ if (Op == OO_Delete || Op == OO_Array_Delete)
return false;
+
+ if (Op == OO_New || Op == OO_Array_New) {
+ bool ret = false;
+ if (FunctionDecl::param_iterator Param = FnDecl->param_begin()) {
+ QualType SizeTy = Context.getCanonicalType(Context.getSizeType());
+ QualType T = Context.getCanonicalType((*Param)->getType());
+ if (!T->isDependentType() && SizeTy != T) {
+ Diag(FnDecl->getLocation(),
+ diag::err_operator_new_param_type) << FnDecl->getDeclName()
+ << SizeTy;
+ ret = true;
+ }
+ }
+ QualType ResultTy = Context.getCanonicalType(FnDecl->getResultType());
+ if (!ResultTy->isDependentType() && ResultTy != Context.VoidPtrTy)
+ return Diag(FnDecl->getLocation(),
+ diag::err_operator_new_result_type) << FnDecl->getDeclName()
+ << static_cast<QualType>(Context.VoidPtrTy);
+ return ret;
+ }
// C++ [over.oper]p6:
// An operator function shall either be a non-static member
@@ -4182,7 +4310,6 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
assert(isa<CXXMethodDecl>(FnDecl) &&
"Overloaded = not member, but not filtered.");
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
- Method->setCopyAssignment(true);
Method->getParent()->addedAssignmentOperator(Context, Method);
}
@@ -4549,8 +4676,8 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
// FIXME: handle dependent contexts
if (!DC) return DeclPtrTy();
- LookupResult R;
- LookupQualifiedName(R, DC, Name, LookupOrdinaryName, true);
+ LookupResult R(*this, Name, Loc, LookupOrdinaryName, ForRedeclaration);
+ LookupQualifiedName(R, DC);
PrevDecl = R.getAsSingleDecl(Context);
// If searching in that context implicitly found a declaration in
@@ -4584,8 +4711,8 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
while (DC->isRecord())
DC = DC->getParent();
- LookupResult R;
- LookupQualifiedName(R, DC, Name, LookupOrdinaryName, true);
+ LookupResult R(*this, Name, Loc, LookupOrdinaryName, ForRedeclaration);
+ LookupQualifiedName(R, DC);
PrevDecl = R.getAsSingleDecl(Context);
// TODO: decide what we think about using declarations.
@@ -4697,7 +4824,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
QualType COldTy = Context.getCanonicalType(OldTy);
if (CNewTy == COldTy &&
- CNewTy.getCVRQualifiers() == COldTy.getCVRQualifiers())
+ CNewTy.getLocalCVRQualifiers() == COldTy.getLocalCVRQualifiers())
return false;
// Check if the return types are covariant
@@ -4726,7 +4853,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
return true;
}
- if (NewClassTy.getUnqualifiedType() != OldClassTy.getUnqualifiedType()) {
+ if (!Context.hasSameUnqualifiedType(NewClassTy, OldClassTy)) {
// Check if the new class derives from the old class.
if (!IsDerivedFrom(NewClassTy, OldClassTy)) {
Diag(New->getLocation(),
@@ -4748,7 +4875,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
}
// The qualifiers of the return types must be the same.
- if (CNewTy.getCVRQualifiers() != COldTy.getCVRQualifiers()) {
+ if (CNewTy.getLocalCVRQualifiers() != COldTy.getLocalCVRQualifiers()) {
Diag(New->getLocation(),
diag::err_covariant_return_type_different_qualifications)
<< New->getDeclName() << NewTy << OldTy;
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 93f8d0d..0c5569c 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -112,6 +112,14 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IDecl->setLocation(AtInterfaceLoc);
IDecl->setForwardDecl(false);
IDecl->setClassLoc(ClassLoc);
+
+ // Since this ObjCInterfaceDecl was created by a forward declaration,
+ // we now add it to the DeclContext since it wasn't added before
+ // (see ActOnForwardClassDeclaration).
+ CurContext->addDecl(IDecl);
+
+ if (AttrList)
+ ProcessDeclAttributeList(TUScope, IDecl, AttrList);
}
} else {
IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc,
@@ -1113,10 +1121,46 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
assert(false && "invalid ObjCContainerDecl type.");
}
+void
+Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl* IDecl) {
+ // Rules apply in non-GC mode only
+ if (getLangOptions().getGCMode() != LangOptions::NonGC)
+ return;
+ for (ObjCContainerDecl::prop_iterator I = IDecl->prop_begin(),
+ E = IDecl->prop_end();
+ I != E; ++I) {
+ ObjCPropertyDecl *Property = (*I);
+ unsigned Attributes = Property->getPropertyAttributes();
+ // We only care about readwrite atomic property.
+ if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) ||
+ !(Attributes & ObjCPropertyDecl::OBJC_PR_readwrite))
+ continue;
+ if (const ObjCPropertyImplDecl *PIDecl
+ = IMPDecl->FindPropertyImplDecl(Property->getIdentifier())) {
+ if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
+ continue;
+ ObjCMethodDecl *GetterMethod =
+ IMPDecl->getInstanceMethod(Property->getGetterName());
+ ObjCMethodDecl *SetterMethod =
+ IMPDecl->getInstanceMethod(Property->getSetterName());
+ if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) {
+ SourceLocation MethodLoc =
+ (GetterMethod ? GetterMethod->getLocation()
+ : SetterMethod->getLocation());
+ Diag(MethodLoc, diag::warn_atomic_property_rule)
+ << Property->getIdentifier();
+ Diag(Property->getLocation(), diag::note_property_declare);
+ }
+ }
+ }
+}
+
/// ActOnForwardClassDeclaration -
Action::DeclPtrTy
Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
IdentifierInfo **IdentList,
+ SourceLocation *IdentLocs,
unsigned NumElts) {
llvm::SmallVector<ObjCInterfaceDecl*, 32> Interfaces;
@@ -1153,18 +1197,23 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
if (!IDecl) { // Not already seen? Make a forward decl.
IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
- IdentList[i],
- // FIXME: need to get the 'real'
- // identifier loc from the parser.
- AtClassLoc, true);
- PushOnScopeChains(IDecl, TUScope);
+ IdentList[i], IdentLocs[i], true);
+
+ // Push the ObjCInterfaceDecl on the scope chain but do *not* add it to
+ // the current DeclContext. This prevents clients that walk DeclContext
+ // from seeing the imaginary ObjCInterfaceDecl until it is actually
+ // declared later (if at all). We also take care to explicitly make
+ // sure this declaration is visible for name lookup.
+ PushOnScopeChains(IDecl, TUScope, false);
+ CurContext->makeDeclVisibleInContext(IDecl, true);
}
Interfaces.push_back(IDecl);
}
+ assert(Interfaces.size() == NumElts);
ObjCClassDecl *CDecl = ObjCClassDecl::Create(Context, CurContext, AtClassLoc,
- &Interfaces[0],
+ Interfaces.data(), IdentLocs,
Interfaces.size());
CurContext->addDecl(CDecl);
CheckObjCDeclScope(CDecl);
@@ -1524,12 +1573,17 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
// should be true.
if (!ClassDecl)
return;
-
+
bool isInterfaceDeclKind =
isa<ObjCInterfaceDecl>(ClassDecl) || isa<ObjCCategoryDecl>(ClassDecl)
|| isa<ObjCProtocolDecl>(ClassDecl);
bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl);
+ if (!isInterfaceDeclKind && AtEndLoc.isInvalid()) {
+ AtEndLoc = ClassDecl->getLocation();
+ Diag(AtEndLoc, diag::warn_missing_atend);
+ }
+
DeclContext *DC = dyn_cast<DeclContext>(ClassDecl);
// FIXME: Remove these and use the ObjCContainerDecl/DeclContext.
@@ -1608,8 +1662,10 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
}
if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
IC->setAtEndLoc(AtEndLoc);
- if (ObjCInterfaceDecl* IDecl = IC->getClassInterface())
+ if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) {
ImplMethodsVsClassMethods(IC, IDecl);
+ AtomicPropertySetterGetterRules(IC, IDecl);
+ }
} else if (ObjCCategoryImplDecl* CatImplClass =
dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) {
CatImplClass->setAtEndLoc(AtEndLoc);
@@ -1910,13 +1966,12 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
// with continuation class's readwrite property attribute!
unsigned PIkind = PIDecl->getPropertyAttributes();
if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) {
- unsigned assignRetainCopyNonatomic =
- (ObjCPropertyDecl::OBJC_PR_assign |
- ObjCPropertyDecl::OBJC_PR_retain |
+ unsigned retainCopyNonatomic =
+ (ObjCPropertyDecl::OBJC_PR_retain |
ObjCPropertyDecl::OBJC_PR_copy |
ObjCPropertyDecl::OBJC_PR_nonatomic);
- if ((Attributes & assignRetainCopyNonatomic) !=
- (PIkind & assignRetainCopyNonatomic)) {
+ if ((Attributes & retainCopyNonatomic) !=
+ (PIkind & retainCopyNonatomic)) {
Diag(AtLoc, diag::warn_property_attr_mismatch);
Diag(PIDecl->getLocation(), diag::note_property_declare);
}
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index bdd00b8..25af052 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -183,7 +183,7 @@ bool Sema::CheckExceptionSpecSubset(
SubIsPointer = true;
}
bool SubIsClass = CanonicalSubT->isRecordType();
- CanonicalSubT = CanonicalSubT.getUnqualifiedType();
+ CanonicalSubT = CanonicalSubT.getLocalUnqualifiedType();
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/false);
@@ -205,7 +205,7 @@ bool Sema::CheckExceptionSpecSubset(
continue;
}
}
- CanonicalSuperT = CanonicalSuperT.getUnqualifiedType();
+ CanonicalSuperT = CanonicalSuperT.getLocalUnqualifiedType();
// If the types are the same, move on to the next type in the subset.
if (CanonicalSubT == CanonicalSuperT) {
Contained = true;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index f1d6f2b..4f08ffe 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "Lookup.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -25,6 +26,7 @@
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Designator.h"
#include "clang/Parse/Scope.h"
+#include "clang/Parse/Template.h"
using namespace clang;
@@ -622,14 +624,12 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
if (Name.getKind() == UnqualifiedId::IK_TemplateId) {
ASTTemplateArgsPtr TemplateArgsPtr(*this,
Name.TemplateId->getTemplateArgs(),
- Name.TemplateId->getTemplateArgIsType(),
Name.TemplateId->NumArgs);
return ActOnTemplateIdExpr(SS,
TemplateTy::make(Name.TemplateId->Template),
Name.TemplateId->TemplateNameLoc,
Name.TemplateId->LAngleLoc,
TemplateArgsPtr,
- Name.TemplateId->getTemplateArgLocations(),
Name.TemplateId->RAngleLoc);
}
@@ -682,15 +682,11 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
isAddressOfOperand));
}
- LookupResult Lookup;
- LookupParsedName(Lookup, S, SS, Name, LookupOrdinaryName, false, true, Loc);
+ LookupResult Lookup(*this, Name, Loc, LookupOrdinaryName);
+ LookupParsedName(Lookup, S, SS, true);
- if (Lookup.isAmbiguous()) {
- DiagnoseAmbiguousLookup(Lookup, Name, Loc,
- SS && SS->isSet() ? SS->getRange()
- : SourceRange());
+ if (Lookup.isAmbiguous())
return ExprError();
- }
NamedDecl *D = Lookup.getAsSingleDecl(Context);
@@ -814,22 +810,18 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// information to check this property.
if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) {
Scope *CheckS = S;
- while (CheckS) {
+ while (CheckS && CheckS->getControlParent()) {
if (CheckS->isWithinElse() &&
CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) {
- if (Var->getType()->isBooleanType())
- ExprError(Diag(Loc, diag::warn_value_always_false)
- << Var->getDeclName());
- else
- ExprError(Diag(Loc, diag::warn_value_always_zero)
- << Var->getDeclName());
+ ExprError(Diag(Loc, diag::warn_value_always_zero)
+ << Var->getDeclName()
+ << (Var->getType()->isPointerType()? 2 :
+ Var->getType()->isBooleanType()? 1 : 0));
break;
}
- // Move up one more control parent to check again.
- CheckS = CheckS->getControlParent();
- if (CheckS)
- CheckS = CheckS->getParent();
+ // Move to the parent of this scope.
+ CheckS = CheckS->getParent();
}
}
} else if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D)) {
@@ -986,7 +978,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
else if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
return BuildDeclRefExpr(Template, Context.OverloadTy, Loc,
false, false, SS);
- else if (UnresolvedUsingDecl *UD = dyn_cast<UnresolvedUsingDecl>(D))
+ else if (UnresolvedUsingValueDecl *UD = dyn_cast<UnresolvedUsingValueDecl>(D))
return BuildDeclRefExpr(UD, Context.DependentTy, Loc,
/*TypeDependent=*/true,
/*ValueDependent=*/true, SS);
@@ -1441,10 +1433,6 @@ QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) {
Action::OwningExprResult
Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Kind, ExprArg Input) {
- // Since this might be a postfix expression, get rid of ParenListExprs.
- Input = MaybeConvertParenListExprToParenExpr(S, move(Input));
- Expr *Arg = (Expr *)Input.get();
-
UnaryOperator::Opcode Opc;
switch (Kind) {
default: assert(0 && "Unknown unary op!");
@@ -1452,124 +1440,7 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
case tok::minusminus: Opc = UnaryOperator::PostDec; break;
}
- if (getLangOptions().CPlusPlus &&
- (Arg->getType()->isRecordType() || Arg->getType()->isEnumeralType())) {
- // Which overloaded operator?
- OverloadedOperatorKind OverOp =
- (Opc == UnaryOperator::PostInc)? OO_PlusPlus : OO_MinusMinus;
-
- // C++ [over.inc]p1:
- //
- // [...] If the function is a member function with one
- // parameter (which shall be of type int) or a non-member
- // function with two parameters (the second of which shall be
- // of type int), it defines the postfix increment operator ++
- // for objects of that type. When the postfix increment is
- // called as a result of using the ++ operator, the int
- // argument will have value zero.
- Expr *Args[2] = {
- Arg,
- new (Context) IntegerLiteral(llvm::APInt(Context.Target.getIntWidth(), 0,
- /*isSigned=*/true), Context.IntTy, SourceLocation())
- };
-
- // Build the candidate set for overloading
- OverloadCandidateSet CandidateSet;
- AddOperatorCandidates(OverOp, S, OpLoc, Args, 2, CandidateSet);
-
- // Perform overload resolution.
- OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, OpLoc, Best)) {
- case OR_Success: {
- // We found a built-in operator or an overloaded operator.
- FunctionDecl *FnDecl = Best->Function;
-
- if (FnDecl) {
- // We matched an overloaded operator. Build a call to that
- // operator.
-
- // Convert the arguments.
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
- if (PerformObjectArgumentInitialization(Arg, Method))
- return ExprError();
- } else {
- // Convert the arguments.
- if (PerformCopyInitialization(Arg,
- FnDecl->getParamDecl(0)->getType(),
- "passing"))
- return ExprError();
- }
-
- // Determine the result type
- QualType ResultTy = FnDecl->getResultType().getNonReferenceType();
-
- // Build the actual expression node.
- Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
- SourceLocation());
- UsualUnaryConversions(FnExpr);
-
- Input.release();
- Args[0] = Arg;
-
- ExprOwningPtr<CXXOperatorCallExpr>
- TheCall(this, new (Context) CXXOperatorCallExpr(Context, OverOp,
- FnExpr, Args, 2,
- ResultTy, OpLoc));
-
- if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(),
- FnDecl))
- return ExprError();
- return Owned(TheCall.release());
-
- } else {
- // We matched a built-in operator. Convert the arguments, then
- // break out so that we will build the appropriate built-in
- // operator node.
- if (PerformCopyInitialization(Arg, Best->BuiltinTypes.ParamTypes[0],
- "passing"))
- return ExprError();
-
- break;
- }
- }
-
- case OR_No_Viable_Function: {
- // No viable function; try checking this as a built-in operator, which
- // will fail and provide a diagnostic. Then, print the overload
- // candidates.
- OwningExprResult Result = CreateBuiltinUnaryOp(OpLoc, Opc, move(Input));
- assert(Result.isInvalid() &&
- "C++ postfix-unary operator overloading is missing candidates!");
- if (Result.isInvalid())
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
-
- return move(Result);
- }
-
- case OR_Ambiguous:
- Diag(OpLoc, diag::err_ovl_ambiguous_oper)
- << UnaryOperator::getOpcodeStr(Opc)
- << Arg->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
- return ExprError();
-
- case OR_Deleted:
- Diag(OpLoc, diag::err_ovl_deleted_oper)
- << Best->Function->isDeleted()
- << UnaryOperator::getOpcodeStr(Opc)
- << Arg->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
- return ExprError();
- }
-
- // Either we found no viable overloaded operator or we matched a
- // built-in operator. In either case, fall through to trying to
- // build a built-in operation.
- }
-
- Input.release();
- Input = Arg;
- return CreateBuiltinUnaryOp(OpLoc, Opc, move(Input));
+ return BuildUnaryOp(S, OpLoc, Opc, move(Input));
}
Action::OwningExprResult
@@ -1886,6 +1757,38 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
DefaultFunctionArrayConversion(BaseExpr);
QualType BaseType = BaseExpr->getType();
+
+ // If the user is trying to apply -> or . to a function pointer
+ // type, it's probably because the forgot parentheses to call that
+ // function. Suggest the addition of those parentheses, build the
+ // call, and continue on.
+ if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
+ if (const FunctionProtoType *Fun
+ = Ptr->getPointeeType()->getAs<FunctionProtoType>()) {
+ QualType ResultTy = Fun->getResultType();
+ if (Fun->getNumArgs() == 0 &&
+ ((OpKind == tok::period && ResultTy->isRecordType()) ||
+ (OpKind == tok::arrow && ResultTy->isPointerType() &&
+ ResultTy->getAs<PointerType>()->getPointeeType()
+ ->isRecordType()))) {
+ SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd());
+ Diag(Loc, diag::err_member_reference_needs_call)
+ << QualType(Fun, 0)
+ << CodeModificationHint::CreateInsertion(Loc, "()");
+
+ OwningExprResult NewBase
+ = ActOnCallExpr(S, ExprArg(*this, BaseExpr), Loc,
+ MultiExprArg(*this, 0, 0), 0, Loc);
+ if (NewBase.isInvalid())
+ return move(NewBase);
+
+ BaseExpr = NewBase.takeAs<Expr>();
+ DefaultFunctionArrayConversion(BaseExpr);
+ BaseType = BaseExpr->getType();
+ }
+ }
+ }
+
// If this is an Objective-C pseudo-builtin and a definition is provided then
// use that.
if (BaseType->isObjCIdType()) {
@@ -2048,17 +1951,14 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
}
// The record definition is complete, now make sure the member is valid.
- LookupResult Result;
- LookupQualifiedName(Result, DC, MemberName, LookupMemberName, false);
+ LookupResult Result(*this, MemberName, MemberLoc, LookupMemberName);
+ LookupQualifiedName(Result, DC);
if (Result.empty())
return ExprError(Diag(MemberLoc, diag::err_no_member)
<< MemberName << DC << BaseExpr->getSourceRange());
- if (Result.isAmbiguous()) {
- DiagnoseAmbiguousLookup(Result, MemberName, MemberLoc,
- BaseExpr->getSourceRange());
+ if (Result.isAmbiguous())
return ExprError();
- }
NamedDecl *MemberDecl = Result.getAsSingleDecl(Context);
@@ -2356,16 +2256,6 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
MemberLoc, BaseExpr));
}
- for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
- E = OPT->qual_end(); I != E; ++I)
- if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
- // Check whether we can reference this property.
- if (DiagnoseUseOfDecl(PD, MemberLoc))
- return ExprError();
-
- return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
- MemberLoc, BaseExpr));
- }
// If that failed, look for an "implicit" property by seeing if the nullary
// selector is implemented.
@@ -2441,18 +2331,6 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
<< BaseType << BaseExpr->getSourceRange();
- // If the user is trying to apply -> or . to a function or function
- // pointer, it's probably because they forgot parentheses to call
- // the function. Suggest the addition of those parentheses.
- if (BaseType == Context.OverloadTy ||
- BaseType->isFunctionType() ||
- (BaseType->isPointerType() &&
- BaseType->getAs<PointerType>()->isFunctionType())) {
- SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd());
- Diag(Loc, diag::note_member_reference_needs_call)
- << CodeModificationHint::CreateInsertion(Loc, "()");
- }
-
return ExprError();
}
@@ -2485,12 +2363,10 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg Base,
// Translate the parser's template argument list in our AST format.
ASTTemplateArgsPtr TemplateArgsPtr(*this,
Member.TemplateId->getTemplateArgs(),
- Member.TemplateId->getTemplateArgIsType(),
Member.TemplateId->NumArgs);
llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs;
translateTemplateArguments(TemplateArgsPtr,
- Member.TemplateId->getTemplateArgLocations(),
TemplateArgs);
TemplateArgsPtr.release();
@@ -2639,6 +2515,9 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
// Pass the argument.
if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
return true;
+
+ if (!ProtoArgType->isReferenceType())
+ Arg = MaybeBindToTemporary(Arg).takeAs<Expr>();
} else {
ParmVarDecl *Param = FDecl->getParamDecl(i);
@@ -2663,7 +2542,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
CallType = VariadicMethod;
// Promote the arguments (C99 6.5.2.2p7).
- for (unsigned i = NumArgsInProto; i != NumArgs; i++) {
+ for (unsigned i = NumArgsInProto; i < NumArgs; i++) {
Expr *Arg = Args[i];
Invalid |= DefaultVariadicArgumentPromotion(Arg, CallType);
Call->setArg(i, Arg);
@@ -3054,8 +2933,7 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist,
static CastExpr::CastKind getScalarCastKind(ASTContext &Context,
QualType SrcTy, QualType DestTy) {
- if (Context.getCanonicalType(SrcTy).getUnqualifiedType() ==
- Context.getCanonicalType(DestTy).getUnqualifiedType())
+ if (Context.hasSameUnqualifiedType(SrcTy, DestTy))
return CastExpr::CK_NoOp;
if (SrcTy->hasPointerRepresentation()) {
@@ -3106,8 +2984,7 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
}
if (!castType->isScalarType() && !castType->isVectorType()) {
- if (Context.getCanonicalType(castType).getUnqualifiedType() ==
- Context.getCanonicalType(castExpr->getType().getUnqualifiedType()) &&
+ if (Context.hasSameUnqualifiedType(castType, castExpr->getType()) &&
(castType->isStructureType() || castType->isUnionType())) {
// GCC struct/union extension: allow cast to self.
// FIXME: Check that the cast destination type is complete.
@@ -3123,8 +3000,8 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
RecordDecl::field_iterator Field, FieldEnd;
for (Field = RD->field_begin(), FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
- if (Context.getCanonicalType(Field->getType()).getUnqualifiedType() ==
- Context.getCanonicalType(castExpr->getType()).getUnqualifiedType()) {
+ if (Context.hasSameUnqualifiedType(Field->getType(),
+ castExpr->getType())) {
Diag(TyR.getBegin(), diag::ext_typecheck_cast_to_union)
<< castExpr->getSourceRange();
break;
@@ -3570,9 +3447,9 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
= Context.getQualifiedType(rhptee, lhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
// Add qualifiers if necessary.
- ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp);
+ ImpCastExprToType(RHS, destType, CastExpr::CK_NoOp);
// Promote to void*.
- ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast);
+ ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast);
return destType;
}
@@ -3731,6 +3608,24 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
return ConvTy;
return IncompatiblePointerSign;
}
+
+ // If we are a multi-level pointer, it's possible that our issue is simply
+ // one of qualification - e.g. char ** -> const char ** is not allowed. If
+ // the eventual target type is the same and the pointers have the same
+ // level of indirection, this must be the issue.
+ if (lhptee->isPointerType() && rhptee->isPointerType()) {
+ do {
+ lhptee = lhptee->getAs<PointerType>()->getPointeeType();
+ rhptee = rhptee->getAs<PointerType>()->getPointeeType();
+
+ lhptee = Context.getCanonicalType(lhptee);
+ rhptee = Context.getCanonicalType(rhptee);
+ } while (lhptee->isPointerType() && rhptee->isPointerType());
+
+ if (Context.hasSameUnqualifiedType(lhptee, rhptee))
+ return IncompatibleNestedPointerQualifiers;
+ }
+
// General pointer incompatibility takes priority over qualifiers.
return IncompatiblePointer;
}
@@ -3757,7 +3652,7 @@ Sema::CheckBlockPointerTypesForAssignment(QualType lhsType,
AssignConvertType ConvTy = Compatible;
// For blocks we enforce that qualifiers are identical.
- if (lhptee.getCVRQualifiers() != rhptee.getCVRQualifiers())
+ if (lhptee.getLocalCVRQualifiers() != rhptee.getLocalCVRQualifiers())
ConvTy = CompatiblePointerDiscardsQualifiers;
if (!Context.typesAreCompatible(lhptee, rhptee))
@@ -4429,26 +4324,51 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
return LHSTy;
}
-/// Implements -Wsign-compare.
+/// \brief Implements -Wsign-compare.
+///
+/// \param lex the left-hand expression
+/// \param rex the right-hand expression
+/// \param OpLoc the location of the joining operator
+/// \param Equality whether this is an "equality-like" join, which
+/// suppresses the warning in some cases
void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc,
- const PartialDiagnostic &PD) {
+ const PartialDiagnostic &PD, bool Equality) {
+ // Don't warn if we're in an unevaluated context.
+ if (ExprEvalContext == Unevaluated)
+ return;
+
QualType lt = lex->getType(), rt = rex->getType();
// Only warn if both operands are integral.
if (!lt->isIntegerType() || !rt->isIntegerType())
return;
+ // If either expression is value-dependent, don't warn. We'll get another
+ // chance at instantiation time.
+ if (lex->isValueDependent() || rex->isValueDependent())
+ return;
+
// The rule is that the signed operand becomes unsigned, so isolate the
// signed operand.
- Expr *signedOperand;
+ Expr *signedOperand, *unsignedOperand;
if (lt->isSignedIntegerType()) {
if (rt->isSignedIntegerType()) return;
signedOperand = lex;
+ unsignedOperand = rex;
} else {
if (!rt->isSignedIntegerType()) return;
signedOperand = rex;
+ unsignedOperand = lex;
}
+ // If the unsigned type is strictly smaller than the signed type,
+ // then (1) the result type will be signed and (2) the unsigned
+ // value will fit fully within the signed type, and thus the result
+ // of the comparison will be exact.
+ if (Context.getIntWidth(signedOperand->getType()) >
+ Context.getIntWidth(unsignedOperand->getType()))
+ return;
+
// If the value is a non-negative integer constant, then the
// signed->unsigned conversion won't change it.
llvm::APSInt value;
@@ -4459,6 +4379,20 @@ void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc,
return;
}
+ if (Equality) {
+ // For (in)equality comparisons, if the unsigned operand is a
+ // constant which cannot collide with a overflowed signed operand,
+ // then reinterpreting the signed operand as unsigned will not
+ // change the result of the comparison.
+ if (unsignedOperand->isIntegerConstantExpr(value, Context)) {
+ assert(!value.isSigned() && "result of unsigned expression is signed");
+
+ // 2's complement: test the top bit.
+ if (value.isNonNegative())
+ return;
+ }
+ }
+
Diag(OpLoc, PD)
<< lex->getType() << rex->getType()
<< lex->getSourceRange() << rex->getSourceRange();
@@ -4472,7 +4406,8 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
return CheckVectorCompareOperands(lex, rex, Loc, isRelational);
- CheckSignCompare(lex, rex, Loc, diag::warn_mixed_sign_comparison);
+ CheckSignCompare(lex, rex, Loc, diag::warn_mixed_sign_comparison,
+ (Opc == BinaryOperator::EQ || Opc == BinaryOperator::NE));
// C99 6.5.8p3 / C99 6.5.9p4
if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
@@ -5637,7 +5572,8 @@ Action::OwningExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
UnaryOperator::Opcode Opc,
ExprArg input) {
Expr *Input = (Expr*)input.get();
- if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType()) {
+ if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType() &&
+ Opc != UnaryOperator::Extension) {
// Find all of the overloaded operators visible from this
// point. We perform both an operator-name lookup from the local
// scope and an argument-dependent lookup based on the types of
@@ -5814,8 +5750,8 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
}
}
- LookupResult R;
- LookupQualifiedName(R, RD, OC.U.IdentInfo, LookupMemberName);
+ LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName);
+ LookupQualifiedName(R, RD);
FieldDecl *MemberDecl
= dyn_cast_or_null<FieldDecl>(R.getAsSingleDecl(Context));
@@ -5828,7 +5764,7 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
// FIXME: Verify that MemberDecl isn't a bitfield.
if (cast<RecordDecl>(MemberDecl->getDeclContext())->isAnonymousStructOrUnion()) {
Res = BuildAnonymousStructUnionMemberReference(
- SourceLocation(), MemberDecl, Res, SourceLocation()).takeAs<Expr>();
+ OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>();
} else {
// MemberDecl->getType() doesn't get the right qualifiers, but it
// doesn't matter here.
@@ -6127,6 +6063,34 @@ Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
return Owned(new (Context) GNUNullExpr(Ty, TokenLoc));
}
+static void
+MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef,
+ QualType DstType,
+ Expr *SrcExpr,
+ CodeModificationHint &Hint) {
+ if (!SemaRef.getLangOptions().ObjC1)
+ return;
+
+ const ObjCObjectPointerType *PT = DstType->getAs<ObjCObjectPointerType>();
+ if (!PT)
+ return;
+
+ // Check if the destination is of type 'id'.
+ if (!PT->isObjCIdType()) {
+ // Check if the destination is the 'NSString' interface.
+ const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
+ if (!ID || !ID->getIdentifier()->isStr("NSString"))
+ return;
+ }
+
+ // Strip off any parens and casts.
+ StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr->IgnoreParenCasts());
+ if (!SL || SL->isWide())
+ return;
+
+ Hint = CodeModificationHint::CreateInsertion(SL->getLocStart(), "@");
+}
+
bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
SourceLocation Loc,
QualType DstType, QualType SrcType,
@@ -6134,6 +6098,8 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
// Decode the result (notice that AST's are still created for extensions).
bool isInvalid = false;
unsigned DiagKind;
+ CodeModificationHint Hint;
+
switch (ConvTy) {
default: assert(0 && "Unknown conversion type");
case Compatible: return false;
@@ -6144,6 +6110,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
DiagKind = diag::ext_typecheck_convert_int_pointer;
break;
case IncompatiblePointer:
+ MakeObjCStringLiteralCodeModificationHint(*this, DstType, SrcExpr, Hint);
DiagKind = diag::ext_typecheck_convert_incompatible_pointer;
break;
case IncompatiblePointerSign:
@@ -6167,6 +6134,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
return false;
DiagKind = diag::ext_typecheck_convert_discards_qualifiers;
break;
+ case IncompatibleNestedPointerQualifiers:
+ DiagKind = diag::ext_nested_pointer_qualifier_mismatch;
+ break;
case IntToBlockPointer:
DiagKind = diag::err_int_to_block_pointer;
break;
@@ -6188,7 +6158,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
}
Diag(Loc, DiagKind) << DstType << SrcType << Flavor
- << SrcExpr->getSourceRange();
+ << SrcExpr->getSourceRange() << Hint;
return isInvalid;
}
@@ -6405,11 +6375,29 @@ bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
SourceLocation Loc;
+ unsigned diagnostic = diag::warn_condition_is_assignment;
+
if (isa<BinaryOperator>(E)) {
BinaryOperator *Op = cast<BinaryOperator>(E);
if (Op->getOpcode() != BinaryOperator::Assign)
return;
+ // Greylist some idioms by putting them into a warning subcategory.
+ if (ObjCMessageExpr *ME
+ = dyn_cast<ObjCMessageExpr>(Op->getRHS()->IgnoreParenCasts())) {
+ Selector Sel = ME->getSelector();
+
+ // self = [<foo> init...]
+ if (isSelfExpr(Op->getLHS())
+ && Sel.getIdentifierInfoForSlot(0)->getName().startswith("init"))
+ diagnostic = diag::warn_condition_is_idiomatic_assignment;
+
+ // <foo> = [<bar> nextObject]
+ else if (Sel.isUnarySelector() &&
+ Sel.getIdentifierInfoForSlot(0)->getName() == "nextObject")
+ diagnostic = diag::warn_condition_is_idiomatic_assignment;
+ }
+
Loc = Op->getOperatorLoc();
} else if (isa<CXXOperatorCallExpr>(E)) {
CXXOperatorCallExpr *Op = cast<CXXOperatorCallExpr>(E);
@@ -6425,7 +6413,7 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
SourceLocation Open = E->getSourceRange().getBegin();
SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd());
- Diag(Loc, diag::warn_condition_is_assignment)
+ Diag(Loc, diagnostic)
<< E->getSourceRange()
<< CodeModificationHint::CreateInsertion(Open, "(")
<< CodeModificationHint::CreateInsertion(Close, ")");
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index dc57681..0eea169 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "Lookup.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/ExprCXX.h"
@@ -34,8 +35,8 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
TyOrExpr = GetTypeFromParser(TyOrExpr).getAsOpaquePtr();
IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info");
- LookupResult R;
- LookupQualifiedName(R, StdNamespace, TypeInfoII, LookupTagName);
+ LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName);
+ LookupQualifiedName(R, StdNamespace);
Decl *TypeInfoDecl = R.getAsSingleDecl(Context);
RecordDecl *TypeInfoRecordDecl = dyn_cast_or_null<RecordDecl>(TypeInfoDecl);
if (!TypeInfoRecordDecl)
@@ -424,14 +425,13 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
Expr **ConsArgs = (Expr**)ConstructorArgs.get();
const RecordType *RT;
unsigned NumConsArgs = ConstructorArgs.size();
-
+ ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this);
+
if (AllocType->isDependentType() ||
Expr::hasAnyTypeDependentArguments(ConsArgs, NumConsArgs)) {
// Skip all the checks.
} else if ((RT = AllocType->getAs<RecordType>()) &&
!AllocType->isAggregateType()) {
- ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this);
-
Constructor = PerformInitializationByConstructor(
AllocType, move(ConstructorArgs),
TypeLoc,
@@ -568,8 +568,8 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
DeclarationName Name, Expr** Args,
unsigned NumArgs, DeclContext *Ctx,
bool AllowMissing, FunctionDecl *&Operator) {
- LookupResult R;
- LookupQualifiedName(R, Ctx, Name, LookupOrdinaryName);
+ LookupResult R(*this, Name, StartLoc, LookupOrdinaryName);
+ LookupQualifiedName(R, Ctx);
if (R.empty()) {
if (AllowMissing)
return false;
@@ -754,6 +754,57 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
((DeclContext *)TUScope->getEntity())->addDecl(Alloc);
}
+bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
+ DeclarationName Name,
+ FunctionDecl* &Operator) {
+ LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName);
+ // Try to find operator delete/operator delete[] in class scope.
+ LookupQualifiedName(Found, RD);
+
+ if (Found.isAmbiguous())
+ return true;
+
+ for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
+ F != FEnd; ++F) {
+ if (CXXMethodDecl *Delete = dyn_cast<CXXMethodDecl>(*F))
+ if (Delete->isUsualDeallocationFunction()) {
+ Operator = Delete;
+ return false;
+ }
+ }
+
+ // We did find operator delete/operator delete[] declarations, but
+ // none of them were suitable.
+ if (!Found.empty()) {
+ Diag(StartLoc, diag::err_no_suitable_delete_member_function_found)
+ << Name << RD;
+
+ for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
+ F != FEnd; ++F) {
+ Diag((*F)->getLocation(),
+ diag::note_delete_member_function_declared_here)
+ << Name;
+ }
+
+ return true;
+ }
+
+ // Look for a global declaration.
+ DeclareGlobalNewDelete();
+ DeclContext *TUDecl = Context.getTranslationUnitDecl();
+
+ CXXNullPtrLiteralExpr Null(Context.VoidPtrTy, SourceLocation());
+ Expr* DeallocArgs[1];
+ DeallocArgs[0] = &Null;
+ if (FindAllocationOverload(StartLoc, SourceRange(), Name,
+ DeallocArgs, 1, TUDecl, /*AllowMissing=*/false,
+ Operator))
+ return true;
+
+ assert(Operator && "Did not find a deallocation function!");
+ return false;
+}
+
/// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in:
/// @code ::delete ptr; @endcode
/// or
@@ -845,32 +896,21 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName(
ArrayForm ? OO_Array_Delete : OO_Delete);
- if (Pointee->isRecordType() && !UseGlobal) {
- CXXRecordDecl *Record
- = cast<CXXRecordDecl>(Pointee->getAs<RecordType>()->getDecl());
-
- // Try to find operator delete/operator delete[] in class scope.
- LookupResult Found;
- LookupQualifiedName(Found, Record, DeleteName, LookupOrdinaryName);
- // FIXME: Diagnose ambiguity properly
- assert(!Found.isAmbiguous() && "Ambiguous delete/delete[] not handled");
- for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
- F != FEnd; ++F) {
- if (CXXMethodDecl *Delete = dyn_cast<CXXMethodDecl>(*F))
- if (Delete->isUsualDeallocationFunction()) {
- OperatorDelete = Delete;
- break;
- }
- }
+ if (const RecordType *RT = Pointee->getAs<RecordType>()) {
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ if (!UseGlobal &&
+ FindDeallocationFunction(StartLoc, RD, DeleteName, OperatorDelete))
+ return ExprError();
- if (!Record->hasTrivialDestructor())
- if (const CXXDestructorDecl *Dtor = Record->getDestructor(Context))
+ if (!RD->hasTrivialDestructor())
+ if (const CXXDestructorDecl *Dtor = RD->getDestructor(Context))
MarkDeclarationReferenced(StartLoc,
const_cast<CXXDestructorDecl*>(Dtor));
}
-
+
if (!OperatorDelete) {
- // Didn't find a member overload. Look for a global one.
+ // Look for a global declaration.
DeclareGlobalNewDelete();
DeclContext *TUDecl = Context.getTranslationUnitDecl();
if (FindAllocationOverload(StartLoc, SourceRange(), DeleteName,
@@ -1064,10 +1104,11 @@ Sema::BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind,
bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
const ImplicitConversionSequence &ICS,
- const char* Flavor) {
+ const char* Flavor, bool IgnoreBaseAccess) {
switch (ICS.ConversionKind) {
case ImplicitConversionSequence::StandardConversion:
- if (PerformImplicitConversion(From, ToType, ICS.Standard, Flavor))
+ if (PerformImplicitConversion(From, ToType, ICS.Standard, Flavor,
+ IgnoreBaseAccess))
return true;
break;
@@ -1086,18 +1127,22 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
} else if (const CXXConstructorDecl *Ctor =
dyn_cast<CXXConstructorDecl>(FD)) {
CastKind = CastExpr::CK_ConstructorConversion;
-
- // If the user-defined conversion is specified by a constructor, the
- // initial standard conversion sequence converts the source type to the
- // type required by the argument of the constructor
- BeforeToType = Ctor->getParamDecl(0)->getType();
+ // Do no conversion if dealing with ... for the first conversion.
+ if (!ICS.UserDefined.EllipsisConversion)
+ // If the user-defined conversion is specified by a constructor, the
+ // initial standard conversion sequence converts the source type to the
+ // type required by the argument of the constructor
+ BeforeToType = Ctor->getParamDecl(0)->getType();
}
else
assert(0 && "Unknown conversion function kind!");
-
- if (PerformImplicitConversion(From, BeforeToType,
- ICS.UserDefined.Before, "converting"))
- return true;
+ // Whatch out for elipsis conversion.
+ if (!ICS.UserDefined.EllipsisConversion) {
+ if (PerformImplicitConversion(From, BeforeToType,
+ ICS.UserDefined.Before, "converting",
+ IgnoreBaseAccess))
+ return true;
+ }
OwningExprResult CastArg
= BuildCXXCastArgument(From->getLocStart(),
@@ -1145,7 +1190,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
const StandardConversionSequence& SCS,
- const char *Flavor) {
+ const char *Flavor, bool IgnoreBaseAccess) {
// Overall FIXME: we are recomputing too many types here and doing far too
// much extra work. What this means is that we need to keep track of more
// information that is computed when we try the implicit conversion initially,
@@ -1273,7 +1318,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
- if (CheckPointerConversion(From, ToType, Kind))
+ if (CheckPointerConversion(From, ToType, Kind, IgnoreBaseAccess))
return true;
ImpCastExprToType(From, ToType, Kind);
break;
@@ -1281,7 +1326,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
case ICK_Pointer_Member: {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
- if (CheckMemberPointerConversion(From, ToType, Kind))
+ if (CheckMemberPointerConversion(From, ToType, Kind, IgnoreBaseAccess))
return true;
if (CheckExceptionSpecCompatibility(From, ToType))
return true;
@@ -1292,6 +1337,17 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
ImpCastExprToType(From, Context.BoolTy, CastExpr::CK_Unknown);
break;
+ case ICK_Derived_To_Base:
+ if (CheckDerivedToBaseConversion(From->getType(),
+ ToType.getNonReferenceType(),
+ From->getLocStart(),
+ From->getSourceRange(),
+ IgnoreBaseAccess))
+ return true;
+ ImpCastExprToType(From, ToType.getNonReferenceType(),
+ CastExpr::CK_DerivedToBase);
+ break;
+
default:
assert(false && "Improper second standard conversion");
break;
@@ -1309,7 +1365,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
CastExpr::CK_NoOp,
ToType->isLValueReferenceType());
break;
-
+
default:
assert(false && "Improper second standard conversion");
break;
@@ -1374,8 +1430,7 @@ QualType Sema::CheckPointerToMemberOperands(
}
}
- if (Context.getCanonicalType(Class).getUnqualifiedType() !=
- Context.getCanonicalType(LType).getUnqualifiedType()) {
+ if (!Context.hasSameUnqualifiedType(Class, LType)) {
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
/*DetectVirtual=*/false);
// FIXME: Would it be useful to print full ambiguity paths, or is that
@@ -1827,8 +1882,6 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
!T2->isPointerType() && !T2->isMemberPointerType())
return QualType();
- // FIXME: Do we need to work on the canonical types?
-
// C++0x 5.9p2
// Pointer conversions and qualification conversions are performed on
// pointer operands to bring them to their composite pointer type. If
@@ -1850,8 +1903,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
}
// Now both have to be pointers or member pointers.
- if (!T1->isPointerType() && !T1->isMemberPointerType() &&
- !T2->isPointerType() && !T2->isMemberPointerType())
+ if ((!T1->isPointerType() && !T1->isMemberPointerType()) ||
+ (!T2->isPointerType() && !T2->isMemberPointerType()))
return QualType();
// Otherwise, of one of the operands has type "pointer to cv1 void," then
@@ -1865,9 +1918,13 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
// conversions in both directions. If only one works, or if the two composite
// types are the same, we have succeeded.
// FIXME: extended qualifiers?
- llvm::SmallVector<unsigned, 4> QualifierUnion;
- llvm::SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass;
- QualType Composite1 = T1, Composite2 = T2;
+ typedef llvm::SmallVector<unsigned, 4> QualifierVector;
+ QualifierVector QualifierUnion;
+ typedef llvm::SmallVector<std::pair<const Type *, const Type *>, 4>
+ ContainingClassVector;
+ ContainingClassVector MemberOfClass;
+ QualType Composite1 = Context.getCanonicalType(T1),
+ Composite2 = Context.getCanonicalType(T2);
do {
const PointerType *Ptr1, *Ptr2;
if ((Ptr1 = Composite1->getAs<PointerType>()) &&
@@ -1899,11 +1956,11 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
} while (true);
// Rewrap the composites as pointers or member pointers with the union CVRs.
- llvm::SmallVector<std::pair<const Type *, const Type *>, 4>::iterator MOC
- = MemberOfClass.begin();
- for (llvm::SmallVector<unsigned, 4>::iterator
- I = QualifierUnion.begin(),
- E = QualifierUnion.end();
+ ContainingClassVector::reverse_iterator MOC
+ = MemberOfClass.rbegin();
+ for (QualifierVector::reverse_iterator
+ I = QualifierUnion.rbegin(),
+ E = QualifierUnion.rend();
I != E; (void)++I, ++MOC) {
Qualifiers Quals = Qualifiers::fromCVRMask(*I);
if (MOC->first && MOC->second) {
@@ -2085,12 +2142,19 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
return move(Base);
}
+ // The object type must be complete (or dependent).
+ if (!BaseType->isDependentType() &&
+ RequireCompleteType(OpLoc, BaseType,
+ PDiag(diag::err_incomplete_member_access)))
+ return ExprError();
+
// C++ [basic.lookup.classref]p2:
// If the id-expression in a class member access (5.2.5) is an
- // unqualified-id, and the type of the object expres- sion is of a class
+ // unqualified-id, and the type of the object expression is of a class
// type C (or of pointer to a class type C), the unqualified-id is looked
// up in the scope of class C. [...]
ObjectType = BaseType.getAsOpaquePtr();
+
return move(Base);
}
@@ -2108,7 +2172,7 @@ CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,
CXXMemberCallExpr *CE =
new (Context) CXXMemberCallExpr(Context, ME, 0, 0,
ResultType,
- SourceLocation());
+ Exp->getLocEnd());
return CE;
}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 4746a25..0f973d6d 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -174,7 +174,8 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
// copy-initialization where the cv-unqualified version of the
// source type is the same class as, or a derived class of, the
// class of the destination, constructors are considered.
- if ((DeclTypeC.getUnqualifiedType() == InitTypeC.getUnqualifiedType()) ||
+ if ((DeclTypeC.getLocalUnqualifiedType()
+ == InitTypeC.getLocalUnqualifiedType()) ||
IsDerivedFrom(InitTypeC, DeclTypeC)) {
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(DeclType->getAs<RecordType>()->getDecl());
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 93752e1..1f49b78 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "Lookup.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
@@ -34,77 +35,161 @@
using namespace clang;
-typedef llvm::SmallVector<UsingDirectiveDecl*, 4> UsingDirectivesTy;
-typedef llvm::DenseSet<NamespaceDecl*> NamespaceSet;
+namespace {
+ class UnqualUsingEntry {
+ const DeclContext *Nominated;
+ const DeclContext *CommonAncestor;
-/// UsingDirAncestorCompare - Implements strict weak ordering of
-/// UsingDirectives. It orders them by address of its common ancestor.
-struct UsingDirAncestorCompare {
+ public:
+ UnqualUsingEntry(const DeclContext *Nominated,
+ const DeclContext *CommonAncestor)
+ : Nominated(Nominated), CommonAncestor(CommonAncestor) {
+ }
- /// @brief Compares UsingDirectiveDecl common ancestor with DeclContext.
- bool operator () (UsingDirectiveDecl *U, const DeclContext *Ctx) const {
- return U->getCommonAncestor() < Ctx;
- }
+ const DeclContext *getCommonAncestor() const {
+ return CommonAncestor;
+ }
- /// @brief Compares UsingDirectiveDecl common ancestor with DeclContext.
- bool operator () (const DeclContext *Ctx, UsingDirectiveDecl *U) const {
- return Ctx < U->getCommonAncestor();
- }
+ const DeclContext *getNominatedNamespace() const {
+ return Nominated;
+ }
- /// @brief Compares UsingDirectiveDecl common ancestors.
- bool operator () (UsingDirectiveDecl *U1, UsingDirectiveDecl *U2) const {
- return U1->getCommonAncestor() < U2->getCommonAncestor();
- }
-};
-
-/// AddNamespaceUsingDirectives - Adds all UsingDirectiveDecl's to heap UDirs
-/// (ordered by common ancestors), found in namespace NS,
-/// including all found (recursively) in their nominated namespaces.
-void AddNamespaceUsingDirectives(ASTContext &Context,
- DeclContext *NS,
- UsingDirectivesTy &UDirs,
- NamespaceSet &Visited) {
- DeclContext::udir_iterator I, End;
-
- for (llvm::tie(I, End) = NS->getUsingDirectives(); I !=End; ++I) {
- UDirs.push_back(*I);
- std::push_heap(UDirs.begin(), UDirs.end(), UsingDirAncestorCompare());
- NamespaceDecl *Nominated = (*I)->getNominatedNamespace();
- if (Visited.insert(Nominated).second)
- AddNamespaceUsingDirectives(Context, Nominated, UDirs, /*ref*/ Visited);
- }
-}
+ // Sort by the pointer value of the common ancestor.
+ struct Comparator {
+ bool operator()(const UnqualUsingEntry &L, const UnqualUsingEntry &R) {
+ return L.getCommonAncestor() < R.getCommonAncestor();
+ }
-/// AddScopeUsingDirectives - Adds all UsingDirectiveDecl's found in Scope S,
-/// including all found in the namespaces they nominate.
-static void AddScopeUsingDirectives(ASTContext &Context, Scope *S,
- UsingDirectivesTy &UDirs) {
- NamespaceSet VisitedNS;
+ bool operator()(const UnqualUsingEntry &E, const DeclContext *DC) {
+ return E.getCommonAncestor() < DC;
+ }
- if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) {
+ bool operator()(const DeclContext *DC, const UnqualUsingEntry &E) {
+ return DC < E.getCommonAncestor();
+ }
+ };
+ };
+
+ /// A collection of using directives, as used by C++ unqualified
+ /// lookup.
+ class UnqualUsingDirectiveSet {
+ typedef llvm::SmallVector<UnqualUsingEntry, 8> ListTy;
+
+ ListTy list;
+ llvm::SmallPtrSet<DeclContext*, 8> visited;
+
+ public:
+ UnqualUsingDirectiveSet() {}
+
+ void visitScopeChain(Scope *S, Scope *InnermostFileScope) {
+ // C++ [namespace.udir]p1:
+ // During unqualified name lookup, the names appear as if they
+ // were declared in the nearest enclosing namespace which contains
+ // both the using-directive and the nominated namespace.
+ DeclContext *InnermostFileDC
+ = static_cast<DeclContext*>(InnermostFileScope->getEntity());
+ assert(InnermostFileDC && InnermostFileDC->isFileContext());
+
+ for (; S; S = S->getParent()) {
+ if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) {
+ DeclContext *EffectiveDC = (Ctx->isFileContext() ? Ctx : InnermostFileDC);
+ visit(Ctx, EffectiveDC);
+ } else {
+ Scope::udir_iterator I = S->using_directives_begin(),
+ End = S->using_directives_end();
+
+ for (; I != End; ++I)
+ visit(I->getAs<UsingDirectiveDecl>(), InnermostFileDC);
+ }
+ }
+ }
- if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(Ctx))
- VisitedNS.insert(NS);
+ // Visits a context and collect all of its using directives
+ // recursively. Treats all using directives as if they were
+ // declared in the context.
+ //
+ // A given context is only every visited once, so it is important
+ // that contexts be visited from the inside out in order to get
+ // the effective DCs right.
+ void visit(DeclContext *DC, DeclContext *EffectiveDC) {
+ if (!visited.insert(DC))
+ return;
+
+ addUsingDirectives(DC, EffectiveDC);
+ }
- AddNamespaceUsingDirectives(Context, Ctx, UDirs, /*ref*/ VisitedNS);
+ // Visits a using directive and collects all of its using
+ // directives recursively. Treats all using directives as if they
+ // were declared in the effective DC.
+ void visit(UsingDirectiveDecl *UD, DeclContext *EffectiveDC) {
+ DeclContext *NS = UD->getNominatedNamespace();
+ if (!visited.insert(NS))
+ return;
- } else {
- Scope::udir_iterator I = S->using_directives_begin(),
- End = S->using_directives_end();
-
- for (; I != End; ++I) {
- UsingDirectiveDecl *UD = I->getAs<UsingDirectiveDecl>();
- UDirs.push_back(UD);
- std::push_heap(UDirs.begin(), UDirs.end(), UsingDirAncestorCompare());
-
- NamespaceDecl *Nominated = UD->getNominatedNamespace();
- if (!VisitedNS.count(Nominated)) {
- VisitedNS.insert(Nominated);
- AddNamespaceUsingDirectives(Context, Nominated, UDirs,
- /*ref*/ VisitedNS);
+ addUsingDirective(UD, EffectiveDC);
+ addUsingDirectives(NS, EffectiveDC);
+ }
+
+ // Adds all the using directives in a context (and those nominated
+ // by its using directives, transitively) as if they appeared in
+ // the given effective context.
+ void addUsingDirectives(DeclContext *DC, DeclContext *EffectiveDC) {
+ llvm::SmallVector<DeclContext*,4> queue;
+ while (true) {
+ DeclContext::udir_iterator I, End;
+ for (llvm::tie(I, End) = DC->getUsingDirectives(); I != End; ++I) {
+ UsingDirectiveDecl *UD = *I;
+ DeclContext *NS = UD->getNominatedNamespace();
+ if (visited.insert(NS)) {
+ addUsingDirective(UD, EffectiveDC);
+ queue.push_back(NS);
+ }
+ }
+
+ if (queue.empty())
+ return;
+
+ DC = queue.back();
+ queue.pop_back();
}
}
- }
+
+ // Add a using directive as if it had been declared in the given
+ // context. This helps implement C++ [namespace.udir]p3:
+ // The using-directive is transitive: if a scope contains a
+ // using-directive that nominates a second namespace that itself
+ // contains using-directives, the effect is as if the
+ // using-directives from the second namespace also appeared in
+ // the first.
+ void addUsingDirective(UsingDirectiveDecl *UD, DeclContext *EffectiveDC) {
+ // Find the common ancestor between the effective context and
+ // the nominated namespace.
+ DeclContext *Common = UD->getNominatedNamespace();
+ while (!Common->Encloses(EffectiveDC))
+ Common = Common->getParent();
+ Common = Common->getPrimaryContext();
+
+ list.push_back(UnqualUsingEntry(UD->getNominatedNamespace(), Common));
+ }
+
+ void done() {
+ std::sort(list.begin(), list.end(), UnqualUsingEntry::Comparator());
+ }
+
+ typedef ListTy::iterator iterator;
+ typedef ListTy::const_iterator const_iterator;
+
+ iterator begin() { return list.begin(); }
+ iterator end() { return list.end(); }
+ const_iterator begin() const { return list.begin(); }
+ const_iterator end() const { return list.end(); }
+
+ std::pair<const_iterator,const_iterator>
+ getNamespacesFor(DeclContext *DC) const {
+ return std::equal_range(begin(), end(), DC->getPrimaryContext(),
+ UnqualUsingEntry::Comparator());
+ }
+ };
}
// Retrieve the set of identifier namespaces that correspond to a
@@ -153,42 +238,50 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
}
// Necessary because CXXBasePaths is not complete in Sema.h
-void Sema::LookupResult::deletePaths(CXXBasePaths *Paths) {
+void LookupResult::deletePaths(CXXBasePaths *Paths) {
delete Paths;
}
-void Sema::LookupResult::resolveKind() {
+void LookupResult::resolveKind() {
unsigned N = Decls.size();
// Fast case: no possible ambiguity.
- if (N <= 1) return;
+ if (N == 0) return;
+ if (N == 1) {
+ if (isa<UnresolvedUsingValueDecl>(Decls[0]))
+ ResultKind = FoundUnresolvedValue;
+ return;
+ }
// Don't do any extra resolution if we've already resolved as ambiguous.
- if (Kind == Ambiguous) return;
+ if (ResultKind == Ambiguous) return;
llvm::SmallPtrSet<NamedDecl*, 16> Unique;
bool Ambiguous = false;
bool HasTag = false, HasFunction = false, HasNonFunction = false;
+ bool HasUnresolved = false;
unsigned UniqueTagIndex = 0;
unsigned I = 0;
while (I < N) {
- NamedDecl *D = Decls[I];
- assert(D == D->getUnderlyingDecl());
+ NamedDecl *D = Decls[I]->getUnderlyingDecl();
+ D = cast<NamedDecl>(D->getCanonicalDecl());
- NamedDecl *CanonD = cast<NamedDecl>(D->getCanonicalDecl());
- if (!Unique.insert(CanonD)) {
+ if (!Unique.insert(D)) {
// If it's not unique, pull something off the back (and
// continue at this index).
Decls[I] = Decls[--N];
- } else if (isa<UnresolvedUsingDecl>(D)) {
- // FIXME: proper support for UnresolvedUsingDecls.
+ } else if (isa<UnresolvedUsingValueDecl>(D)) {
+ // FIXME: support unresolved using value declarations
Decls[I] = Decls[--N];
} else {
// Otherwise, do some decl type analysis and then continue.
- if (isa<TagDecl>(D)) {
+
+ if (isa<UnresolvedUsingValueDecl>(D)) {
+ HasUnresolved = true;
+ } else if (isa<TagDecl>(D)) {
if (HasTag)
Ambiguous = true;
UniqueTagIndex = I;
@@ -213,7 +306,8 @@ void Sema::LookupResult::resolveKind() {
// wherever the object, function, or enumerator name is visible.
// But it's still an error if there are distinct tag types found,
// even if they're not visible. (ref?)
- if (HasTag && !Ambiguous && (HasFunction || HasNonFunction))
+ if (HideTags && HasTag && !Ambiguous && !HasUnresolved &&
+ (HasFunction || HasNonFunction))
Decls[UniqueTagIndex] = Decls[--N];
Decls.set_size(N);
@@ -223,10 +317,12 @@ void Sema::LookupResult::resolveKind() {
if (Ambiguous)
setAmbiguous(LookupResult::AmbiguousReference);
+ else if (HasUnresolved)
+ ResultKind = LookupResult::FoundUnresolvedValue;
else if (N > 1)
- Kind = LookupResult::FoundOverloaded;
+ ResultKind = LookupResult::FoundOverloaded;
else
- Kind = LookupResult::Found;
+ ResultKind = LookupResult::Found;
}
/// @brief Converts the result of name lookup into a single (possible
@@ -242,10 +338,10 @@ void Sema::LookupResult::resolveKind() {
/// solution, since it causes the OverloadedFunctionDecl to be
/// leaked. FIXME: Eventually, there will be a better way to iterate
/// over the set of overloaded functions returned by name lookup.
-NamedDecl *Sema::LookupResult::getAsSingleDecl(ASTContext &C) const {
+NamedDecl *LookupResult::getAsSingleDecl(ASTContext &C) const {
size_t size = Decls.size();
if (size == 0) return 0;
- if (size == 1) return *begin();
+ if (size == 1) return (*begin())->getUnderlyingDecl();
if (isAmbiguous()) return 0;
@@ -255,9 +351,7 @@ NamedDecl *Sema::LookupResult::getAsSingleDecl(ASTContext &C) const {
= OverloadedFunctionDecl::Create(C, (*I)->getDeclContext(),
(*I)->getDeclName());
for (; I != E; ++I) {
- NamedDecl *ND = *I;
- assert(ND->getUnderlyingDecl() == ND
- && "decls in lookup result should have redirections stripped");
+ NamedDecl *ND = (*I)->getUnderlyingDecl();
assert(ND->isFunctionOrFunctionTemplate());
if (isa<FunctionDecl>(ND))
Ovl->addOverload(cast<FunctionDecl>(ND));
@@ -269,7 +363,7 @@ NamedDecl *Sema::LookupResult::getAsSingleDecl(ASTContext &C) const {
return Ovl;
}
-void Sema::LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) {
+void LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) {
CXXBasePaths::paths_iterator I, E;
DeclContext::lookup_iterator DI, DE;
for (I = P.begin(), E = P.end(); I != E; ++I)
@@ -277,7 +371,7 @@ void Sema::LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) {
addDecl(*DI);
}
-void Sema::LookupResult::setAmbiguousBaseSubobjects(CXXBasePaths &P) {
+void LookupResult::setAmbiguousBaseSubobjects(CXXBasePaths &P) {
Paths = new CXXBasePaths;
Paths->swap(P);
addDeclsFromBasePaths(*Paths);
@@ -285,7 +379,7 @@ void Sema::LookupResult::setAmbiguousBaseSubobjects(CXXBasePaths &P) {
setAmbiguous(AmbiguousBaseSubobjects);
}
-void Sema::LookupResult::setAmbiguousBaseSubobjectTypes(CXXBasePaths &P) {
+void LookupResult::setAmbiguousBaseSubobjectTypes(CXXBasePaths &P) {
Paths = new CXXBasePaths;
Paths->swap(P);
addDeclsFromBasePaths(*Paths);
@@ -293,7 +387,7 @@ void Sema::LookupResult::setAmbiguousBaseSubobjectTypes(CXXBasePaths &P) {
setAmbiguous(AmbiguousBaseSubobjectTypes);
}
-void Sema::LookupResult::print(llvm::raw_ostream &Out) {
+void LookupResult::print(llvm::raw_ostream &Out) {
Out << Decls.size() << " result(s)";
if (isAmbiguous()) Out << ", ambiguous";
if (Paths) Out << ", base paths present";
@@ -306,42 +400,36 @@ void Sema::LookupResult::print(llvm::raw_ostream &Out) {
// Adds all qualifying matches for a name within a decl context to the
// given lookup result. Returns true if any matches were found.
-static bool LookupDirect(Sema::LookupResult &R, DeclContext *DC,
- DeclarationName Name,
- Sema::LookupNameKind NameKind,
- unsigned IDNS) {
+static bool LookupDirect(LookupResult &R, const DeclContext *DC) {
bool Found = false;
- DeclContext::lookup_iterator I, E;
- for (llvm::tie(I, E) = DC->lookup(Name); I != E; ++I)
- if (Sema::isAcceptableLookupResult(*I, NameKind, IDNS))
+ DeclContext::lookup_const_iterator I, E;
+ for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I)
+ if (Sema::isAcceptableLookupResult(*I, R.getLookupKind(),
+ R.getIdentifierNamespace()))
R.addDecl(*I), Found = true;
return Found;
}
+// Performs C++ unqualified lookup into the given file context.
static bool
-CppNamespaceLookup(Sema::LookupResult &R, ASTContext &Context, DeclContext *NS,
- DeclarationName Name, Sema::LookupNameKind NameKind,
- unsigned IDNS, UsingDirectivesTy *UDirs = 0) {
+CppNamespaceLookup(LookupResult &R, ASTContext &Context, DeclContext *NS,
+ UnqualUsingDirectiveSet &UDirs) {
assert(NS && NS->isFileContext() && "CppNamespaceLookup() requires namespace!");
- // Perform qualified name lookup into the LookupCtx.
- bool Found = LookupDirect(R, NS, Name, NameKind, IDNS);
-
- if (UDirs) {
- // For each UsingDirectiveDecl, which common ancestor is equal
- // to NS, we preform qualified name lookup into namespace nominated by it.
- UsingDirectivesTy::const_iterator UI, UEnd;
- llvm::tie(UI, UEnd) =
- std::equal_range(UDirs->begin(), UDirs->end(), NS,
- UsingDirAncestorCompare());
-
- for (; UI != UEnd; ++UI)
- if (LookupDirect(R, (*UI)->getNominatedNamespace(), Name, NameKind, IDNS))
- Found = true;
- }
+ // Perform direct name lookup into the LookupCtx.
+ bool Found = LookupDirect(R, NS);
+
+ // Perform direct name lookup into the namespaces nominated by the
+ // using directives whose common ancestor is this namespace.
+ UnqualUsingDirectiveSet::const_iterator UI, UEnd;
+ llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(NS);
+
+ for (; UI != UEnd; ++UI)
+ if (LookupDirect(R, UI->getNominatedNamespace()))
+ Found = true;
R.resolveKind();
@@ -363,20 +451,23 @@ static DeclContext *findOuterContext(Scope *S) {
return 0;
}
-bool
-Sema::CppLookupName(LookupResult &R, Scope *S, DeclarationName Name,
- LookupNameKind NameKind, bool RedeclarationOnly) {
+bool Sema::CppLookupName(LookupResult &R, Scope *S) {
assert(getLangOptions().CPlusPlus &&
"Can perform only C++ lookup");
+ LookupNameKind NameKind = R.getLookupKind();
unsigned IDNS
= getIdentifierNamespacesFromLookupNameKind(NameKind, /*CPlusPlus*/ true);
// If we're testing for redeclarations, also look in the friend namespaces.
- if (RedeclarationOnly) {
+ if (R.isForRedeclaration()) {
if (IDNS & Decl::IDNS_Tag) IDNS |= Decl::IDNS_TagFriend;
if (IDNS & Decl::IDNS_Ordinary) IDNS |= Decl::IDNS_OrdinaryFriend;
}
+ R.setIdentifierNamespace(IDNS);
+
+ DeclarationName Name = R.getLookupName();
+
Scope *Initial = S;
IdentifierResolver::iterator
I = IdResolver.begin(Name),
@@ -427,24 +518,25 @@ Sema::CppLookupName(LookupResult &R, Scope *S, DeclarationName Name,
// example, inside a class without any base classes, we never need to
// perform qualified lookup because all of the members are on top of the
// identifier chain.
- if (LookupQualifiedName(R, Ctx, Name, NameKind, RedeclarationOnly))
+ if (LookupQualifiedName(R, Ctx))
return true;
}
}
}
+ // Stop if we ran out of scopes.
+ // FIXME: This really, really shouldn't be happening.
+ if (!S) return false;
+
// Collect UsingDirectiveDecls in all scopes, and recursively all
// nominated namespaces by those using-directives.
- // UsingDirectives are pushed to heap, in common ancestor pointer value order.
+ //
// FIXME: Cache this sorted list in Scope structure, and DeclContext, so we
// don't build it for each lookup!
- UsingDirectivesTy UDirs;
- for (Scope *SC = Initial; SC; SC = SC->getParent())
- if (SC->getFlags() & Scope::DeclScope)
- AddScopeUsingDirectives(Context, SC, UDirs);
- // Sort heapified UsingDirectiveDecls.
- std::sort_heap(UDirs.begin(), UDirs.end(), UsingDirAncestorCompare());
+ UnqualUsingDirectiveSet UDirs;
+ UDirs.visitScopeChain(Initial, S);
+ UDirs.done();
// Lookup namespace scope, and global scope.
// Unqualified name lookup in C++ requires looking into scopes
@@ -473,7 +565,7 @@ Sema::CppLookupName(LookupResult &R, Scope *S, DeclarationName Name,
}
// Look into context considering using-directives.
- if (CppNamespaceLookup(R, Context, Ctx, Name, NameKind, IDNS, &UDirs))
+ if (CppNamespaceLookup(R, Context, Ctx, UDirs))
Found = true;
if (Found) {
@@ -481,7 +573,7 @@ Sema::CppLookupName(LookupResult &R, Scope *S, DeclarationName Name,
return true;
}
- if (RedeclarationOnly && !Ctx->isTransparentContext())
+ if (R.isForRedeclaration() && !Ctx->isTransparentContext())
return false;
}
@@ -519,11 +611,12 @@ Sema::CppLookupName(LookupResult &R, Scope *S, DeclarationName Name,
/// @returns The result of name lookup, which includes zero or more
/// declarations and possibly additional information used to diagnose
/// ambiguities.
-bool Sema::LookupName(LookupResult &R, Scope *S, DeclarationName Name,
- LookupNameKind NameKind, bool RedeclarationOnly,
- bool AllowBuiltinCreation, SourceLocation Loc) {
+bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
+ DeclarationName Name = R.getLookupName();
if (!Name) return false;
+ LookupNameKind NameKind = R.getLookupKind();
+
if (!getLangOptions().CPlusPlus) {
// Unqualified name lookup in C/Objective-C is purely lexical, so
// search in the declarations attached to the name.
@@ -619,7 +712,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, DeclarationName Name,
}
} else {
// Perform C++ unqualified name lookup.
- if (CppLookupName(R, S, Name, NameKind, RedeclarationOnly))
+ if (CppLookupName(R, S))
return true;
}
@@ -639,7 +732,8 @@ bool Sema::LookupName(LookupResult &R, Scope *S, DeclarationName Name,
return false;
NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
- S, RedeclarationOnly, Loc);
+ S, R.isForRedeclaration(),
+ R.getNameLoc());
if (D) R.addDecl(D);
return (D != NULL);
}
@@ -674,11 +768,8 @@ bool Sema::LookupName(LookupResult &R, Scope *S, DeclarationName Name,
/// class or enumeration name if and only if the declarations are
/// from the same namespace; otherwise (the declarations are from
/// different namespaces), the program is ill-formed.
-static bool LookupQualifiedNameInUsingDirectives(Sema::LookupResult &R,
- DeclContext *StartDC,
- DeclarationName Name,
- Sema::LookupNameKind NameKind,
- unsigned IDNS) {
+static bool LookupQualifiedNameInUsingDirectives(LookupResult &R,
+ DeclContext *StartDC) {
assert(StartDC->isFileContext() && "start context is not a file context");
DeclContext::udir_iterator I = StartDC->using_directives_begin();
@@ -697,7 +788,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema::LookupResult &R,
// We have already looked into the initial namespace; seed the queue
// with its using-children.
for (; I != E; ++I) {
- NamespaceDecl *ND = (*I)->getNominatedNamespace();
+ NamespaceDecl *ND = (*I)->getNominatedNamespace()->getOriginalNamespace();
if (Visited.insert(ND).second)
Queue.push_back(ND);
}
@@ -709,7 +800,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema::LookupResult &R,
bool FoundTag = false;
bool FoundNonTag = false;
- Sema::LookupResult LocalR;
+ LookupResult LocalR(LookupResult::Temporary, R);
bool Found = false;
while (!Queue.empty()) {
@@ -719,8 +810,8 @@ static bool LookupQualifiedNameInUsingDirectives(Sema::LookupResult &R,
// We go through some convolutions here to avoid copying results
// between LookupResults.
bool UseLocal = !R.empty();
- Sema::LookupResult &DirectR = UseLocal ? LocalR : R;
- bool FoundDirect = LookupDirect(DirectR, ND, Name, NameKind, IDNS);
+ LookupResult &DirectR = UseLocal ? LocalR : R;
+ bool FoundDirect = LookupDirect(DirectR, ND);
if (FoundDirect) {
// First do any local hiding.
@@ -792,22 +883,23 @@ static bool LookupQualifiedNameInUsingDirectives(Sema::LookupResult &R,
/// @returns The result of name lookup, which includes zero or more
/// declarations and possibly additional information used to diagnose
/// ambiguities.
-bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
- DeclarationName Name, LookupNameKind NameKind,
- bool RedeclarationOnly) {
+bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) {
assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context");
- if (!Name)
+ if (!R.getLookupName())
return false;
// If we're performing qualified name lookup (e.g., lookup into a
// struct), find fields as part of ordinary name lookup.
+ LookupNameKind NameKind = R.getLookupKind();
unsigned IDNS
= getIdentifierNamespacesFromLookupNameKind(NameKind,
getLangOptions().CPlusPlus);
if (NameKind == LookupOrdinaryName)
IDNS |= Decl::IDNS_Member;
+ R.setIdentifierNamespace(IDNS);
+
// Make sure that the declaration context is complete.
assert((!isa<TagDecl>(LookupCtx) ||
LookupCtx->isDependentContext() ||
@@ -817,7 +909,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
"Declaration context must already be complete!");
// Perform qualified name lookup into the LookupCtx.
- if (LookupDirect(R, LookupCtx, Name, NameKind, IDNS)) {
+ if (LookupDirect(R, LookupCtx)) {
R.resolveKind();
return true;
}
@@ -831,13 +923,12 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// the unqualified-id shall name a member of the namespace
// designated by the nested-name-specifier.
// See also [class.mfct]p5 and [class.static.data]p2.
- if (RedeclarationOnly)
+ if (R.isForRedeclaration())
return false;
- // If this is a namespace, look it up in
+ // If this is a namespace, look it up in the implied namespaces.
if (LookupCtx->isFileContext())
- return LookupQualifiedNameInUsingDirectives(R, LookupCtx, Name, NameKind,
- IDNS);
+ return LookupQualifiedNameInUsingDirectives(R, LookupCtx);
// If this isn't a C++ class, we aren't allowed to look into base
// classes, we're done.
@@ -851,7 +942,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// Look for this member in our base classes
CXXRecordDecl::BaseMatchesCallback *BaseCallback = 0;
- switch (NameKind) {
+ switch (R.getLookupKind()) {
case LookupOrdinaryName:
case LookupMemberName:
case LookupRedeclarationWithLinkage:
@@ -875,7 +966,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
break;
}
- if (!LookupRec->lookupInBases(BaseCallback, Name.getAsOpaquePtr(), Paths))
+ if (!LookupRec->lookupInBases(BaseCallback,
+ R.getLookupName().getAsOpaquePtr(), Paths))
return false;
// C++ [class.member.lookup]p2:
@@ -977,10 +1069,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
///
/// @returns True if any decls were found (but possibly ambiguous)
bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
- DeclarationName Name, LookupNameKind NameKind,
- bool RedeclarationOnly, bool AllowBuiltinCreation,
- SourceLocation Loc,
- bool EnteringContext) {
+ bool AllowBuiltinCreation, bool EnteringContext) {
if (SS && SS->isInvalid()) {
// When the scope specifier is invalid, don't even look for
// anything.
@@ -994,7 +1083,9 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS))
return false;
- return LookupQualifiedName(R, DC, Name, NameKind, RedeclarationOnly);
+ R.setContextRange(SS->getRange());
+
+ return LookupQualifiedName(R, DC);
}
// We could not resolve the scope specified to a specific declaration
@@ -1004,8 +1095,7 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
}
// Perform unqualified name lookup starting in the given scope.
- return LookupName(R, S, Name, NameKind, RedeclarationOnly,
- AllowBuiltinCreation, Loc);
+ return LookupName(R, S, AllowBuiltinCreation);
}
@@ -1025,11 +1115,13 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
/// precedes the name.
///
/// @returns true
-bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
- SourceLocation NameLoc,
- SourceRange LookupRange) {
+bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
assert(Result.isAmbiguous() && "Lookup result must be ambiguous");
+ DeclarationName Name = Result.getLookupName();
+ SourceLocation NameLoc = Result.getNameLoc();
+ SourceRange LookupRange = Result.getContextRange();
+
switch (Result.getAmbiguityKind()) {
case LookupResult::AmbiguousBaseSubobjects: {
CXXBasePaths *Paths = Result.getBasePaths();
@@ -1136,12 +1228,13 @@ addAssociatedClassesAndNamespaces(const TemplateArgument &Arg,
AssociatedClasses);
break;
- case TemplateArgument::Declaration:
+ case TemplateArgument::Template: {
// [...] the namespaces in which any template template arguments are
// defined; and the classes in which any member templates used as
// template template arguments are defined.
+ TemplateName Template = Arg.getAsTemplate();
if (ClassTemplateDecl *ClassTemplate
- = dyn_cast<ClassTemplateDecl>(Arg.getAsDecl())) {
+ = dyn_cast<ClassTemplateDecl>(Template.getAsTemplateDecl())) {
DeclContext *Ctx = ClassTemplate->getDeclContext();
if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
AssociatedClasses.insert(EnclosingClass);
@@ -1151,7 +1244,9 @@ addAssociatedClassesAndNamespaces(const TemplateArgument &Arg,
CollectNamespace(AssociatedNamespaces, Ctx);
}
break;
-
+ }
+
+ case TemplateArgument::Declaration:
case TemplateArgument::Integral:
case TemplateArgument::Expression:
// [Note: non-type template arguments do not contribute to the set of
@@ -1490,8 +1585,7 @@ IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
if (T1->isEnumeralType()) {
QualType ArgType = Proto->getArgType(0).getNonReferenceType();
- if (Context.getCanonicalType(T1).getUnqualifiedType()
- == Context.getCanonicalType(ArgType).getUnqualifiedType())
+ if (Context.hasSameUnqualifiedType(T1, ArgType))
return true;
}
@@ -1500,14 +1594,21 @@ IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
if (!T2.isNull() && T2->isEnumeralType()) {
QualType ArgType = Proto->getArgType(1).getNonReferenceType();
- if (Context.getCanonicalType(T2).getUnqualifiedType()
- == Context.getCanonicalType(ArgType).getUnqualifiedType())
+ if (Context.hasSameUnqualifiedType(T2, ArgType))
return true;
}
return false;
}
+NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name,
+ LookupNameKind NameKind,
+ RedeclarationKind Redecl) {
+ LookupResult R(*this, Name, SourceLocation(), NameKind, Redecl);
+ LookupName(R, S);
+ return R.getAsSingleDecl(Context);
+}
+
/// \brief Find the protocol with the given name, if any.
ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) {
Decl *D = LookupSingleName(TUScope, II, LookupObjCProtocolName);
@@ -1537,8 +1638,8 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
// of type T2 or "reference to (possibly cv-qualified) T2",
// when T2 is an enumeration type, are candidate functions.
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
- LookupResult Operators;
- LookupName(Operators, S, OpName, LookupOperatorName);
+ LookupResult Operators(*this, OpName, SourceLocation(), LookupOperatorName);
+ LookupName(Operators, S);
assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous");
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 3e6778b..adcd977 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "Lookup.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/AST/ASTContext.h"
@@ -350,7 +351,7 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD,
if (NewTemplate &&
(!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
OldTemplate->getTemplateParameters(),
- false, false, SourceLocation()) ||
+ false, TPL_TemplateMatch) ||
OldType->getResultType() != NewType->getResultType()))
return true;
@@ -519,8 +520,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// cv-unqualified version of T. Otherwise, the type of the rvalue
// is T (C++ 4.1p1). C++ can't get here with class types; in C, we
// just strip the qualifiers because they don't matter.
-
- // FIXME: Doesn't see through to qualifiers behind a typedef!
FromType = FromType.getUnqualifiedType();
} else if (FromType->isArrayType()) {
// Array-to-pointer conversion (C++ 4.2)
@@ -678,8 +677,9 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// a conversion. [...]
CanonFrom = Context.getCanonicalType(FromType);
CanonTo = Context.getCanonicalType(ToType);
- if (CanonFrom.getUnqualifiedType() == CanonTo.getUnqualifiedType() &&
- CanonFrom.getCVRQualifiers() != CanonTo.getCVRQualifiers()) {
+ if (CanonFrom.getLocalUnqualifiedType()
+ == CanonTo.getLocalUnqualifiedType() &&
+ CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers()) {
FromType = ToType;
CanonFrom = CanonTo;
}
@@ -756,8 +756,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
// We found the type that we can promote to. If this is the
// type we wanted, we have a promotion. Otherwise, no
// promotion.
- return Context.getCanonicalType(ToType).getUnqualifiedType()
- == Context.getCanonicalType(PromoteTypes[Idx]).getUnqualifiedType();
+ return Context.hasSameUnqualifiedType(ToType, PromoteTypes[Idx]);
}
}
}
@@ -864,7 +863,7 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr,
Qualifiers Quals = CanonFromPointee.getQualifiers();
// Exact qualifier match -> return the pointer type we're converting to.
- if (CanonToPointee.getQualifiers() == Quals) {
+ if (CanonToPointee.getLocalQualifiers() == Quals) {
// ToType is exactly what we need. Return it.
if (!ToType.isNull())
return ToType;
@@ -876,7 +875,8 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr,
// Just build a canonical type that has the right qualifiers.
return Context.getPointerType(
- Context.getQualifiedType(CanonToPointee.getUnqualifiedType(), Quals));
+ Context.getQualifiedType(CanonToPointee.getLocalUnqualifiedType(),
+ Quals));
}
static bool isNullPointerConstantForConversion(Expr *Expr,
@@ -1155,7 +1155,8 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
/// true. It returns true and produces a diagnostic if there was an
/// error, or returns false otherwise.
bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
- CastExpr::CastKind &Kind) {
+ CastExpr::CastKind &Kind,
+ bool IgnoreBaseAccess) {
QualType FromType = From->getType();
if (const PointerType *FromPtrType = FromType->getAs<PointerType>())
@@ -1169,7 +1170,8 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
// ambiguous or inaccessible conversion.
if (CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType,
From->getExprLoc(),
- From->getSourceRange()))
+ From->getSourceRange(),
+ IgnoreBaseAccess))
return true;
// The conversion was successful.
@@ -1238,7 +1240,9 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType,
/// true and produces a diagnostic if there was an error, or returns false
/// otherwise.
bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
- CastExpr::CastKind &Kind) {
+ CastExpr::CastKind &Kind,
+ bool IgnoreBaseAccess) {
+ (void)IgnoreBaseAccess;
QualType FromType = From->getType();
const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>();
if (!FromPtrType) {
@@ -1344,8 +1348,7 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) {
// of types. If we unwrapped any pointers, and if FromType and
// ToType have the same unqualified type (since we checked
// qualifiers above), then this is a qualification conversion.
- return UnwrappedAnyPointer &&
- FromType.getUnqualifiedType() == ToType.getUnqualifiedType();
+ return UnwrappedAnyPointer && Context.hasSameUnqualifiedType(FromType,ToType);
}
/// \brief Given a function template or function, extract the function template
@@ -1399,6 +1402,13 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion(
// functions are all the converting constructors (12.3.1) of
// that class. The argument list is the expression-list within
// the parentheses of the initializer.
+ bool SuppressUserConversions = !UserCast;
+ if (Context.hasSameUnqualifiedType(ToType, From->getType()) ||
+ IsDerivedFrom(From->getType(), ToType)) {
+ SuppressUserConversions = false;
+ AllowConversionFunctions = false;
+ }
+
DeclarationName ConstructorName
= Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(ToType).getUnqualifiedType());
@@ -1415,20 +1425,18 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion(
= cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
else
Constructor = cast<CXXConstructorDecl>(*Con);
-
+
if (!Constructor->isInvalidDecl() &&
Constructor->isConvertingConstructor(AllowExplicit)) {
if (ConstructorTmpl)
AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0, &From,
- 1, CandidateSet,
- /*SuppressUserConversions=*/!UserCast,
- ForceRValue);
+ 1, CandidateSet,
+ SuppressUserConversions, ForceRValue);
else
// Allow one user-defined conversion when user specifies a
// From->ToType conversion via an static cast (c-style, etc).
AddOverloadCandidate(Constructor, &From, 1, CandidateSet,
- /*SuppressUserConversions=*/!UserCast,
- ForceRValue);
+ SuppressUserConversions, ForceRValue);
}
}
}
@@ -1481,9 +1489,14 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion(
// sequence converts the source type to the type required by
// the argument of the constructor.
//
- // FIXME: What about ellipsis conversions?
QualType ThisType = Constructor->getThisType(Context);
- User.Before = Best->Conversions[0].Standard;
+ if (Best->Conversions[0].ConversionKind ==
+ ImplicitConversionSequence::EllipsisConversion)
+ User.EllipsisConversion = true;
+ else {
+ User.Before = Best->Conversions[0].Standard;
+ User.EllipsisConversion = false;
+ }
User.ConversionFunction = Constructor;
User.After.setAsIdentityConversion();
User.After.FromTypePtr
@@ -1500,6 +1513,7 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion(
// implicit object parameter of the conversion function.
User.Before = Best->Conversions[0].Standard;
User.ConversionFunction = Conversion;
+ User.EllipsisConversion = false;
// C++ [over.ics.user]p2:
// The second standard conversion sequence converts the
@@ -1727,7 +1741,7 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
T1 = Context.getCanonicalType(T1);
T2 = Context.getCanonicalType(T2);
- if (T1.getUnqualifiedType() == T2.getUnqualifiedType()) {
+ if (Context.hasSameUnqualifiedType(T1, T2)) {
if (T2.isMoreQualifiedThan(T1))
return ImplicitConversionSequence::Better;
else if (T1.isMoreQualifiedThan(T2))
@@ -1763,7 +1777,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
// If the types are the same, we won't learn anything by unwrapped
// them.
- if (T1.getUnqualifiedType() == T2.getUnqualifiedType())
+ if (Context.hasSameUnqualifiedType(T1, T2))
return ImplicitConversionSequence::Indistinguishable;
ImplicitConversionSequence::CompareKind Result
@@ -1803,7 +1817,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
}
// If the types after this point are equivalent, we're done.
- if (T1.getUnqualifiedType() == T2.getUnqualifiedType())
+ if (Context.hasSameUnqualifiedType(T1, T2))
break;
}
@@ -1918,8 +1932,8 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
// -- binding of an expression of type C to a reference of type
// B& is better than binding an expression of type C to a
// reference of type A&,
- if (FromType1.getUnqualifiedType() == FromType2.getUnqualifiedType() &&
- ToType1.getUnqualifiedType() != ToType2.getUnqualifiedType()) {
+ if (Context.hasSameUnqualifiedType(FromType1, FromType2) &&
+ !Context.hasSameUnqualifiedType(ToType1, ToType2)) {
if (IsDerivedFrom(ToType1, ToType2))
return ImplicitConversionSequence::Better;
else if (IsDerivedFrom(ToType2, ToType1))
@@ -1929,8 +1943,8 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
// -- binding of an expression of type B to a reference of type
// A& is better than binding an expression of type C to a
// reference of type A&,
- if (FromType1.getUnqualifiedType() != FromType2.getUnqualifiedType() &&
- ToType1.getUnqualifiedType() == ToType2.getUnqualifiedType()) {
+ if (!Context.hasSameUnqualifiedType(FromType1, FromType2) &&
+ Context.hasSameUnqualifiedType(ToType1, ToType2)) {
if (IsDerivedFrom(FromType2, FromType1))
return ImplicitConversionSequence::Better;
else if (IsDerivedFrom(FromType1, FromType2))
@@ -1977,8 +1991,8 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
if (SCS1.CopyConstructor && SCS2.CopyConstructor &&
SCS1.Second == ICK_Derived_To_Base) {
// -- conversion of C to B is better than conversion of C to A,
- if (FromType1.getUnqualifiedType() == FromType2.getUnqualifiedType() &&
- ToType1.getUnqualifiedType() != ToType2.getUnqualifiedType()) {
+ if (Context.hasSameUnqualifiedType(FromType1, FromType2) &&
+ !Context.hasSameUnqualifiedType(ToType1, ToType2)) {
if (IsDerivedFrom(ToType1, ToType2))
return ImplicitConversionSequence::Better;
else if (IsDerivedFrom(ToType2, ToType1))
@@ -1986,8 +2000,8 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
}
// -- conversion of B to A is better than conversion of C to A.
- if (FromType1.getUnqualifiedType() != FromType2.getUnqualifiedType() &&
- ToType1.getUnqualifiedType() == ToType2.getUnqualifiedType()) {
+ if (!Context.hasSameUnqualifiedType(FromType1, FromType2) &&
+ Context.hasSameUnqualifiedType(ToType1, ToType2)) {
if (IsDerivedFrom(FromType2, FromType1))
return ImplicitConversionSequence::Better;
else if (IsDerivedFrom(FromType1, FromType2))
@@ -2099,14 +2113,15 @@ Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) {
// First check the qualifiers. We don't care about lvalue-vs-rvalue
// with the implicit object parameter (C++ [over.match.funcs]p5).
QualType FromTypeCanon = Context.getCanonicalType(FromType);
- if (ImplicitParamType.getCVRQualifiers() != FromTypeCanon.getCVRQualifiers() &&
+ if (ImplicitParamType.getCVRQualifiers()
+ != FromTypeCanon.getLocalCVRQualifiers() &&
!ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon))
return ICS;
// Check that we have either the same type or a derived type. It
// affects the conversion rank.
QualType ClassTypeCanon = Context.getCanonicalType(ClassType);
- if (ClassTypeCanon == FromTypeCanon.getUnqualifiedType())
+ if (ClassTypeCanon == FromTypeCanon.getLocalUnqualifiedType())
ICS.Standard.Second = ICK_Identity;
else if (IsDerivedFrom(FromType, ClassType))
ICS.Standard.Second = ICK_Derived_To_Base;
@@ -2228,7 +2243,18 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
if (!CandidateSet.isNewCandidate(Function))
return;
-
+
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Function)){
+ // C++ [class.copy]p3:
+ // A member function template is never instantiated to perform the copy
+ // of a class object to an object of its class type.
+ QualType ClassType = Context.getTypeDeclType(Constructor->getParent());
+ if (NumArgs == 1 &&
+ Constructor->isCopyConstructorLikeSpecialization() &&
+ Context.hasSameUnqualifiedType(ClassType, Args[0]->getType()))
+ return;
+ }
+
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
@@ -2342,6 +2368,33 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions,
}
}
+/// AddMethodCandidate - Adds a named decl (which is some kind of
+/// method) as a method candidate to the given overload set.
+void Sema::AddMethodCandidate(NamedDecl *Decl, Expr *Object,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool SuppressUserConversions, bool ForceRValue) {
+
+ // FIXME: use this
+ //DeclContext *ActingContext = Decl->getDeclContext();
+
+ if (isa<UsingShadowDecl>(Decl))
+ Decl = cast<UsingShadowDecl>(Decl)->getTargetDecl();
+
+ if (FunctionTemplateDecl *TD = dyn_cast<FunctionTemplateDecl>(Decl)) {
+ assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) &&
+ "Expected a member function template");
+ AddMethodTemplateCandidate(TD, false, 0, 0,
+ Object, Args, NumArgs,
+ CandidateSet,
+ SuppressUserConversions,
+ ForceRValue);
+ } else {
+ AddMethodCandidate(cast<CXXMethodDecl>(Decl), Object, Args, NumArgs,
+ CandidateSet, SuppressUserConversions, ForceRValue);
+ }
+}
+
/// AddMethodCandidate - Adds the given C++ member function to the set
/// of candidate functions, using the given function call arguments
/// and the object argument (@c Object). For example, in a call
@@ -2593,7 +2646,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
// call on the stack and we don't need its arguments to be
// well-formed.
DeclRefExpr ConversionRef(Conversion, Conversion->getType(),
- SourceLocation());
+ From->getLocStart());
ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()),
CastExpr::CK_FunctionToPointerDecay,
&ConversionRef, false);
@@ -2603,7 +2656,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
// allocator).
CallExpr Call(Context, &ConversionFn, 0, 0,
Conversion->getConversionType().getNonReferenceType(),
- SourceLocation());
+ From->getLocStart());
ImplicitConversionSequence ICS =
TryCopyInitialization(&Call, ToType,
/*SuppressUserConversions=*/true,
@@ -2693,6 +2746,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
Candidate.Conversions[0].ConversionKind
= ImplicitConversionSequence::UserDefinedConversion;
Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard;
+ Candidate.Conversions[0].UserDefined.EllipsisConversion = false;
Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion;
Candidate.Conversions[0].UserDefined.After
= Candidate.Conversions[0].UserDefined.Before;
@@ -2807,27 +2861,16 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
if (RequireCompleteType(OpLoc, T1, PDiag()))
return;
- LookupResult Operators;
- LookupQualifiedName(Operators, T1Rec->getDecl(), OpName,
- LookupOrdinaryName, false);
+ LookupResult Operators(*this, OpName, OpLoc, LookupOrdinaryName);
+ LookupQualifiedName(Operators, T1Rec->getDecl());
+ Operators.suppressDiagnostics();
+
for (LookupResult::iterator Oper = Operators.begin(),
OperEnd = Operators.end();
Oper != OperEnd;
- ++Oper) {
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Oper)) {
- AddMethodCandidate(Method, Args[0], Args+1, NumArgs - 1, CandidateSet,
- /*SuppressUserConversions=*/false);
- continue;
- }
-
- assert(isa<FunctionTemplateDecl>(*Oper) &&
- isa<CXXMethodDecl>(cast<FunctionTemplateDecl>(*Oper)
- ->getTemplatedDecl()) &&
- "Expected a member function template");
- AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Oper), false, 0, 0,
- Args[0], Args+1, NumArgs - 1, CandidateSet,
- /*SuppressUserConversions=*/false);
- }
+ ++Oper)
+ AddMethodCandidate(*Oper, Args[0], Args + 1, NumArgs - 1, CandidateSet,
+ /* SuppressUserConversions = */ false);
}
}
@@ -2975,6 +3018,8 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty,
QualType PointeeTy = PointerTy->getPointeeType();
unsigned BaseCVR = PointeeTy.getCVRQualifiers();
+ if (const ConstantArrayType *Array =Context.getAsConstantArrayType(PointeeTy))
+ BaseCVR = Array->getElementType().getCVRQualifiers();
bool hasVolatile = VisibleQuals.hasVolatile();
bool hasRestrict = VisibleQuals.hasRestrict();
@@ -3050,7 +3095,7 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
Ty = RefTy->getPointeeType();
// We don't care about qualifiers on the type.
- Ty = Ty.getUnqualifiedType();
+ Ty = Ty.getLocalUnqualifiedType();
// If we're dealing with an array type, decay to the pointer.
if (Ty->isArrayType())
@@ -4710,10 +4755,10 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
UsualUnaryConversions(FnExpr);
input.release();
-
+ Args[0] = Input;
ExprOwningPtr<CallExpr> TheCall(this,
new (Context) CXXOperatorCallExpr(Context, Op, FnExpr,
- &Input, 1, ResultTy, OpLoc));
+ Args, NumArgs, ResultTy, OpLoc));
if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(),
FnDecl))
@@ -5226,17 +5271,22 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// (E).operator().
OverloadCandidateSet CandidateSet;
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call);
- DeclContext::lookup_const_iterator Oper, OperEnd;
- for (llvm::tie(Oper, OperEnd) = Record->getDecl()->lookup(OpName);
- Oper != OperEnd; ++Oper)
- AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Object, Args, NumArgs,
- CandidateSet, /*SuppressUserConversions=*/false);
if (RequireCompleteType(LParenLoc, Object->getType(),
PartialDiagnostic(diag::err_incomplete_object_call)
- << Object->getSourceRange()))
+ << Object->getSourceRange()))
return true;
+ LookupResult R(*this, OpName, LParenLoc, LookupOrdinaryName);
+ LookupQualifiedName(R, Record->getDecl());
+ R.suppressDiagnostics();
+
+ for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
+ Oper != OperEnd; ++Oper) {
+ AddMethodCandidate(*Oper, Object, Args, NumArgs, CandidateSet,
+ /*SuppressUserConversions=*/ false);
+ }
+
// C++ [over.call.object]p2:
// In addition, for each conversion function declared in T of the
// form
@@ -5405,7 +5455,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
QualType ProtoArgType = Proto->getArgType(i);
IsError |= PerformCopyInitialization(Arg, ProtoArgType, "passing");
} else {
- Arg = CXXDefaultArgExpr::Create(Context, Method->getParamDecl(i));
+ OwningExprResult DefArg
+ = BuildCXXDefaultArgExpr(LParenLoc, Method, Method->getParamDecl(i));
+ if (DefArg.isInvalid()) {
+ IsError = true;
+ break;
+ }
+
+ Arg = DefArg.takeAs<Expr>();
}
TheCall->setArg(i + 1, Arg);
@@ -5447,8 +5504,14 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
OverloadCandidateSet CandidateSet;
const RecordType *BaseRecord = Base->getType()->getAs<RecordType>();
- LookupResult R;
- LookupQualifiedName(R, BaseRecord->getDecl(), OpName, LookupOrdinaryName);
+ if (RequireCompleteType(Base->getLocStart(), Base->getType(),
+ PDiag(diag::err_typecheck_incomplete_tag)
+ << Base->getSourceRange()))
+ return ExprError();
+
+ LookupResult R(*this, OpName, OpLoc, LookupOrdinaryName);
+ LookupQualifiedName(R, BaseRecord->getDecl());
+ R.suppressDiagnostics();
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
Oper != OperEnd; ++Oper)
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index 898393a..0d1f37a 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -156,6 +156,14 @@ namespace clang {
/// object parameter of the conversion function.
StandardConversionSequence Before;
+ /// EllipsisConversion - When this is true, it means user-defined
+ /// conversion sequence starts with a ... (elipsis) conversion, instead of
+ /// a standard conversion. In this case, 'Before' field must be ignored.
+ // FIXME. I much rather put this as the first field. But there seems to be
+ // a gcc code gen. bug which causes a crash in a test. Putting it here seems
+ // to work around the crash.
+ bool EllipsisConversion : 1;
+
/// After - Represents the standard conversion that occurs after
/// the actual user-defined conversion.
StandardConversionSequence After;
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 6a65bd1..d0f214f 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -873,8 +873,7 @@ static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType,
if (!RetType->isRecordType())
return false;
// ... the same cv-unqualified type as the function return type ...
- if (Ctx.getCanonicalType(RetType).getUnqualifiedType() !=
- Ctx.getCanonicalType(ExprType).getUnqualifiedType())
+ if (!Ctx.hasSameUnqualifiedType(RetType, ExprType))
return false;
// ... the expression is the name of a non-volatile automatic object ...
// We ignore parentheses here.
@@ -965,9 +964,12 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
// In C++ the return statement is handled via a copy initialization.
// the C version of which boils down to CheckSingleAssignmentConstraints.
// FIXME: Leaks RetValExp on error.
- if (PerformCopyInitialization(RetValExp, FnRetType, "returning", Elidable))
+ if (PerformCopyInitialization(RetValExp, FnRetType, "returning", Elidable)){
+ // We should still clean up our temporaries, even when we're failing!
+ RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true);
return StmtError();
-
+ }
+
if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 5ef3701..466a0e3 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -10,12 +10,14 @@
//===----------------------------------------------------------------------===/
#include "Sema.h"
+#include "Lookup.h"
#include "TreeTransform.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Template.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "llvm/Support/Compiler.h"
@@ -129,29 +131,29 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
LookupCtx = computeDeclContext(ObjectType);
isDependent = ObjectType->isDependentType();
+ assert((isDependent || !ObjectType->isIncompleteType()) &&
+ "Caller should have completed object type");
} else if (SS.isSet()) {
// This nested-name-specifier occurs after another nested-name-specifier,
// so long into the context associated with the prior nested-name-specifier.
-
LookupCtx = computeDeclContext(SS, EnteringContext);
isDependent = isDependentScopeSpecifier(SS);
+
+ // The declaration context must be complete.
+ if (LookupCtx && RequireCompleteDeclContext(SS))
+ return TNK_Non_template;
}
- LookupResult Found;
+ LookupResult Found(*this, TName, SourceLocation(), LookupOrdinaryName);
bool ObjectTypeSearchedInScope = false;
if (LookupCtx) {
// Perform "qualified" name lookup into the declaration context we
// computed, which is either the type of the base of a member access
// expression or the declaration context associated with a prior
// nested-name-specifier.
+ LookupQualifiedName(Found, LookupCtx);
- // The declaration context must be complete.
- if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS))
- return TNK_Non_template;
-
- LookupQualifiedName(Found, LookupCtx, TName, LookupOrdinaryName);
-
- if (ObjectTypePtr && Found.getKind() == LookupResult::NotFound) {
+ if (ObjectTypePtr && Found.empty()) {
// C++ [basic.lookup.classref]p1:
// In a class member access expression (5.2.5), if the . or -> token is
// immediately followed by an identifier followed by a <, the
@@ -164,7 +166,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
//
// FIXME: When we're instantiating a template, do we actually have to
// look in the scope of the template? Seems fishy...
- LookupName(Found, S, TName, LookupOrdinaryName);
+ LookupName(Found, S);
ObjectTypeSearchedInScope = true;
}
} else if (isDependent) {
@@ -172,7 +174,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
return TNK_Non_template;
} else {
// Perform unqualified name lookup in the current scope.
- LookupName(Found, S, TName, LookupOrdinaryName);
+ LookupName(Found, S);
}
// FIXME: Cope with ambiguous name-lookup results.
@@ -190,8 +192,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
// template, the name is also looked up in the context of the entire
// postfix-expression and [...]
//
- LookupResult FoundOuter;
- LookupName(FoundOuter, S, TName, LookupOrdinaryName);
+ LookupResult FoundOuter(*this, TName, SourceLocation(), LookupOrdinaryName);
+ LookupName(FoundOuter, S);
// FIXME: Handle ambiguities in this lookup better
NamedDecl *OuterTemplate
= isAcceptableTemplateName(Context, FoundOuter.getAsSingleDecl(Context));
@@ -283,6 +285,46 @@ TemplateDecl *Sema::AdjustDeclIfTemplate(DeclPtrTy &D) {
return 0;
}
+static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
+ const ParsedTemplateArgument &Arg) {
+
+ switch (Arg.getKind()) {
+ case ParsedTemplateArgument::Type: {
+ DeclaratorInfo *DI;
+ QualType T = SemaRef.GetTypeFromParser(Arg.getAsType(), &DI);
+ if (!DI)
+ DI = SemaRef.Context.getTrivialDeclaratorInfo(T, Arg.getLocation());
+ return TemplateArgumentLoc(TemplateArgument(T), DI);
+ }
+
+ case ParsedTemplateArgument::NonType: {
+ Expr *E = static_cast<Expr *>(Arg.getAsExpr());
+ return TemplateArgumentLoc(TemplateArgument(E), E);
+ }
+
+ case ParsedTemplateArgument::Template: {
+ TemplateName Template
+ = TemplateName::getFromVoidPointer(Arg.getAsTemplate().get());
+ return TemplateArgumentLoc(TemplateArgument(Template),
+ Arg.getScopeSpec().getRange(),
+ Arg.getLocation());
+ }
+ }
+
+ llvm::llvm_unreachable("Unhandled parsed template argument");
+ return TemplateArgumentLoc();
+}
+
+/// \brief Translates template arguments as provided by the parser
+/// into template arguments used by semantic analysis.
+void Sema::translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
+ llvm::SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
+ TemplateArgs.reserve(TemplateArgsIn.size());
+
+ for (unsigned I = 0, Last = TemplateArgsIn.size(); I != Last; ++I)
+ TemplateArgs.push_back(translateTemplateArgument(*this, TemplateArgsIn[I]));
+}
+
/// ActOnTypeParameter - Called when a C++ template type parameter
/// (e.g., "typename T") has been parsed. Typename specifies whether
/// the keyword "typename" was used to declare the type parameter
@@ -517,34 +559,30 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S,
/// parameter.
void Sema::ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParamD,
SourceLocation EqualLoc,
- ExprArg DefaultE) {
+ const ParsedTemplateArgument &Default) {
TemplateTemplateParmDecl *TemplateParm
= cast<TemplateTemplateParmDecl>(TemplateParamD.getAs<Decl>());
-
- // Since a template-template parameter's default argument is an
- // id-expression, it must be a DeclRefExpr.
- DeclRefExpr *Default
- = cast<DeclRefExpr>(static_cast<Expr *>(DefaultE.get()));
-
+
// C++ [temp.param]p14:
// A template-parameter shall not be used in its own default argument.
// FIXME: Implement this check! Needs a recursive walk over the types.
- // Check the well-formedness of the template argument.
- if (!isa<TemplateDecl>(Default->getDecl())) {
- Diag(Default->getSourceRange().getBegin(),
- diag::err_template_arg_must_be_template)
- << Default->getSourceRange();
- TemplateParm->setInvalidDecl();
- return;
- }
- if (CheckTemplateArgument(TemplateParm, Default)) {
- TemplateParm->setInvalidDecl();
+ // Check only that we have a template template argument. We don't want to
+ // try to check well-formedness now, because our template template parameter
+ // might have dependent types in its template parameters, which we wouldn't
+ // be able to match now.
+ //
+ // If none of the template template parameter's template arguments mention
+ // other template parameters, we could actually perform more checking here.
+ // However, it isn't worth doing.
+ TemplateArgumentLoc DefaultArg = translateTemplateArgument(*this, Default);
+ if (DefaultArg.getArgument().getAsTemplate().isNull()) {
+ Diag(DefaultArg.getLocation(), diag::err_template_arg_not_class_template)
+ << DefaultArg.getSourceRange();
return;
}
-
- DefaultE.release();
- TemplateParm->setDefaultArgument(Default);
+
+ TemplateParm->setDefaultArgument(DefaultArg);
}
/// ActOnTemplateParameterList - Builds a TemplateParameterList that
@@ -591,7 +629,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Find any previous declaration with this name.
DeclContext *SemanticContext;
- LookupResult Previous;
+ LookupResult Previous(*this, Name, NameLoc, LookupOrdinaryName,
+ ForRedeclaration);
if (SS.isNotEmpty() && !SS.isInvalid()) {
if (RequireCompleteDeclContext(SS))
return true;
@@ -602,11 +641,10 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
return true;
}
- LookupQualifiedName(Previous, SemanticContext, Name, LookupOrdinaryName,
- true);
+ LookupQualifiedName(Previous, SemanticContext);
} else {
SemanticContext = CurContext;
- LookupName(Previous, S, Name, LookupOrdinaryName, true);
+ LookupName(Previous, S);
}
assert(!Previous.isAmbiguous() && "Ambiguity in class template redecl?");
@@ -669,7 +707,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Ensure that the template parameter lists are compatible.
if (!TemplateParameterListsAreEqual(TemplateParams,
PrevClassTemplate->getTemplateParameters(),
- /*Complain=*/true))
+ /*Complain=*/true,
+ TPL_TemplateMatch))
return true;
// C++ [temp.class]p4:
@@ -923,8 +962,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
= OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : 0;
if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
NewTemplateParm->hasDefaultArgument()) {
- OldDefaultLoc = OldTemplateParm->getDefaultArgumentLoc();
- NewDefaultLoc = NewTemplateParm->getDefaultArgumentLoc();
+ OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation();
+ NewDefaultLoc = NewTemplateParm->getDefaultArgument().getLocation();
SawDefaultArgument = true;
RedundantDefaultArg = true;
PreviousDefaultArgLoc = NewDefaultLoc;
@@ -936,10 +975,12 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
// that points to a previous template template parameter.
NewTemplateParm->setDefaultArgument(
OldTemplateParm->getDefaultArgument());
- PreviousDefaultArgLoc = OldTemplateParm->getDefaultArgumentLoc();
+ PreviousDefaultArgLoc
+ = OldTemplateParm->getDefaultArgument().getLocation();
} else if (NewTemplateParm->hasDefaultArgument()) {
SawDefaultArgument = true;
- PreviousDefaultArgLoc = NewTemplateParm->getDefaultArgumentLoc();
+ PreviousDefaultArgLoc
+ = NewTemplateParm->getDefaultArgument().getLocation();
} else if (SawDefaultArgument)
MissingDefaultArg = true;
}
@@ -1085,7 +1126,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
if (ExpectedTemplateParams)
TemplateParameterListsAreEqual(ParamLists[Idx],
ExpectedTemplateParams,
- true);
+ true, TPL_TemplateMatch);
}
} else if (ParamLists[Idx]->size() > 0)
Diag(ParamLists[Idx]->getTemplateLoc(),
@@ -1118,28 +1159,6 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
return ParamLists[NumParamLists - 1];
}
-/// \brief Translates template arguments as provided by the parser
-/// into template arguments used by semantic analysis.
-void Sema::translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
- SourceLocation *TemplateArgLocs,
- llvm::SmallVector<TemplateArgumentLoc, 16> &TemplateArgs) {
- TemplateArgs.reserve(TemplateArgsIn.size());
-
- void **Args = TemplateArgsIn.getArgs();
- bool *ArgIsType = TemplateArgsIn.getArgIsType();
- for (unsigned Arg = 0, Last = TemplateArgsIn.size(); Arg != Last; ++Arg) {
- if (ArgIsType[Arg]) {
- DeclaratorInfo *DI;
- QualType T = Sema::GetTypeFromParser(Args[Arg], &DI);
- if (!DI) DI = Context.getTrivialDeclaratorInfo(T, TemplateArgLocs[Arg]);
- TemplateArgs.push_back(TemplateArgumentLoc(TemplateArgument(T), DI));
- } else {
- Expr *E = reinterpret_cast<Expr *>(Args[Arg]);
- TemplateArgs.push_back(TemplateArgumentLoc(TemplateArgument(E), E));
- }
- }
-}
-
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
@@ -1169,7 +1188,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
QualType CanonType;
- if (TemplateSpecializationType::anyDependentTemplateArguments(
+ if (Name.isDependent() ||
+ TemplateSpecializationType::anyDependentTemplateArguments(
TemplateArgs,
NumTemplateArgs)) {
// This class template specialization is a dependent
@@ -1228,13 +1248,12 @@ Action::TypeResult
Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
- SourceLocation *TemplateArgLocsIn,
SourceLocation RAngleLoc) {
TemplateName Template = TemplateD.getAsVal<TemplateName>();
// Translate the parser's template argument list in our AST format.
llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs;
- translateTemplateArguments(TemplateArgsIn, TemplateArgLocsIn, TemplateArgs);
+ translateTemplateArguments(TemplateArgsIn, TemplateArgs);
QualType Result = CheckTemplateIdType(Template, TemplateLoc, LAngleLoc,
TemplateArgs.data(),
@@ -1336,13 +1355,12 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(const CXXScopeSpec &SS,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
- SourceLocation *TemplateArgSLs,
SourceLocation RAngleLoc) {
TemplateName Template = TemplateD.getAsVal<TemplateName>();
// Translate the parser's template argument list in our AST format.
llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs;
- translateTemplateArguments(TemplateArgsIn, TemplateArgSLs, TemplateArgs);
+ translateTemplateArguments(TemplateArgsIn, TemplateArgs);
TemplateArgsIn.release();
return BuildTemplateIdExpr((NestedNameSpecifier *)SS.getScopeRep(),
@@ -1449,6 +1467,333 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
return false;
}
+/// \brief Substitute template arguments into the default template argument for
+/// the given template type parameter.
+///
+/// \param SemaRef the semantic analysis object for which we are performing
+/// the substitution.
+///
+/// \param Template the template that we are synthesizing template arguments
+/// for.
+///
+/// \param TemplateLoc the location of the template name that started the
+/// template-id we are checking.
+///
+/// \param RAngleLoc the location of the right angle bracket ('>') that
+/// terminates the template-id.
+///
+/// \param Param the template template parameter whose default we are
+/// substituting into.
+///
+/// \param Converted the list of template arguments provided for template
+/// parameters that precede \p Param in the template parameter list.
+///
+/// \returns the substituted template argument, or NULL if an error occurred.
+static DeclaratorInfo *
+SubstDefaultTemplateArgument(Sema &SemaRef,
+ TemplateDecl *Template,
+ SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc,
+ TemplateTypeParmDecl *Param,
+ TemplateArgumentListBuilder &Converted) {
+ DeclaratorInfo *ArgType = Param->getDefaultArgumentInfo();
+
+ // If the argument type is dependent, instantiate it now based
+ // on the previously-computed template arguments.
+ if (ArgType->getType()->isDependentType()) {
+ TemplateArgumentList TemplateArgs(SemaRef.Context, Converted,
+ /*TakeArgs=*/false);
+
+ MultiLevelTemplateArgumentList AllTemplateArgs
+ = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs);
+
+ Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
+ Template, Converted.getFlatArguments(),
+ Converted.flatSize(),
+ SourceRange(TemplateLoc, RAngleLoc));
+
+ ArgType = SemaRef.SubstType(ArgType, AllTemplateArgs,
+ Param->getDefaultArgumentLoc(),
+ Param->getDeclName());
+ }
+
+ return ArgType;
+}
+
+/// \brief Substitute template arguments into the default template argument for
+/// the given non-type template parameter.
+///
+/// \param SemaRef the semantic analysis object for which we are performing
+/// the substitution.
+///
+/// \param Template the template that we are synthesizing template arguments
+/// for.
+///
+/// \param TemplateLoc the location of the template name that started the
+/// template-id we are checking.
+///
+/// \param RAngleLoc the location of the right angle bracket ('>') that
+/// terminates the template-id.
+///
+/// \param Param the non-type template parameter whose default we are
+/// substituting into.
+///
+/// \param Converted the list of template arguments provided for template
+/// parameters that precede \p Param in the template parameter list.
+///
+/// \returns the substituted template argument, or NULL if an error occurred.
+static Sema::OwningExprResult
+SubstDefaultTemplateArgument(Sema &SemaRef,
+ TemplateDecl *Template,
+ SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc,
+ NonTypeTemplateParmDecl *Param,
+ TemplateArgumentListBuilder &Converted) {
+ TemplateArgumentList TemplateArgs(SemaRef.Context, Converted,
+ /*TakeArgs=*/false);
+
+ MultiLevelTemplateArgumentList AllTemplateArgs
+ = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs);
+
+ Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
+ Template, Converted.getFlatArguments(),
+ Converted.flatSize(),
+ SourceRange(TemplateLoc, RAngleLoc));
+
+ return SemaRef.SubstExpr(Param->getDefaultArgument(), AllTemplateArgs);
+}
+
+/// \brief Substitute template arguments into the default template argument for
+/// the given template template parameter.
+///
+/// \param SemaRef the semantic analysis object for which we are performing
+/// the substitution.
+///
+/// \param Template the template that we are synthesizing template arguments
+/// for.
+///
+/// \param TemplateLoc the location of the template name that started the
+/// template-id we are checking.
+///
+/// \param RAngleLoc the location of the right angle bracket ('>') that
+/// terminates the template-id.
+///
+/// \param Param the template template parameter whose default we are
+/// substituting into.
+///
+/// \param Converted the list of template arguments provided for template
+/// parameters that precede \p Param in the template parameter list.
+///
+/// \returns the substituted template argument, or NULL if an error occurred.
+static TemplateName
+SubstDefaultTemplateArgument(Sema &SemaRef,
+ TemplateDecl *Template,
+ SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc,
+ TemplateTemplateParmDecl *Param,
+ TemplateArgumentListBuilder &Converted) {
+ TemplateArgumentList TemplateArgs(SemaRef.Context, Converted,
+ /*TakeArgs=*/false);
+
+ MultiLevelTemplateArgumentList AllTemplateArgs
+ = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs);
+
+ Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
+ Template, Converted.getFlatArguments(),
+ Converted.flatSize(),
+ SourceRange(TemplateLoc, RAngleLoc));
+
+ return SemaRef.SubstTemplateName(
+ Param->getDefaultArgument().getArgument().getAsTemplate(),
+ Param->getDefaultArgument().getTemplateNameLoc(),
+ AllTemplateArgs);
+}
+
+/// \brief Check that the given template argument corresponds to the given
+/// template parameter.
+bool Sema::CheckTemplateArgument(NamedDecl *Param,
+ const TemplateArgumentLoc &Arg,
+ TemplateDecl *Template,
+ SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc,
+ TemplateArgumentListBuilder &Converted) {
+ // Check template type parameters.
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+ return CheckTemplateTypeArgument(TTP, Arg, Converted);
+
+ // Check non-type template parameters.
+ if (NonTypeTemplateParmDecl *NTTP =dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ // Do substitution on the type of the non-type template parameter
+ // with the template arguments we've seen thus far.
+ QualType NTTPType = NTTP->getType();
+ if (NTTPType->isDependentType()) {
+ // Do substitution on the type of the non-type template parameter.
+ InstantiatingTemplate Inst(*this, TemplateLoc, Template,
+ NTTP, Converted.getFlatArguments(),
+ Converted.flatSize(),
+ SourceRange(TemplateLoc, RAngleLoc));
+
+ TemplateArgumentList TemplateArgs(Context, Converted,
+ /*TakeArgs=*/false);
+ NTTPType = SubstType(NTTPType,
+ MultiLevelTemplateArgumentList(TemplateArgs),
+ NTTP->getLocation(),
+ NTTP->getDeclName());
+ // If that worked, check the non-type template parameter type
+ // for validity.
+ if (!NTTPType.isNull())
+ NTTPType = CheckNonTypeTemplateParameterType(NTTPType,
+ NTTP->getLocation());
+ if (NTTPType.isNull())
+ return true;
+ }
+
+ switch (Arg.getArgument().getKind()) {
+ case TemplateArgument::Null:
+ assert(false && "Should never see a NULL template argument here");
+ return true;
+
+ case TemplateArgument::Expression: {
+ Expr *E = Arg.getArgument().getAsExpr();
+ TemplateArgument Result;
+ if (CheckTemplateArgument(NTTP, NTTPType, E, Result))
+ return true;
+
+ Converted.Append(Result);
+ break;
+ }
+
+ case TemplateArgument::Declaration:
+ case TemplateArgument::Integral:
+ // We've already checked this template argument, so just copy
+ // it to the list of converted arguments.
+ Converted.Append(Arg.getArgument());
+ break;
+
+ case TemplateArgument::Template:
+ // We were given a template template argument. It may not be ill-formed;
+ // see below.
+ if (DependentTemplateName *DTN
+ = Arg.getArgument().getAsTemplate().getAsDependentTemplateName()) {
+ // We have a template argument such as \c T::template X, which we
+ // parsed as a template template argument. However, since we now
+ // know that we need a non-type template argument, convert this
+ // template name into an expression.
+ Expr *E = new (Context) UnresolvedDeclRefExpr(DTN->getIdentifier(),
+ Context.DependentTy,
+ Arg.getTemplateNameLoc(),
+ Arg.getTemplateQualifierRange(),
+ DTN->getQualifier(),
+ /*isAddressOfOperand=*/false);
+
+ TemplateArgument Result;
+ if (CheckTemplateArgument(NTTP, NTTPType, E, Result))
+ return true;
+
+ Converted.Append(Result);
+ break;
+ }
+
+ // We have a template argument that actually does refer to a class
+ // template, template alias, or template template parameter, and
+ // therefore cannot be a non-type template argument.
+ Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr)
+ << Arg.getSourceRange();
+
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+
+ case TemplateArgument::Type: {
+ // We have a non-type template parameter but the template
+ // argument is a type.
+
+ // C++ [temp.arg]p2:
+ // In a template-argument, an ambiguity between a type-id and
+ // an expression is resolved to a type-id, regardless of the
+ // form of the corresponding template-parameter.
+ //
+ // We warn specifically about this case, since it can be rather
+ // confusing for users.
+ QualType T = Arg.getArgument().getAsType();
+ SourceRange SR = Arg.getSourceRange();
+ if (T->isFunctionType())
+ Diag(SR.getBegin(), diag::err_template_arg_nontype_ambig) << SR << T;
+ else
+ Diag(SR.getBegin(), diag::err_template_arg_must_be_expr) << SR;
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ case TemplateArgument::Pack:
+ llvm::llvm_unreachable("Caller must expand template argument packs");
+ break;
+ }
+
+ return false;
+ }
+
+
+ // Check template template parameters.
+ TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(Param);
+
+ // Substitute into the template parameter list of the template
+ // template parameter, since previously-supplied template arguments
+ // may appear within the template template parameter.
+ {
+ // Set up a template instantiation context.
+ LocalInstantiationScope Scope(*this);
+ InstantiatingTemplate Inst(*this, TemplateLoc, Template,
+ TempParm, Converted.getFlatArguments(),
+ Converted.flatSize(),
+ SourceRange(TemplateLoc, RAngleLoc));
+
+ TemplateArgumentList TemplateArgs(Context, Converted,
+ /*TakeArgs=*/false);
+ TempParm = cast_or_null<TemplateTemplateParmDecl>(
+ SubstDecl(TempParm, CurContext,
+ MultiLevelTemplateArgumentList(TemplateArgs)));
+ if (!TempParm)
+ return true;
+
+ // FIXME: TempParam is leaked.
+ }
+
+ switch (Arg.getArgument().getKind()) {
+ case TemplateArgument::Null:
+ assert(false && "Should never see a NULL template argument here");
+ return true;
+
+ case TemplateArgument::Template:
+ if (CheckTemplateArgument(TempParm, Arg))
+ return true;
+
+ Converted.Append(Arg.getArgument());
+ break;
+
+ case TemplateArgument::Expression:
+ case TemplateArgument::Type:
+ // We have a template template parameter but the template
+ // argument does not refer to a template.
+ Diag(Arg.getLocation(), diag::err_template_arg_must_be_template);
+ return true;
+
+ case TemplateArgument::Declaration:
+ llvm::llvm_unreachable(
+ "Declaration argument with template template parameter");
+ break;
+ case TemplateArgument::Integral:
+ llvm::llvm_unreachable(
+ "Integral argument with template template parameter");
+ break;
+
+ case TemplateArgument::Pack:
+ llvm::llvm_unreachable("Caller must expand template argument packs");
+ break;
+ }
+
+ return false;
+}
+
/// \brief Check that the given template argument list is well-formed
/// for specializing the given template.
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
@@ -1499,226 +1844,105 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
if (ArgIdx > NumArgs && PartialTemplateArgs)
break;
- // Decode the template argument
- TemplateArgumentLoc Arg;
-
- if (ArgIdx >= NumArgs) {
- // Retrieve the default template argument from the template
- // parameter.
- if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
- if (TTP->isParameterPack()) {
- // We have an empty argument pack.
- Converted.BeginPack();
- Converted.EndPack();
- break;
- }
-
- if (!TTP->hasDefaultArgument())
+ // If we have a template parameter pack, check every remaining template
+ // argument against that template parameter pack.
+ if ((*Param)->isTemplateParameterPack()) {
+ Converted.BeginPack();
+ for (; ArgIdx < NumArgs; ++ArgIdx) {
+ if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template,
+ TemplateLoc, RAngleLoc, Converted)) {
+ Invalid = true;
break;
-
- DeclaratorInfo *ArgType = TTP->getDefaultArgumentInfo();
-
- // If the argument type is dependent, instantiate it now based
- // on the previously-computed template arguments.
- if (ArgType->getType()->isDependentType()) {
- InstantiatingTemplate Inst(*this, TemplateLoc,
- Template, Converted.getFlatArguments(),
- Converted.flatSize(),
- SourceRange(TemplateLoc, RAngleLoc));
-
- TemplateArgumentList TemplateArgs(Context, Converted,
- /*TakeArgs=*/false);
- ArgType = SubstType(ArgType,
- MultiLevelTemplateArgumentList(TemplateArgs),
- TTP->getDefaultArgumentLoc(),
- TTP->getDeclName());
}
-
- if (!ArgType)
- return true;
-
- Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()), ArgType);
- } else if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
- if (!NTTP->hasDefaultArgument())
- break;
-
- InstantiatingTemplate Inst(*this, TemplateLoc,
- Template, Converted.getFlatArguments(),
- Converted.flatSize(),
- SourceRange(TemplateLoc, RAngleLoc));
-
- TemplateArgumentList TemplateArgs(Context, Converted,
- /*TakeArgs=*/false);
-
- Sema::OwningExprResult E
- = SubstExpr(NTTP->getDefaultArgument(),
- MultiLevelTemplateArgumentList(TemplateArgs));
- if (E.isInvalid())
- return true;
-
- Expr *Ex = E.takeAs<Expr>();
- Arg = TemplateArgumentLoc(TemplateArgument(Ex), Ex);
- } else {
- TemplateTemplateParmDecl *TempParm
- = cast<TemplateTemplateParmDecl>(*Param);
-
- if (!TempParm->hasDefaultArgument())
- break;
-
- // FIXME: Subst default argument
- Arg = TemplateArgumentLoc(TemplateArgument(TempParm->getDefaultArgument()),
- TempParm->getDefaultArgument());
}
- } else {
- // Retrieve the template argument produced by the user.
- Arg = TemplateArgs[ArgIdx];
+ Converted.EndPack();
+ continue;
}
-
-
+
+ if (ArgIdx < NumArgs) {
+ // Check the template argument we were given.
+ if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template,
+ TemplateLoc, RAngleLoc, Converted))
+ return true;
+
+ continue;
+ }
+
+ // We have a default template argument that we will use.
+ TemplateArgumentLoc Arg;
+
+ // Retrieve the default template argument from the template
+ // parameter. For each kind of template parameter, we substitute the
+ // template arguments provided thus far and any "outer" template arguments
+ // (when the template parameter was part of a nested template) into
+ // the default argument.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
- if (TTP->isParameterPack()) {
- Converted.BeginPack();
- // Check all the remaining arguments (if any).
- for (; ArgIdx < NumArgs; ++ArgIdx) {
- if (CheckTemplateTypeArgument(TTP, TemplateArgs[ArgIdx], Converted))
- Invalid = true;
- }
-
- Converted.EndPack();
- } else {
- if (CheckTemplateTypeArgument(TTP, Arg, Converted))
- Invalid = true;
+ if (!TTP->hasDefaultArgument()) {
+ assert((Invalid || PartialTemplateArgs) && "Missing default argument");
+ break;
}
+
+ DeclaratorInfo *ArgType = SubstDefaultTemplateArgument(*this,
+ Template,
+ TemplateLoc,
+ RAngleLoc,
+ TTP,
+ Converted);
+ if (!ArgType)
+ return true;
+
+ Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()),
+ ArgType);
} else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
- // Check non-type template parameters.
-
- // Do substitution on the type of the non-type template parameter
- // with the template arguments we've seen thus far.
- QualType NTTPType = NTTP->getType();
- if (NTTPType->isDependentType()) {
- // Do substitution on the type of the non-type template parameter.
- InstantiatingTemplate Inst(*this, TemplateLoc,
- Template, Converted.getFlatArguments(),
- Converted.flatSize(),
- SourceRange(TemplateLoc, RAngleLoc));
-
- TemplateArgumentList TemplateArgs(Context, Converted,
- /*TakeArgs=*/false);
- NTTPType = SubstType(NTTPType,
- MultiLevelTemplateArgumentList(TemplateArgs),
- NTTP->getLocation(),
- NTTP->getDeclName());
- // If that worked, check the non-type template parameter type
- // for validity.
- if (!NTTPType.isNull())
- NTTPType = CheckNonTypeTemplateParameterType(NTTPType,
- NTTP->getLocation());
- if (NTTPType.isNull()) {
- Invalid = true;
- break;
- }
- }
-
- switch (Arg.getArgument().getKind()) {
- case TemplateArgument::Null:
- assert(false && "Should never see a NULL template argument here");
- break;
-
- case TemplateArgument::Expression: {
- Expr *E = Arg.getArgument().getAsExpr();
- TemplateArgument Result;
- if (CheckTemplateArgument(NTTP, NTTPType, E, Result))
- Invalid = true;
- else
- Converted.Append(Result);
+ if (!NTTP->hasDefaultArgument()) {
+ assert((Invalid || PartialTemplateArgs) && "Missing default argument");
break;
}
- case TemplateArgument::Declaration:
- case TemplateArgument::Integral:
- // We've already checked this template argument, so just copy
- // it to the list of converted arguments.
- Converted.Append(Arg.getArgument());
- break;
-
- case TemplateArgument::Type: {
- // We have a non-type template parameter but the template
- // argument is a type.
-
- // C++ [temp.arg]p2:
- // In a template-argument, an ambiguity between a type-id and
- // an expression is resolved to a type-id, regardless of the
- // form of the corresponding template-parameter.
- //
- // We warn specifically about this case, since it can be rather
- // confusing for users.
- QualType T = Arg.getArgument().getAsType();
- SourceRange SR = Arg.getSourceRange();
- if (T->isFunctionType())
- Diag(SR.getBegin(), diag::err_template_arg_nontype_ambig)
- << SR << T;
- else
- Diag(SR.getBegin(), diag::err_template_arg_must_be_expr) << SR;
- Diag((*Param)->getLocation(), diag::note_template_param_here);
- Invalid = true;
- break;
- }
+ Sema::OwningExprResult E = SubstDefaultTemplateArgument(*this, Template,
+ TemplateLoc,
+ RAngleLoc,
+ NTTP,
+ Converted);
+ if (E.isInvalid())
+ return true;
- case TemplateArgument::Pack:
- assert(0 && "FIXME: Implement!");
- break;
- }
+ Expr *Ex = E.takeAs<Expr>();
+ Arg = TemplateArgumentLoc(TemplateArgument(Ex), Ex);
} else {
- // Check template template parameters.
TemplateTemplateParmDecl *TempParm
= cast<TemplateTemplateParmDecl>(*Param);
- switch (Arg.getArgument().getKind()) {
- case TemplateArgument::Null:
- assert(false && "Should never see a NULL template argument here");
+ if (!TempParm->hasDefaultArgument()) {
+ assert((Invalid || PartialTemplateArgs) && "Missing default argument");
break;
-
- case TemplateArgument::Expression: {
- Expr *ArgExpr = Arg.getArgument().getAsExpr();
- if (ArgExpr && isa<DeclRefExpr>(ArgExpr) &&
- isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) {
- if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr)))
- Invalid = true;
-
- // Add the converted template argument.
- Decl *D
- = cast<DeclRefExpr>(ArgExpr)->getDecl()->getCanonicalDecl();
- Converted.Append(TemplateArgument(D));
- continue;
- }
}
- // fall through
- case TemplateArgument::Type: {
- // We have a template template parameter but the template
- // argument does not refer to a template.
- Diag(Arg.getLocation(), diag::err_template_arg_must_be_template);
- Invalid = true;
- break;
- }
-
- case TemplateArgument::Declaration:
- // We've already checked this template argument, so just copy
- // it to the list of converted arguments.
- Converted.Append(Arg.getArgument());
- break;
-
- case TemplateArgument::Integral:
- assert(false && "Integral argument with template template parameter");
- break;
-
- case TemplateArgument::Pack:
- assert(0 && "FIXME: Implement!");
- break;
- }
+ TemplateName Name = SubstDefaultTemplateArgument(*this, Template,
+ TemplateLoc,
+ RAngleLoc,
+ TempParm,
+ Converted);
+ if (Name.isNull())
+ return true;
+
+ Arg = TemplateArgumentLoc(TemplateArgument(Name),
+ TempParm->getDefaultArgument().getTemplateQualifierRange(),
+ TempParm->getDefaultArgument().getTemplateNameLoc());
}
+
+ // Introduce an instantiation record that describes where we are using
+ // the default template argument.
+ InstantiatingTemplate Instantiating(*this, RAngleLoc, Template, *Param,
+ Converted.getFlatArguments(),
+ Converted.flatSize(),
+ SourceRange(TemplateLoc, RAngleLoc));
+
+ // Check the default template argument.
+ if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc,
+ RAngleLoc, Converted))
+ return true;
}
return Invalid;
@@ -1864,8 +2088,8 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
/// \brief Checks whether the given template argument is a pointer to
/// member constant according to C++ [temp.arg.nontype]p1.
-bool
-Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
+bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg,
+ TemplateArgument &Converted) {
bool Invalid = false;
// See through any implicit casts we added to fix the type.
@@ -1896,13 +2120,33 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
Arg = Parens->getSubExpr();
}
- if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg))
+ // A pointer-to-member constant written &Class::member.
+ if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) {
if (UnOp->getOpcode() == UnaryOperator::AddrOf) {
DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr());
if (DRE && !DRE->getQualifier())
DRE = 0;
}
-
+ }
+ // A constant of pointer-to-member type.
+ else if ((DRE = dyn_cast<DeclRefExpr>(Arg))) {
+ if (ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl())) {
+ if (VD->getType()->isMemberPointerType()) {
+ if (isa<NonTypeTemplateParmDecl>(VD) ||
+ (isa<VarDecl>(VD) &&
+ Context.getCanonicalType(VD->getType()).isConstQualified())) {
+ if (Arg->isTypeDependent() || Arg->isValueDependent())
+ Converted = TemplateArgument(Arg->Retain());
+ else
+ Converted = TemplateArgument(VD->getCanonicalDecl());
+ return Invalid;
+ }
+ }
+ }
+
+ DRE = 0;
+ }
+
if (!DRE)
return Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_pointer_to_member_form)
@@ -1915,7 +2159,10 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
// Okay: this is the address of a non-static member, and therefore
// a member pointer constant.
- Member = DRE->getDecl();
+ if (Arg->isTypeDependent() || Arg->isValueDependent())
+ Converted = TemplateArgument(Arg->Retain());
+ else
+ Converted = TemplateArgument(DRE->getDecl()->getCanonicalDecl());
return Invalid;
}
@@ -2119,16 +2366,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
- if (ParamType->isMemberPointerType()) {
- NamedDecl *Member = 0;
- if (CheckTemplateArgumentPointerToMember(Arg, Member))
- return true;
-
- if (Member)
- Member = cast<NamedDecl>(Member->getCanonicalDecl());
- Converted = TemplateArgument(Member);
- return false;
- }
+ if (ParamType->isMemberPointerType())
+ return CheckTemplateArgumentPointerToMember(Arg, Converted);
NamedDecl *Entity = 0;
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
@@ -2241,14 +2480,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
- NamedDecl *Member = 0;
- if (CheckTemplateArgumentPointerToMember(Arg, Member))
- return true;
-
- if (Member)
- Member = cast<NamedDecl>(Member->getCanonicalDecl());
- Converted = TemplateArgument(Member);
- return false;
+ return CheckTemplateArgumentPointerToMember(Arg, Converted);
}
/// \brief Check a template argument against its corresponding
@@ -2257,9 +2489,14 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
/// This routine implements the semantics of C++ [temp.arg.template].
/// It returns true if an error occurred, and false otherwise.
bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
- DeclRefExpr *Arg) {
- assert(isa<TemplateDecl>(Arg->getDecl()) && "Only template decls allowed");
- TemplateDecl *Template = cast<TemplateDecl>(Arg->getDecl());
+ const TemplateArgumentLoc &Arg) {
+ TemplateName Name = Arg.getArgument().getAsTemplate();
+ TemplateDecl *Template = Name.getAsTemplateDecl();
+ if (!Template) {
+ // Any dependent template name is fine.
+ assert(Name.isDependent() && "Non-dependent template isn't a declaration?");
+ return false;
+ }
// C++ [temp.arg.template]p1:
// A template-argument for a template template-parameter shall be
@@ -2276,15 +2513,16 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
!isa<TemplateTemplateParmDecl>(Template)) {
assert(isa<FunctionTemplateDecl>(Template) &&
"Only function templates are possible here");
- Diag(Arg->getLocStart(), diag::err_template_arg_not_class_template);
+ Diag(Arg.getLocation(), diag::err_template_arg_not_class_template);
Diag(Template->getLocation(), diag::note_template_arg_refers_here_func)
<< Template;
}
return !TemplateParameterListsAreEqual(Template->getTemplateParameters(),
Param->getTemplateParameters(),
- true, true,
- Arg->getSourceRange().getBegin());
+ true,
+ TPL_TemplateTemplateArgumentMatch,
+ Arg.getLocation());
}
/// \brief Determine whether the given template parameter lists are
@@ -2300,9 +2538,7 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
/// \param Complain If true, this routine will produce a diagnostic if
/// the template parameter lists are not equivalent.
///
-/// \param IsTemplateTemplateParm If true, this routine is being
-/// called to compare the template parameter lists of a template
-/// template parameter.
+/// \param Kind describes how we are to match the template parameter lists.
///
/// \param TemplateArgLoc If this source location is valid, then we
/// are actually checking the template parameter list of a template
@@ -2316,7 +2552,7 @@ bool
Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
TemplateParameterList *Old,
bool Complain,
- bool IsTemplateTemplateParm,
+ TemplateParameterListEqualKind Kind,
SourceLocation TemplateArgLoc) {
if (Old->size() != New->size()) {
if (Complain) {
@@ -2327,10 +2563,10 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
}
Diag(New->getTemplateLoc(), NextDiag)
<< (New->size() > Old->size())
- << IsTemplateTemplateParm
+ << (Kind != TPL_TemplateMatch)
<< SourceRange(New->getTemplateLoc(), New->getRAngleLoc());
Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration)
- << IsTemplateTemplateParm
+ << (Kind != TPL_TemplateMatch)
<< SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc());
}
@@ -2348,9 +2584,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
NextDiag = diag::note_template_param_different_kind;
}
Diag((*NewParm)->getLocation(), NextDiag)
- << IsTemplateTemplateParm;
+ << (Kind != TPL_TemplateMatch);
Diag((*OldParm)->getLocation(), diag::note_template_prev_declaration)
- << IsTemplateTemplateParm;
+ << (Kind != TPL_TemplateMatch);
}
return false;
}
@@ -2358,26 +2594,21 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
if (isa<TemplateTypeParmDecl>(*OldParm)) {
// Okay; all template type parameters are equivalent (since we
// know we're at the same index).
-#if 0
- // FIXME: Enable this code in debug mode *after* we properly go through
- // and "instantiate" the template parameter lists of template template
- // parameters. It's only after this instantiation that (1) any dependent
- // types within the template parameter list of the template template
- // parameter can be checked, and (2) the template type parameter depths
- // will match up.
- QualType OldParmType
- = Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*OldParm));
- QualType NewParmType
- = Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*NewParm));
- assert(Context.getCanonicalType(OldParmType) ==
- Context.getCanonicalType(NewParmType) &&
- "type parameter mismatch?");
-#endif
} else if (NonTypeTemplateParmDecl *OldNTTP
= dyn_cast<NonTypeTemplateParmDecl>(*OldParm)) {
// The types of non-type template parameters must agree.
NonTypeTemplateParmDecl *NewNTTP
= cast<NonTypeTemplateParmDecl>(*NewParm);
+
+ // If we are matching a template template argument to a template
+ // template parameter and one of the non-type template parameter types
+ // is dependent, then we must wait until template instantiation time
+ // to actually compare the arguments.
+ if (Kind == TPL_TemplateTemplateArgumentMatch &&
+ (OldNTTP->getType()->isDependentType() ||
+ NewNTTP->getType()->isDependentType()))
+ continue;
+
if (Context.getCanonicalType(OldNTTP->getType()) !=
Context.getCanonicalType(NewNTTP->getType())) {
if (Complain) {
@@ -2389,7 +2620,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
}
Diag(NewNTTP->getLocation(), NextDiag)
<< NewNTTP->getType()
- << IsTemplateTemplateParm;
+ << (Kind != TPL_TemplateMatch);
Diag(OldNTTP->getLocation(),
diag::note_template_nontype_parm_prev_declaration)
<< OldNTTP->getType();
@@ -2399,7 +2630,6 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
} else {
// The template parameter lists of template template
// parameters must agree.
- // FIXME: Could we perform a faster "type" comparison here?
assert(isa<TemplateTemplateParmDecl>(*OldParm) &&
"Only template template parameters handled here");
TemplateTemplateParmDecl *OldTTP
@@ -2409,7 +2639,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
if (!TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(),
OldTTP->getTemplateParameters(),
Complain,
- /*IsTemplateTemplateParm=*/true,
+ (Kind == TPL_TemplateMatch? TPL_TemplateTemplateParmMatch : Kind),
TemplateArgLoc))
return false;
}
@@ -2635,16 +2865,9 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
} else if (TemplateTemplateParmDecl *TTP
= dyn_cast<TemplateTemplateParmDecl>(
TemplateParams->getParam(I))) {
- // FIXME: We should settle on either Declaration storage or
- // Expression storage for template template parameters.
+ TemplateName Name = ArgList[I].getAsTemplate();
TemplateTemplateParmDecl *ArgDecl
- = dyn_cast_or_null<TemplateTemplateParmDecl>(
- ArgList[I].getAsDecl());
- if (!ArgDecl)
- if (DeclRefExpr *DRE
- = dyn_cast_or_null<DeclRefExpr>(ArgList[I].getAsExpr()))
- ArgDecl = dyn_cast<TemplateTemplateParmDecl>(DRE->getDecl());
-
+ = dyn_cast_or_null<TemplateTemplateParmDecl>(Name.getAsTemplateDecl());
if (!ArgDecl ||
ArgDecl->getIndex() != TTP->getIndex() ||
ArgDecl->getDepth() != TTP->getDepth())
@@ -2724,7 +2947,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
- SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc,
AttributeList *Attr,
MultiTemplateParamsArg TemplateParameterLists) {
@@ -2733,7 +2955,14 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// Find the class template we're specializing
TemplateName Name = TemplateD.getAsVal<TemplateName>();
ClassTemplateDecl *ClassTemplate
- = cast<ClassTemplateDecl>(Name.getAsTemplateDecl());
+ = dyn_cast_or_null<ClassTemplateDecl>(Name.getAsTemplateDecl());
+
+ if (!ClassTemplate) {
+ Diag(TemplateNameLoc, diag::err_not_class_template_specialization)
+ << (Name.getAsTemplateDecl() &&
+ isa<TemplateTemplateParmDecl>(Name.getAsTemplateDecl()));
+ return true;
+ }
bool isExplicitSpecialization = false;
bool isPartialSpecialization = false;
@@ -2772,12 +3001,11 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
}
} else {
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(Param);
- if (Expr *DefArg = TTP->getDefaultArgument()) {
- Diag(TTP->getDefaultArgumentLoc(),
+ if (TTP->hasDefaultArgument()) {
+ Diag(TTP->getDefaultArgument().getLocation(),
diag::err_default_arg_in_partial_spec)
- << DefArg->getSourceRange();
- TTP->setDefaultArgument(0);
- DefArg->Destroy(Context);
+ << TTP->getDefaultArgument().getSourceRange();
+ TTP->setDefaultArgument(TemplateArgumentLoc());
}
}
}
@@ -2819,7 +3047,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// Translate the parser's template argument list in our AST format.
llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs;
- translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
+ translateTemplateArguments(TemplateArgsIn, TemplateArgs);
// Check that the template argument list is well-formed for this
// template.
@@ -3625,7 +3853,6 @@ Sema::ActOnExplicitInstantiation(Scope *S,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
- SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc,
AttributeList *Attr) {
// Find the class template we're specializing
@@ -3664,7 +3891,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// Translate the parser's template argument list in our AST format.
llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs;
- translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
+ translateTemplateArguments(TemplateArgsIn, TemplateArgs);
// Check that the template argument list is well-formed for this
// template.
@@ -3966,19 +4193,16 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
= ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
: TSK_ExplicitInstantiationDeclaration;
- LookupResult Previous;
- LookupParsedName(Previous, S, &D.getCXXScopeSpec(),
- Name, LookupOrdinaryName);
+ LookupResult Previous(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName);
+ LookupParsedName(Previous, S, &D.getCXXScopeSpec());
if (!R->isFunctionType()) {
// C++ [temp.explicit]p1:
// A [...] static data member of a class template can be explicitly
// instantiated from the member definition associated with its class
// template.
- if (Previous.isAmbiguous()) {
- return DiagnoseAmbiguousLookup(Previous, Name, D.getIdentifierLoc(),
- D.getSourceRange());
- }
+ if (Previous.isAmbiguous())
+ return true;
VarDecl *Prev = dyn_cast_or_null<VarDecl>(
Previous.getAsSingleDecl(Context));
@@ -4047,10 +4271,8 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
ASTTemplateArgsPtr TemplateArgsPtr(*this,
TemplateId->getTemplateArgs(),
- TemplateId->getTemplateArgIsType(),
TemplateId->NumArgs);
translateTemplateArguments(TemplateArgsPtr,
- TemplateId->getTemplateArgLocations(),
TemplateArgs);
HasExplicitTemplateArgs = true;
TemplateArgsPtr.release();
@@ -4259,11 +4481,11 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
assert(Ctx && "No declaration context?");
DeclarationName Name(&II);
- LookupResult Result;
- LookupQualifiedName(Result, Ctx, Name, LookupOrdinaryName, false);
+ LookupResult Result(*this, Name, Range.getEnd(), LookupOrdinaryName);
+ LookupQualifiedName(Result, Ctx);
unsigned DiagID = 0;
Decl *Referenced = 0;
- switch (Result.getKind()) {
+ switch (Result.getResultKind()) {
case LookupResult::NotFound:
DiagID = diag::err_typename_nested_not_found;
break;
@@ -4280,13 +4502,16 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
Referenced = Result.getFoundDecl();
break;
+ case LookupResult::FoundUnresolvedValue:
+ llvm::llvm_unreachable("unresolved using decl in non-dependent context");
+ return QualType();
+
case LookupResult::FoundOverloaded:
DiagID = diag::err_typename_nested_not_type;
Referenced = *Result.begin();
break;
case LookupResult::Ambiguous:
- DiagnoseAmbiguousLookup(Result, Name, Range.getEnd(), Range);
return QualType();
}
@@ -4436,12 +4661,24 @@ QualType Sema::RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc,
std::string
Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params,
const TemplateArgumentList &Args) {
+ // FIXME: For variadic templates, we'll need to get the structured list.
+ return getTemplateArgumentBindingsText(Params, Args.getFlatArgumentList(),
+ Args.flat_size());
+}
+
+std::string
+Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params,
+ const TemplateArgument *Args,
+ unsigned NumArgs) {
std::string Result;
- if (!Params || Params->size() == 0)
+ if (!Params || Params->size() == 0 || NumArgs == 0)
return Result;
for (unsigned I = 0, N = Params->size(); I != N; ++I) {
+ if (I >= NumArgs)
+ break;
+
if (I == 0)
Result += "[with ";
else
@@ -4484,6 +4721,14 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params,
break;
}
+ case TemplateArgument::Template: {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ Args[I].getAsTemplate().print(OS, Context.PrintingPolicy);
+ Result += OS.str();
+ break;
+ }
+
case TemplateArgument::Integral: {
Result += Args[I].getAsIntegral()->toString(10);
break;
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 7b5ad7f..10594c7 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -126,7 +126,6 @@ DeduceNonTypeTemplateArgument(ASTContext &Context,
/// from the given type- or value-dependent expression.
///
/// \returns true if deduction succeeded, false otherwise.
-
static Sema::TemplateDeductionResult
DeduceNonTypeTemplateArgument(ASTContext &Context,
NonTypeTemplateParmDecl *NTTP,
@@ -166,34 +165,87 @@ DeduceNonTypeTemplateArgument(ASTContext &Context,
return Sema::TDK_Success;
}
+/// \brief Deduce the value of the given non-type template parameter
+/// from the given declaration.
+///
+/// \returns true if deduction succeeded, false otherwise.
+static Sema::TemplateDeductionResult
+DeduceNonTypeTemplateArgument(ASTContext &Context,
+ NonTypeTemplateParmDecl *NTTP,
+ Decl *D,
+ Sema::TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ assert(NTTP->getDepth() == 0 &&
+ "Cannot deduce non-type template argument with depth > 0");
+
+ if (Deduced[NTTP->getIndex()].isNull()) {
+ Deduced[NTTP->getIndex()] = TemplateArgument(D->getCanonicalDecl());
+ return Sema::TDK_Success;
+ }
+
+ if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Expression) {
+ // Okay, we deduced a declaration in one case and a dependent expression
+ // in another case.
+ return Sema::TDK_Success;
+ }
+
+ if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Declaration) {
+ // Compare the declarations for equality
+ if (Deduced[NTTP->getIndex()].getAsDecl()->getCanonicalDecl() ==
+ D->getCanonicalDecl())
+ return Sema::TDK_Success;
+
+ // FIXME: Fill in argument mismatch information
+ return Sema::TDK_NonDeducedMismatch;
+ }
+
+ return Sema::TDK_Success;
+}
+
static Sema::TemplateDeductionResult
DeduceTemplateArguments(ASTContext &Context,
+ TemplateParameterList *TemplateParams,
TemplateName Param,
TemplateName Arg,
Sema::TemplateDeductionInfo &Info,
llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
- // FIXME: Implement template argument deduction for template
- // template parameters.
-
- // FIXME: this routine does not have enough information to produce
- // good diagnostics.
-
TemplateDecl *ParamDecl = Param.getAsTemplateDecl();
- TemplateDecl *ArgDecl = Arg.getAsTemplateDecl();
-
- if (!ParamDecl || !ArgDecl) {
- // FIXME: fill in Info.Param/Info.FirstArg
- return Sema::TDK_Inconsistent;
+ if (!ParamDecl) {
+ // The parameter type is dependent and is not a template template parameter,
+ // so there is nothing that we can deduce.
+ return Sema::TDK_Success;
}
-
- ParamDecl = cast<TemplateDecl>(ParamDecl->getCanonicalDecl());
- ArgDecl = cast<TemplateDecl>(ArgDecl->getCanonicalDecl());
- if (ParamDecl != ArgDecl) {
- // FIXME: fill in Info.Param/Info.FirstArg
+
+ if (TemplateTemplateParmDecl *TempParam
+ = dyn_cast<TemplateTemplateParmDecl>(ParamDecl)) {
+ // Bind the template template parameter to the given template name.
+ TemplateArgument &ExistingArg = Deduced[TempParam->getIndex()];
+ if (ExistingArg.isNull()) {
+ // This is the first deduction for this template template parameter.
+ ExistingArg = TemplateArgument(Context.getCanonicalTemplateName(Arg));
+ return Sema::TDK_Success;
+ }
+
+ // Verify that the previous binding matches this deduction.
+ assert(ExistingArg.getKind() == TemplateArgument::Template);
+ if (Context.hasSameTemplateName(ExistingArg.getAsTemplate(), Arg))
+ return Sema::TDK_Success;
+
+ // Inconsistent deduction.
+ Info.Param = TempParam;
+ Info.FirstArg = ExistingArg;
+ Info.SecondArg = TemplateArgument(Arg);
return Sema::TDK_Inconsistent;
}
-
- return Sema::TDK_Success;
+
+ // Verify that the two template names are equivalent.
+ if (Context.hasSameTemplateName(Param, Arg))
+ return Sema::TDK_Success;
+
+ // Mismatch of non-dependent template parameter to argument.
+ Info.FirstArg = TemplateArgument(Param);
+ Info.SecondArg = TemplateArgument(Arg);
+ return Sema::TDK_NonDeducedMismatch;
}
/// \brief Deduce the template arguments by comparing the template parameter
@@ -224,32 +276,20 @@ DeduceTemplateArguments(ASTContext &Context,
assert(Arg.isCanonical() && "Argument type must be canonical");
// Check whether the template argument is a dependent template-id.
- // FIXME: This is untested code; it can be tested when we implement
- // partial ordering of class template partial specializations.
if (const TemplateSpecializationType *SpecArg
= dyn_cast<TemplateSpecializationType>(Arg)) {
// Perform template argument deduction for the template name.
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context,
+ = DeduceTemplateArguments(Context, TemplateParams,
Param->getTemplateName(),
SpecArg->getTemplateName(),
Info, Deduced))
return Result;
- unsigned NumArgs = Param->getNumArgs();
-
- // FIXME: When one of the template-names refers to a
- // declaration with default template arguments, do we need to
- // fill in those default template arguments here? Most likely,
- // the answer is "yes", but I don't see any references. This
- // issue may be resolved elsewhere, because we may want to
- // instantiate default template arguments when we actually write
- // the template-id.
- if (SpecArg->getNumArgs() != NumArgs)
- return Sema::TDK_NonDeducedMismatch;
// Perform template argument deduction on each template
// argument.
+ unsigned NumArgs = std::min(SpecArg->getNumArgs(), Param->getNumArgs());
for (unsigned I = 0; I != NumArgs; ++I)
if (Sema::TemplateDeductionResult Result
= DeduceTemplateArguments(Context, TemplateParams,
@@ -276,13 +316,12 @@ DeduceTemplateArguments(ASTContext &Context,
// Perform template argument deduction for the template name.
if (Sema::TemplateDeductionResult Result
= DeduceTemplateArguments(Context,
+ TemplateParams,
Param->getTemplateName(),
TemplateName(SpecArg->getSpecializedTemplate()),
Info, Deduced))
return Result;
- // FIXME: Can the # of arguments in the parameter and the argument
- // differ due to default arguments?
unsigned NumArgs = Param->getNumArgs();
const TemplateArgumentList &ArgArgs = SpecArg->getTemplateArgs();
if (NumArgs != ArgArgs.size())
@@ -315,8 +354,8 @@ static QualType getUnqualifiedArrayType(ASTContext &Context, QualType T,
Qualifiers &Quals) {
assert(T.isCanonical() && "Only operates on canonical types");
if (!isa<ArrayType>(T)) {
- Quals = T.getQualifiers();
- return T.getUnqualifiedType();
+ Quals = T.getLocalQualifiers();
+ return T.getLocalUnqualifiedType();
}
assert(!T.hasQualifiers() && "canonical array type has qualifiers!");
@@ -639,9 +678,9 @@ DeduceTemplateArguments(ASTContext &Context,
// template-name<T> (where template-name refers to a class template)
// template-name<i>
- // TT<T> (TODO)
- // TT<i> (TODO)
- // TT<> (TODO)
+ // TT<T>
+ // TT<i>
+ // TT<>
case Type::TemplateSpecialization: {
const TemplateSpecializationType *SpecParam
= cast<TemplateSpecializationType>(Param);
@@ -785,13 +824,28 @@ DeduceTemplateArguments(ASTContext &Context,
break;
case TemplateArgument::Type:
- assert(Arg.getKind() == TemplateArgument::Type && "Type/value mismatch");
- return DeduceTemplateArguments(Context, TemplateParams, Param.getAsType(),
- Arg.getAsType(), Info, Deduced, 0);
-
+ if (Arg.getKind() == TemplateArgument::Type)
+ return DeduceTemplateArguments(Context, TemplateParams, Param.getAsType(),
+ Arg.getAsType(), Info, Deduced, 0);
+ Info.FirstArg = Param;
+ Info.SecondArg = Arg;
+ return Sema::TDK_NonDeducedMismatch;
+
+ case TemplateArgument::Template:
+ if (Arg.getKind() == TemplateArgument::Template)
+ return DeduceTemplateArguments(Context, TemplateParams,
+ Param.getAsTemplate(),
+ Arg.getAsTemplate(), Info, Deduced);
+ Info.FirstArg = Param;
+ Info.SecondArg = Arg;
+ return Sema::TDK_NonDeducedMismatch;
+
case TemplateArgument::Declaration:
- // FIXME: Implement this check
- assert(false && "Unimplemented template argument deduction case");
+ if (Arg.getKind() == TemplateArgument::Declaration &&
+ Param.getAsDecl()->getCanonicalDecl() ==
+ Arg.getAsDecl()->getCanonicalDecl())
+ return Sema::TDK_Success;
+
Info.FirstArg = Param;
Info.SecondArg = Arg;
return Sema::TDK_NonDeducedMismatch;
@@ -829,7 +883,10 @@ DeduceTemplateArguments(ASTContext &Context,
if (Arg.getKind() == TemplateArgument::Expression)
return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsExpr(),
Info, Deduced);
-
+ if (Arg.getKind() == TemplateArgument::Declaration)
+ return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsDecl(),
+ Info, Deduced);
+
assert(false && "Type/value mismatch");
Info.FirstArg = Param;
Info.SecondArg = Arg;
@@ -885,13 +942,21 @@ static bool isSameTemplateArg(ASTContext &Context,
return X.getAsDecl()->getCanonicalDecl() ==
Y.getAsDecl()->getCanonicalDecl();
+ case TemplateArgument::Template:
+ return Context.getCanonicalTemplateName(X.getAsTemplate())
+ .getAsVoidPointer() ==
+ Context.getCanonicalTemplateName(Y.getAsTemplate())
+ .getAsVoidPointer();
+
case TemplateArgument::Integral:
return *X.getAsIntegral() == *Y.getAsIntegral();
- case TemplateArgument::Expression:
- // FIXME: We assume that all expressions are distinct, but we should
- // really check their canonical forms.
- return false;
+ case TemplateArgument::Expression: {
+ llvm::FoldingSetNodeID XID, YID;
+ X.getAsExpr()->Profile(XID, Context, true);
+ Y.getAsExpr()->Profile(YID, Context, true);
+ return XID == YID;
+ }
case TemplateArgument::Pack:
if (X.pack_size() != Y.pack_size())
@@ -1030,15 +1095,6 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
Info.FirstArg = Partial->getTemplateArgs()[I];
return TDK_SubstitutionFailure;
}
- } else if (TemplateTemplateParmDecl *TTP
- = dyn_cast<TemplateTemplateParmDecl>(Param)) {
- // FIXME: template template arguments should really resolve to decls
- DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InstExpr);
- if (!DRE || CheckTemplateArgument(TTP, DRE)) {
- Info.Param = makeTemplateParameter(Param);
- Info.FirstArg = Partial->getTemplateArgs()[I];
- return TDK_SubstitutionFailure;
- }
}
}
@@ -1384,16 +1440,16 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// - If A is a cv-qualified type, the top level cv-qualifiers of A’s
// type are ignored for type deduction.
QualType CanonArgType = Context.getCanonicalType(ArgType);
- if (CanonArgType.getCVRQualifiers())
- ArgType = CanonArgType.getUnqualifiedType();
+ if (CanonArgType.getLocalCVRQualifiers())
+ ArgType = CanonArgType.getLocalUnqualifiedType();
}
}
// C++0x [temp.deduct.call]p3:
// If P is a cv-qualified type, the top level cv-qualifiers of P’s type
// are ignored for type deduction.
- if (CanonParamType.getCVRQualifiers())
- ParamType = CanonParamType.getUnqualifiedType();
+ if (CanonParamType.getLocalCVRQualifiers())
+ ParamType = CanonParamType.getLocalUnqualifiedType();
if (const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>()) {
// [...] If P is a reference type, the type referred to by P is used
// for type deduction.
@@ -2074,6 +2130,7 @@ Sema::getMoreSpecializedPartialSpecialization(
0);
// Determine whether PS2 is at least as specialized as PS1
+ Deduced.clear();
Deduced.resize(PS1->getTemplateParameters()->size());
bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(Context,
PS1->getTemplateParameters(),
@@ -2153,6 +2210,9 @@ MarkUsedTemplateParameters(Sema &SemaRef,
return;
}
+ if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName())
+ MarkUsedTemplateParameters(SemaRef, QTN->getQualifier(), OnlyDeduced,
+ Depth, Used);
if (DependentTemplateName *DTN = Name.getAsDependentTemplateName())
MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced,
Depth, Used);
@@ -2309,6 +2369,7 @@ MarkUsedTemplateParameters(Sema &SemaRef,
switch (TemplateArg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::Integral:
+ case TemplateArgument::Declaration:
break;
case TemplateArgument::Type:
@@ -2316,12 +2377,9 @@ MarkUsedTemplateParameters(Sema &SemaRef,
Depth, Used);
break;
- case TemplateArgument::Declaration:
- if (TemplateTemplateParmDecl *TTP
- = dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl())) {
- if (TTP->getDepth() == Depth)
- Used[TTP->getIndex()] = true;
- }
+ case TemplateArgument::Template:
+ MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsTemplate(),
+ OnlyDeduced, Depth, Used);
break;
case TemplateArgument::Expression:
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index dfe37d8..58fe59e 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -28,11 +28,20 @@ using namespace clang;
/// \brief Retrieve the template argument list(s) that should be used to
/// instantiate the definition of the given declaration.
+///
+/// \param D the declaration for which we are computing template instantiation
+/// arguments.
+///
+/// \param Innermost if non-NULL, the innermost template argument list.
MultiLevelTemplateArgumentList
-Sema::getTemplateInstantiationArgs(NamedDecl *D) {
+Sema::getTemplateInstantiationArgs(NamedDecl *D,
+ const TemplateArgumentList *Innermost) {
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
+ if (Innermost)
+ Result.addOuterTemplateArguments(Innermost);
+
DeclContext *Ctx = dyn_cast<DeclContext>(D);
if (!Ctx)
Ctx = D->getDeclContext();
@@ -87,6 +96,23 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D) {
return Result;
}
+bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const {
+ switch (Kind) {
+ case TemplateInstantiation:
+ case DefaultTemplateArgumentInstantiation:
+ case DefaultFunctionArgumentInstantiation:
+ return true;
+
+ case ExplicitTemplateArgumentSubstitution:
+ case DeducedTemplateArgumentSubstitution:
+ case PriorTemplateArgumentSubstitution:
+ case DefaultTemplateArgumentChecking:
+ return false;
+ }
+
+ return true;
+}
+
Sema::InstantiatingTemplate::
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
Decl *Entity,
@@ -104,7 +130,6 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
Inst.NumTemplateArgs = 0;
Inst.InstantiationRange = InstantiationRange;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- Invalid = false;
}
}
@@ -128,7 +153,6 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
Inst.NumTemplateArgs = NumTemplateArgs;
Inst.InstantiationRange = InstantiationRange;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- Invalid = false;
}
}
@@ -152,7 +176,9 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
Inst.NumTemplateArgs = NumTemplateArgs;
Inst.InstantiationRange = InstantiationRange;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- Invalid = false;
+
+ if (!Inst.isInstantiationRecord())
+ ++SemaRef.NonInstantiationEntries;
}
}
@@ -164,48 +190,119 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
SourceRange InstantiationRange)
: SemaRef(SemaRef) {
- Invalid = CheckInstantiationDepth(PointOfInstantiation,
- InstantiationRange);
- if (!Invalid) {
- ActiveTemplateInstantiation Inst;
- Inst.Kind
- = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution;
- Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec);
- Inst.TemplateArgs = TemplateArgs;
- Inst.NumTemplateArgs = NumTemplateArgs;
- Inst.InstantiationRange = InstantiationRange;
- SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- Invalid = false;
- }
+ Invalid = false;
+
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec);
+ Inst.TemplateArgs = TemplateArgs;
+ Inst.NumTemplateArgs = NumTemplateArgs;
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+
+ assert(!Inst.isInstantiationRecord());
+ ++SemaRef.NonInstantiationEntries;
}
Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
- SourceLocation PointOfInstantation,
+ SourceLocation PointOfInstantiation,
ParmVarDecl *Param,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
SourceRange InstantiationRange)
: SemaRef(SemaRef) {
- Invalid = CheckInstantiationDepth(PointOfInstantation, InstantiationRange);
+ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
if (!Invalid) {
ActiveTemplateInstantiation Inst;
Inst.Kind
= ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation;
- Inst.PointOfInstantiation = PointOfInstantation;
+ Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Entity = reinterpret_cast<uintptr_t>(Param);
Inst.TemplateArgs = TemplateArgs;
Inst.NumTemplateArgs = NumTemplateArgs;
Inst.InstantiationRange = InstantiationRange;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- Invalid = false;
}
}
+Sema::InstantiatingTemplate::
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ TemplateDecl *Template,
+ NonTypeTemplateParmDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange) : SemaRef(SemaRef) {
+ Invalid = false;
+
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Template = Template;
+ Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.TemplateArgs = TemplateArgs;
+ Inst.NumTemplateArgs = NumTemplateArgs;
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+
+ assert(!Inst.isInstantiationRecord());
+ ++SemaRef.NonInstantiationEntries;
+}
+
+Sema::InstantiatingTemplate::
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ TemplateDecl *Template,
+ TemplateTemplateParmDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange) : SemaRef(SemaRef) {
+ Invalid = false;
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Template = Template;
+ Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.TemplateArgs = TemplateArgs;
+ Inst.NumTemplateArgs = NumTemplateArgs;
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+
+ assert(!Inst.isInstantiationRecord());
+ ++SemaRef.NonInstantiationEntries;
+}
+
+Sema::InstantiatingTemplate::
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ TemplateDecl *Template,
+ NamedDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange) : SemaRef(SemaRef) {
+ Invalid = false;
+
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind = ActiveTemplateInstantiation::DefaultTemplateArgumentChecking;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Template = Template;
+ Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.TemplateArgs = TemplateArgs;
+ Inst.NumTemplateArgs = NumTemplateArgs;
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+
+ assert(!Inst.isInstantiationRecord());
+ ++SemaRef.NonInstantiationEntries;
+}
+
void Sema::InstantiatingTemplate::Clear() {
if (!Invalid) {
+ if (!SemaRef.ActiveTemplateInstantiations.back().isInstantiationRecord()) {
+ assert(SemaRef.NonInstantiationEntries > 0);
+ --SemaRef.NonInstantiationEntries;
+ }
+
SemaRef.ActiveTemplateInstantiations.pop_back();
Invalid = true;
}
@@ -214,8 +311,11 @@ void Sema::InstantiatingTemplate::Clear() {
bool Sema::InstantiatingTemplate::CheckInstantiationDepth(
SourceLocation PointOfInstantiation,
SourceRange InstantiationRange) {
- if (SemaRef.ActiveTemplateInstantiations.size()
- <= SemaRef.getLangOptions().InstantiationDepth)
+ assert(SemaRef.NonInstantiationEntries <=
+ SemaRef.ActiveTemplateInstantiations.size());
+ if ((SemaRef.ActiveTemplateInstantiations.size() -
+ SemaRef.NonInstantiationEntries)
+ <= SemaRef.getLangOptions().InstantiationDepth)
return false;
SemaRef.Diag(PointOfInstantiation,
@@ -322,6 +422,34 @@ void Sema::PrintInstantiationStack() {
break;
}
+ case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution: {
+ NamedDecl *Parm = cast<NamedDecl>((Decl *)Active->Entity);
+ std::string Name;
+ if (!Parm->getName().empty())
+ Name = std::string(" '") + Parm->getName().str() + "'";
+
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ diag::note_prior_template_arg_substitution)
+ << isa<TemplateTemplateParmDecl>(Parm)
+ << Name
+ << getTemplateArgumentBindingsText(
+ Active->Template->getTemplateParameters(),
+ Active->TemplateArgs,
+ Active->NumTemplateArgs)
+ << Active->InstantiationRange;
+ break;
+ }
+
+ case ActiveTemplateInstantiation::DefaultTemplateArgumentChecking: {
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ diag::note_template_default_arg_checking)
+ << getTemplateArgumentBindingsText(
+ Active->Template->getTemplateParameters(),
+ Active->TemplateArgs,
+ Active->NumTemplateArgs)
+ << Active->InstantiationRange;
+ break;
+ }
}
}
}
@@ -332,18 +460,20 @@ bool Sema::isSFINAEContext() const {
Active = ActiveTemplateInstantiations.rbegin(),
ActiveEnd = ActiveTemplateInstantiations.rend();
Active != ActiveEnd;
- ++Active) {
-
+ ++Active)
+ {
switch(Active->Kind) {
case ActiveTemplateInstantiation::TemplateInstantiation:
case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation:
-
// This is a template instantiation, so there is no SFINAE.
return false;
case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation:
- // A default template argument instantiation may or may not be a
- // SFINAE context; look further up the stack.
+ case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution:
+ case ActiveTemplateInstantiation::DefaultTemplateArgumentChecking:
+ // A default template argument instantiation and substitution into
+ // template parameters with arguments for prior parameters may or may
+ // not be a SFINAE context; look further up the stack.
break;
case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution:
@@ -427,6 +557,9 @@ namespace {
Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E,
bool isAddressOfOperand);
+ Sema::OwningExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E,
+ bool isAddressOfOperand);
+
/// \brief Transforms a template type parameter type by performing
/// substitution of the corresponding template type argument.
QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
@@ -440,10 +573,11 @@ Decl *TemplateInstantiator::TransformDecl(Decl *D) {
if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
- assert(TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsDecl() &&
+ TemplateName Template
+ = TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsTemplate();
+ assert(!Template.isNull() && Template.getAsTemplateDecl() &&
"Wrong kind of template template argument");
- return cast<TemplateDecl>(TemplateArgs(TTP->getDepth(),
- TTP->getPosition()).getAsDecl());
+ return Template.getAsTemplateDecl();
}
// If the corresponding template argument is NULL or non-existent, it's
@@ -454,9 +588,8 @@ Decl *TemplateInstantiator::TransformDecl(Decl *D) {
TTP->getPosition()))
return D;
- // FIXME: Implement depth reduction of template template parameters
- assert(false &&
- "Reducing depth of template template parameters is not yet implemented");
+ // Fall through to find the instantiated declaration for this template
+ // template parameter.
}
return SemaRef.FindInstantiatedDecl(cast<NamedDecl>(D), TemplateArgs);
@@ -567,7 +700,6 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E,
NamedDecl *D = E->getDecl();
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
if (NTTP->getDepth() < TemplateArgs.getNumLevels()) {
-
// If the corresponding template argument is NULL or non-existent, it's
// because we are performing instantiation from explicitly-specified
// template arguments in a function template, but there were some
@@ -592,7 +724,38 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E,
if (!VD)
return SemaRef.ExprError();
- return SemaRef.BuildDeclRefExpr(VD, VD->getType(), E->getLocation(),
+ if (VD->getDeclContext()->isRecord()) {
+ // If the value is a class member, we might have a pointer-to-member.
+ // Determine whether the non-type template template parameter is of
+ // pointer-to-member type. If so, we need to build an appropriate
+ // expression for a pointer-to-member, since a "normal" DeclRefExpr
+ // would refer to the member itself.
+ if (NTTP->getType()->isMemberPointerType()) {
+ QualType ClassType
+ = SemaRef.Context.getTypeDeclType(
+ cast<RecordDecl>(VD->getDeclContext()));
+ NestedNameSpecifier *Qualifier
+ = NestedNameSpecifier::Create(SemaRef.Context, 0, false,
+ ClassType.getTypePtr());
+ CXXScopeSpec SS;
+ SS.setScopeRep(Qualifier);
+ OwningExprResult RefExpr
+ = SemaRef.BuildDeclRefExpr(VD,
+ VD->getType().getNonReferenceType(),
+ E->getLocation(),
+ /*FIXME:*/false, /*FIXME:*/false,
+ &SS);
+ if (RefExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ return SemaRef.CreateBuiltinUnaryOp(E->getLocation(),
+ UnaryOperator::AddrOf,
+ move(RefExpr));
+ }
+ }
+
+ return SemaRef.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(),
+ E->getLocation(),
/*FIXME:*/false, /*FIXME:*/false);
}
@@ -625,10 +788,46 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E,
if (!InstD)
return SemaRef.ExprError();
- // If we instantiated an UnresolvedUsingDecl and got back an UsingDecl,
- // we need to get the underlying decl.
- // FIXME: Is this correct? Maybe FindInstantiatedDecl should do this?
- InstD = InstD->getUnderlyingDecl();
+ // Flatten using declarations into their shadow declarations.
+ if (isa<UsingDecl>(InstD)) {
+ UsingDecl *UD = cast<UsingDecl>(InstD);
+
+ bool HasNonFunction = false;
+
+ llvm::SmallVector<NamedDecl*, 8> Decls;
+ for (UsingDecl::shadow_iterator I = UD->shadow_begin(),
+ E = UD->shadow_end(); I != E; ++I) {
+ NamedDecl *TD = (*I)->getTargetDecl();
+ if (!TD->isFunctionOrFunctionTemplate())
+ HasNonFunction = true;
+
+ Decls.push_back(TD);
+ }
+
+ if (Decls.empty())
+ return SemaRef.ExprError();
+
+ if (Decls.size() == 1)
+ InstD = Decls[0];
+ else if (!HasNonFunction) {
+ OverloadedFunctionDecl *OFD
+ = OverloadedFunctionDecl::Create(SemaRef.Context,
+ UD->getDeclContext(),
+ UD->getDeclName());
+ for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Decls.begin(),
+ E = Decls.end(); I != E; ++I)
+ if (isa<FunctionDecl>(*I))
+ OFD->addOverload(cast<FunctionDecl>(*I));
+ else
+ OFD->addOverload(cast<FunctionTemplateDecl>(*I));
+
+ InstD = OFD;
+ } else {
+ // FIXME
+ assert(false && "using declaration resolved to mixed set");
+ return SemaRef.ExprError();
+ }
+ }
CXXScopeSpec SS;
NestedNameSpecifier *Qualifier = 0;
@@ -648,6 +847,15 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E,
isAddressOfOperand);
}
+Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr(
+ CXXDefaultArgExpr *E, bool isAddressOfOperand) {
+ assert(!cast<FunctionDecl>(E->getParam()->getDeclContext())->
+ getDescribedFunctionTemplate() &&
+ "Default arg expressions are never formed in dependent cases.");
+ return SemaRef.Owned(E->Retain());
+}
+
+
QualType
TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
TemplateTypeParmTypeLoc TL) {
@@ -889,9 +1097,9 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Member != MemberEnd; ++Member) {
Decl *NewMember = SubstDecl(*Member, Instantiation, TemplateArgs);
if (NewMember) {
- if (NewMember->isInvalidDecl())
+ if (NewMember->isInvalidDecl()) {
Invalid = true;
- else if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
+ } else if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
Fields.push_back(DeclPtrTy::make(Field));
else if (UsingDecl *UD = dyn_cast<UsingDecl>(NewMember))
Instantiation->addDecl(UD);
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 7288ae2..7e618cd 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===/
#include "Sema.h"
+#include "Lookup.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
@@ -28,6 +29,8 @@ namespace {
DeclContext *Owner;
const MultiLevelTemplateArgumentList &TemplateArgs;
+ void InstantiateAttrs(Decl *Tmpl, Decl *New);
+
public:
typedef Sema::OwningExprResult OwningExprResult;
@@ -62,11 +65,19 @@ namespace {
Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
- Decl *VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D);
+ Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+ Decl *VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
+ Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
+ Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
// Base case. FIXME: Remove once we can instantiate everything.
- Decl *VisitDecl(Decl *) {
- assert(false && "Template instantiation of unknown declaration kind!");
+ Decl *VisitDecl(Decl *D) {
+ unsigned DiagID = SemaRef.getDiagnostics().getCustomDiagID(
+ Diagnostic::Error,
+ "cannot instantiate %0 yet");
+ SemaRef.Diag(D->getLocation(), DiagID)
+ << D->getDeclKindName();
+
return 0;
}
@@ -89,6 +100,18 @@ namespace {
};
}
+// FIXME: Is this too simple?
+void TemplateDeclInstantiator::InstantiateAttrs(Decl *Tmpl, Decl *New) {
+ for (const Attr *TmplAttr = Tmpl->getAttrs(); TmplAttr;
+ TmplAttr = TmplAttr->getNext()) {
+
+ // FIXME: Is cloning correct for all attributes?
+ Attr *NewAttr = TmplAttr->clone(SemaRef.Context);
+
+ New->addAttr(NewAttr);
+ }
+}
+
Decl *
TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
assert(false && "Translation units cannot be instantiated");
@@ -172,6 +195,15 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
= SemaRef.SubstExpr(D->getInit(), TemplateArgs);
if (Init.isInvalid())
Var->setInvalidDecl();
+ else if (!D->getType()->isDependentType() &&
+ !D->getInit()->isTypeDependent() &&
+ !D->getInit()->isValueDependent()) {
+ // If neither the declaration's type nor its initializer are dependent,
+ // we don't want to redo all the checking, especially since the
+ // initializer might have been wrapped by a CXXConstructExpr since we did
+ // it the first time.
+ Var->setInit(SemaRef.Context, Init.takeAs<Expr>());
+ }
else if (ParenListExpr *PLE = dyn_cast<ParenListExpr>((Expr *)Init.get())) {
// FIXME: We're faking all of the comma locations, which is suboptimal.
// Do we even need these comma locations?
@@ -258,6 +290,8 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
return 0;
}
+ InstantiateAttrs(D, Field);
+
if (Invalid)
Field->setInvalidDecl();
@@ -632,6 +666,12 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
TemplateParams, Function);
Function->setDescribedFunctionTemplate(FunctionTemplate);
FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
+ } else if (FunctionTemplate) {
+ // Record this function template specialization.
+ Function->setFunctionTemplateSpecialization(SemaRef.Context,
+ FunctionTemplate,
+ &TemplateArgs.getInnermost(),
+ InsertPos);
}
if (InitFunctionInstantiation(Function, D))
@@ -645,9 +685,10 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
// Look only into the namespace where the friend would be declared to
// find a previous declaration. This is the innermost enclosing namespace,
// as described in ActOnFriendFunctionDecl.
- Sema::LookupResult R;
- SemaRef.LookupQualifiedName(R, DC, Function->getDeclName(),
- Sema::LookupOrdinaryName, true);
+ LookupResult R(SemaRef, Function->getDeclName(), SourceLocation(),
+ Sema::LookupOrdinaryName,
+ Sema::ForRedeclaration);
+ SemaRef.LookupQualifiedName(R, DC);
PrevDecl = R.getAsSingleDecl(SemaRef.Context);
@@ -683,14 +724,6 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
}
- if (FunctionTemplate && !TemplateParams) {
- // Record this function template specialization.
- Function->setFunctionTemplateSpecialization(SemaRef.Context,
- FunctionTemplate,
- &TemplateArgs.getInnermost(),
- InsertPos);
- }
-
return Function;
}
@@ -785,9 +818,17 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
if (D->isOutOfLine())
FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
Method->setDescribedFunctionTemplate(FunctionTemplate);
- } else if (!FunctionTemplate)
+ } else if (FunctionTemplate) {
+ // Record this function template specialization.
+ Method->setFunctionTemplateSpecialization(SemaRef.Context,
+ FunctionTemplate,
+ &TemplateArgs.getInnermost(),
+ InsertPos);
+ } else {
+ // Record that this is an instantiation of a member function.
Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
-
+ }
+
// If we are instantiating a member function defined
// out-of-line, the instantiation will have the same lexical
// context (which will be a namespace scope) as the template.
@@ -805,8 +846,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
NamedDecl *PrevDecl = 0;
if (!FunctionTemplate || TemplateParams) {
- Sema::LookupResult R;
- SemaRef.LookupQualifiedName(R, Owner, Name, Sema::LookupOrdinaryName, true);
+ LookupResult R(SemaRef, Name, SourceLocation(),
+ Sema::LookupOrdinaryName,
+ Sema::ForRedeclaration);
+ SemaRef.LookupQualifiedName(R, Owner);
PrevDecl = R.getAsSingleDecl(SemaRef.Context);
// In C++, the previous declaration we find might be a tag type
@@ -817,13 +860,6 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
PrevDecl = 0;
}
- if (FunctionTemplate && !TemplateParams)
- // Record this function template specialization.
- Method->setFunctionTemplateSpecialization(SemaRef.Context,
- FunctionTemplate,
- &TemplateArgs.getInnermost(),
- InsertPos);
-
bool Redeclaration = false;
bool OverloadableAttrRequired = false;
SemaRef.CheckFunctionDeclaration(Method, PrevDecl, false, Redeclaration,
@@ -898,18 +934,8 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
D->wasDeclaredWithTypename(),
D->isParameterPack());
- // FIXME: Do we actually want to perform substitution here? I don't think
- // we do.
- if (D->hasDefaultArgument()) {
- DeclaratorInfo *DefaultPattern = D->getDefaultArgumentInfo();
- DeclaratorInfo *DefaultInst
- = SemaRef.SubstType(DefaultPattern, TemplateArgs,
- D->getDefaultArgumentLoc(),
- D->getDeclName());
-
- Inst->setDefaultArgument(DefaultInst,
- D->defaultArgumentWasInherited() /* preserve? */);
- }
+ if (D->hasDefaultArgument())
+ Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false);
// Introduce this template parameter's instantiation into the instantiation
// scope.
@@ -959,7 +985,75 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
}
Decl *
-TemplateDeclInstantiator::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) {
+TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
+ TemplateTemplateParmDecl *D) {
+ // Instantiate the template parameter list of the template template parameter.
+ TemplateParameterList *TempParams = D->getTemplateParameters();
+ TemplateParameterList *InstParams;
+ {
+ // Perform the actual substitution of template parameters within a new,
+ // local instantiation scope.
+ Sema::LocalInstantiationScope Scope(SemaRef);
+ InstParams = SubstTemplateParams(TempParams);
+ if (!InstParams)
+ return NULL;
+ }
+
+ // Build the template template parameter.
+ TemplateTemplateParmDecl *Param
+ = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ D->getDepth() - 1, D->getPosition(),
+ D->getIdentifier(), InstParams);
+ Param->setDefaultArgument(D->getDefaultArgument());
+
+ // Introduce this template parameter's instantiation into the instantiation
+ // scope.
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param);
+
+ return Param;
+}
+
+Decl *TemplateDeclInstantiator::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
+ // Using directives are never dependent, so they require no explicit
+
+ UsingDirectiveDecl *Inst
+ = UsingDirectiveDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ D->getNamespaceKeyLocation(),
+ D->getQualifierRange(), D->getQualifier(),
+ D->getIdentLocation(),
+ D->getNominatedNamespace(),
+ D->getCommonAncestor());
+ Owner->addDecl(Inst);
+ return Inst;
+}
+
+Decl * TemplateDeclInstantiator
+ ::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
+ NestedNameSpecifier *NNS =
+ SemaRef.SubstNestedNameSpecifier(D->getTargetNestedNameSpecifier(),
+ D->getTargetNestedNameRange(),
+ TemplateArgs);
+ if (!NNS)
+ return 0;
+
+ CXXScopeSpec SS;
+ SS.setRange(D->getTargetNestedNameRange());
+ SS.setScopeRep(NNS);
+
+ NamedDecl *UD =
+ SemaRef.BuildUsingDeclaration(/*Scope*/ 0, D->getAccess(),
+ D->getUsingLoc(), SS, D->getLocation(),
+ D->getDeclName(), 0,
+ /*instantiation*/ true,
+ /*typename*/ true, D->getTypenameLoc());
+ if (UD)
+ SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast<UsingDecl>(UD),
+ D);
+ return UD;
+}
+
+Decl * TemplateDeclInstantiator
+ ::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
NestedNameSpecifier *NNS =
SemaRef.SubstNestedNameSpecifier(D->getTargetNestedNameSpecifier(),
D->getTargetNestedNameRange(),
@@ -972,9 +1066,11 @@ TemplateDeclInstantiator::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) {
SS.setScopeRep(NNS);
NamedDecl *UD =
- SemaRef.BuildUsingDeclaration(D->getLocation(), SS,
- D->getTargetNameLocation(),
- D->getTargetName(), 0, D->isTypeName());
+ SemaRef.BuildUsingDeclaration(/*Scope*/ 0, D->getAccess(),
+ D->getUsingLoc(), SS, D->getLocation(),
+ D->getDeclName(), 0,
+ /*instantiation*/ true,
+ /*typename*/ false, SourceLocation());
if (UD)
SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast<UsingDecl>(UD),
D);
@@ -1006,7 +1102,7 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
PI != PE; ++PI) {
NamedDecl *D = cast_or_null<NamedDecl>(Visit(*PI));
Params.push_back(D);
- Invalid = Invalid || !D;
+ Invalid = Invalid || !D || D->isInvalidDecl();
}
// Clean up if we had an error.
@@ -1240,6 +1336,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
(void) FunTmpl;
ActiveInst.Kind = ActiveInstType::TemplateInstantiation;
ActiveInst.Entity = reinterpret_cast<uintptr_t>(New);
+ --SemaRef.NonInstantiationEntries;
}
}
@@ -1656,7 +1753,13 @@ static bool isInstantiationOf(EnumDecl *Pattern,
return false;
}
-static bool isInstantiationOf(UnresolvedUsingDecl *Pattern,
+static bool isInstantiationOf(UnresolvedUsingValueDecl *Pattern,
+ UsingDecl *Instance,
+ ASTContext &C) {
+ return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern;
+}
+
+static bool isInstantiationOf(UnresolvedUsingTypenameDecl *Pattern,
UsingDecl *Instance,
ASTContext &C) {
return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern;
@@ -1679,7 +1782,15 @@ static bool isInstantiationOfStaticDataMember(VarDecl *Pattern,
static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
if (D->getKind() != Other->getKind()) {
- if (UnresolvedUsingDecl *UUD = dyn_cast<UnresolvedUsingDecl>(D)) {
+ if (UnresolvedUsingTypenameDecl *UUD
+ = dyn_cast<UnresolvedUsingTypenameDecl>(D)) {
+ if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) {
+ return isInstantiationOf(UUD, UD, Ctx);
+ }
+ }
+
+ if (UnresolvedUsingValueDecl *UUD
+ = dyn_cast<UnresolvedUsingValueDecl>(D)) {
if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) {
return isInstantiationOf(UUD, UD, Ctx);
}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index f003127..00dc809 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -229,7 +229,8 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){
case DeclSpec::TST_enum:
case DeclSpec::TST_union:
case DeclSpec::TST_struct: {
- TypeDecl *D = cast_or_null<TypeDecl>(static_cast<Decl *>(DS.getTypeRep()));
+ TypeDecl *D
+ = dyn_cast_or_null<TypeDecl>(static_cast<Decl *>(DS.getTypeRep()));
if (!D) {
// This can happen in C++ with ambiguous lookups.
Result = Context.IntTy;
@@ -1703,7 +1704,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
// class template specialization, or an array with known size of such,
// try to instantiate it.
QualType MaybeTemplate = T;
- if (const ConstantArrayType *Array = T->getAs<ConstantArrayType>())
+ if (const ConstantArrayType *Array = Context.getAsConstantArrayType(T))
MaybeTemplate = Array->getElementType();
if (const RecordType *Record = MaybeTemplate->getAs<RecordType>()) {
if (ClassTemplateSpecializationDecl *ClassTemplateSpec
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 767725a..2bee32a 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1063,8 +1063,18 @@ public:
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildInitList(SourceLocation LBraceLoc,
MultiExprArg Inits,
- SourceLocation RBraceLoc) {
- return SemaRef.ActOnInitList(LBraceLoc, move(Inits), RBraceLoc);
+ SourceLocation RBraceLoc,
+ QualType ResultTy) {
+ OwningExprResult Result
+ = SemaRef.ActOnInitList(LBraceLoc, move(Inits), RBraceLoc);
+ if (Result.isInvalid() || ResultTy->isDependentType())
+ return move(Result);
+
+ // Patch in the result type we were given, which may have been computed
+ // when the initial InitListExpr was built.
+ InitListExpr *ILE = cast<InitListExpr>((Expr *)Result.get());
+ ILE->setType(ResultTy);
+ return move(Result);
}
/// \brief Build a new designated initializer expression.
@@ -1699,7 +1709,7 @@ Sema::OwningStmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) {
if (E.isInvalid())
return getSema().StmtError();
- return getSema().Owned(E.takeAs<Stmt>());
+ return getSema().ActOnExprStmt(getSema().FullExpr(E));
}
}
@@ -1947,6 +1957,10 @@ void TreeTransform<Derived>::InventTemplateArgumentLoc(
break;
+ case TemplateArgument::Template:
+ Output = TemplateArgumentLoc(Arg, SourceRange(), Loc);
+ break;
+
case TemplateArgument::Expression:
Output = TemplateArgumentLoc(Arg, Arg.getAsExpr());
break;
@@ -1987,7 +2001,7 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
DeclarationName Name;
if (NamedDecl *ND = dyn_cast<NamedDecl>(Arg.getAsDecl()))
Name = ND->getDeclName();
- TemporaryBase Rebase(*this, SourceLocation(), Name);
+ TemporaryBase Rebase(*this, Input.getLocation(), Name);
Decl *D = getDerived().TransformDecl(Arg.getAsDecl());
if (!D) return true;
@@ -2008,6 +2022,19 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
return false;
}
+ case TemplateArgument::Template: {
+ TemporaryBase Rebase(*this, Input.getLocation(), DeclarationName());
+ TemplateName Template
+ = getDerived().TransformTemplateName(Arg.getAsTemplate());
+ if (Template.isNull())
+ return true;
+
+ Output = TemplateArgumentLoc(TemplateArgument(Template),
+ Input.getTemplateQualifierRange(),
+ Input.getTemplateNameLoc());
+ return false;
+ }
+
case TemplateArgument::Expression: {
// Template argument expressions are not potentially evaluated.
EnterExpressionEvaluationContext Unevaluated(getSema(),
@@ -2119,7 +2146,7 @@ template<typename Derived>
QualType
TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
QualifiedTypeLoc T) {
- Qualifiers Quals = T.getType().getQualifiers();
+ Qualifiers Quals = T.getType().getLocalQualifiers();
QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc());
if (Result.isNull())
@@ -3893,7 +3920,7 @@ TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E,
return SemaRef.Owned(E->Retain());
return getDerived().RebuildInitList(E->getLBraceLoc(), move_arg(Inits),
- E->getRBraceLoc());
+ E->getRBraceLoc(), E->getType());
}
template<typename Derived>
@@ -5279,7 +5306,7 @@ TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
QualType T) {
if (T->isDependentType() || T->isRecordType() ||
(SemaRef.getLangOptions().CPlusPlus0x && T->isEnumeralType())) {
- assert(!T.hasQualifiers() && "Can't get cv-qualifiers here");
+ assert(!T.hasLocalQualifiers() && "Can't get cv-qualifiers here");
return NestedNameSpecifier::Create(SemaRef.Context, Prefix, TemplateKW,
T.getTypePtr());
}
@@ -5363,6 +5390,9 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
return getSema().CreateBuiltinArraySubscriptExpr(move(First),
DRE->getLocStart(),
move(Second), OpLoc);
+ } else if (Op == OO_Arrow) {
+ // -> is never a builtin operation.
+ return SemaRef.BuildOverloadedArrowExpr(0, move(First), OpLoc);
} else if (SecondExpr == 0 || isPostIncDec) {
if (!FirstExpr->getType()->isOverloadableType()) {
// The argument is not of overloadable type, so try to create a
OpenPOWER on IntegriCloud