aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRoman Divacky <rdivacky@FreeBSD.org>2010-02-16 09:31:36 +0000
committerRoman Divacky <rdivacky@FreeBSD.org>2010-02-16 09:31:36 +0000
commitecb7e5c8afe929ee38155db94de6b084ec32a645 (patch)
tree53010172e19c77ea447bcd89e117cda052ab52e0 /lib
parent5044f5c816adfd5cba17f1adee1a10127296d0bf (diff)
downloadsrc-ecb7e5c8afe929ee38155db94de6b084ec32a645.tar.gz
src-ecb7e5c8afe929ee38155db94de6b084ec32a645.zip
Update clang to r96341.
Notes
Notes: svn path=/vendor/clang/dist/; revision=203955
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/ASTContext.cpp247
-rw-r--r--lib/AST/ASTDiagnostic.cpp266
-rw-r--r--lib/AST/ASTImporter.cpp2394
-rw-r--r--lib/AST/AttrImpl.cpp65
-rw-r--r--lib/AST/CMakeLists.txt2
-rw-r--r--lib/AST/CXXInheritance.cpp14
-rw-r--r--lib/AST/Decl.cpp734
-rw-r--r--lib/AST/DeclBase.cpp35
-rw-r--r--lib/AST/DeclCXX.cpp123
-rw-r--r--lib/AST/DeclObjC.cpp14
-rw-r--r--lib/AST/DeclPrinter.cpp62
-rw-r--r--lib/AST/DeclTemplate.cpp3
-rw-r--r--lib/AST/DeclarationName.cpp47
-rw-r--r--lib/AST/Expr.cpp134
-rw-r--r--lib/AST/ExprCXX.cpp100
-rw-r--r--lib/AST/ExprConstant.cpp39
-rw-r--r--lib/AST/Makefile1
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp9
-rw-r--r--lib/AST/Stmt.cpp148
-rw-r--r--lib/AST/StmtDumper.cpp2
-rw-r--r--lib/AST/StmtPrinter.cpp4
-rw-r--r--lib/AST/StmtProfile.cpp4
-rw-r--r--lib/AST/Type.cpp154
-rw-r--r--lib/AST/TypePrinter.cpp40
-rw-r--r--lib/Analysis/AnalysisContext.cpp48
-rw-r--r--lib/Analysis/CMakeLists.txt59
-rw-r--r--lib/Analysis/LiveVariables.cpp2
-rw-r--r--lib/Analysis/Makefile1
-rw-r--r--lib/Analysis/PrintfFormatString.cpp436
-rw-r--r--lib/Analysis/ReturnStackAddressChecker.cpp114
-rw-r--r--lib/Analysis/UninitializedValues.cpp1
-rw-r--r--lib/Basic/Diagnostic.cpp219
-rw-r--r--lib/Basic/IdentifierTable.cpp4
-rw-r--r--lib/Basic/Makefile1
-rw-r--r--lib/Basic/SourceManager.cpp10
-rw-r--r--lib/Basic/TargetInfo.cpp39
-rw-r--r--lib/Basic/Targets.cpp157
-rw-r--r--lib/Basic/Version.cpp78
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/Checker/AdjustedReturnValueChecker.cpp98
-rw-r--r--lib/Checker/ArrayBoundChecker.cpp (renamed from lib/Analysis/ArrayBoundChecker.cpp)6
-rw-r--r--lib/Checker/AttrNonNullChecker.cpp (renamed from lib/Analysis/AttrNonNullChecker.cpp)4
-rw-r--r--lib/Checker/BasicConstraintManager.cpp (renamed from lib/Analysis/BasicConstraintManager.cpp)6
-rw-r--r--lib/Checker/BasicObjCFoundationChecks.cpp (renamed from lib/Analysis/BasicObjCFoundationChecks.cpp)89
-rw-r--r--lib/Checker/BasicObjCFoundationChecks.h (renamed from lib/Analysis/BasicObjCFoundationChecks.h)0
-rw-r--r--lib/Checker/BasicStore.cpp (renamed from lib/Analysis/BasicStore.cpp)215
-rw-r--r--lib/Checker/BasicValueFactory.cpp (renamed from lib/Analysis/BasicValueFactory.cpp)13
-rw-r--r--lib/Checker/BugReporter.cpp (renamed from lib/Analysis/BugReporter.cpp)6
-rw-r--r--lib/Checker/BugReporterVisitors.cpp (renamed from lib/Analysis/BugReporterVisitors.cpp)26
-rw-r--r--lib/Checker/BuiltinFunctionChecker.cpp (renamed from lib/Analysis/BuiltinFunctionChecker.cpp)2
-rw-r--r--lib/Checker/CFRefCount.cpp (renamed from lib/Analysis/CFRefCount.cpp)463
-rw-r--r--lib/Checker/CMakeLists.txt67
-rw-r--r--lib/Checker/CallAndMessageChecker.cpp (renamed from lib/Analysis/CallAndMessageChecker.cpp)4
-rw-r--r--lib/Checker/CallInliner.cpp (renamed from lib/Analysis/CallInliner.cpp)6
-rw-r--r--lib/Checker/CastToStructChecker.cpp (renamed from lib/Analysis/CastToStructChecker.cpp)2
-rw-r--r--lib/Checker/CheckDeadStores.cpp (renamed from lib/Analysis/CheckDeadStores.cpp)6
-rw-r--r--lib/Checker/CheckObjCDealloc.cpp (renamed from lib/Analysis/CheckObjCDealloc.cpp)6
-rw-r--r--lib/Checker/CheckObjCInstMethSignature.cpp (renamed from lib/Analysis/CheckObjCInstMethSignature.cpp)6
-rw-r--r--lib/Checker/CheckObjCUnusedIVars.cpp (renamed from lib/Analysis/CheckObjCUnusedIVars.cpp)6
-rw-r--r--lib/Checker/CheckSecuritySyntaxOnly.cpp (renamed from lib/Analysis/CheckSecuritySyntaxOnly.cpp)4
-rw-r--r--lib/Checker/CheckSizeofPointer.cpp (renamed from lib/Analysis/CheckSizeofPointer.cpp)4
-rw-r--r--lib/Checker/Checker.cpp (renamed from lib/Analysis/Checker.cpp)2
-rw-r--r--lib/Checker/CocoaConventions.cpp195
-rw-r--r--lib/Checker/DereferenceChecker.cpp (renamed from lib/Analysis/DereferenceChecker.cpp)8
-rw-r--r--lib/Checker/DivZeroChecker.cpp (renamed from lib/Analysis/DivZeroChecker.cpp)2
-rw-r--r--lib/Checker/Environment.cpp (renamed from lib/Analysis/Environment.cpp)2
-rw-r--r--lib/Checker/ExplodedGraph.cpp (renamed from lib/Analysis/ExplodedGraph.cpp)4
-rw-r--r--lib/Checker/FixedAddressChecker.cpp (renamed from lib/Analysis/FixedAddressChecker.cpp)2
-rw-r--r--lib/Checker/FlatStore.cpp166
-rw-r--r--lib/Checker/GRBlockCounter.cpp (renamed from lib/Analysis/GRBlockCounter.cpp)2
-rw-r--r--lib/Checker/GRCoreEngine.cpp (renamed from lib/Analysis/GRCoreEngine.cpp)4
-rw-r--r--lib/Checker/GRExprEngine.cpp (renamed from lib/Analysis/GRExprEngine.cpp)439
-rw-r--r--lib/Checker/GRExprEngineExperimentalChecks.cpp (renamed from lib/Analysis/GRExprEngineExperimentalChecks.cpp)2
-rw-r--r--lib/Checker/GRExprEngineExperimentalChecks.h (renamed from lib/Analysis/GRExprEngineExperimentalChecks.h)0
-rw-r--r--lib/Checker/GRExprEngineInternalChecks.h (renamed from lib/Analysis/GRExprEngineInternalChecks.h)3
-rw-r--r--lib/Checker/GRState.cpp (renamed from lib/Analysis/GRState.cpp)12
-rw-r--r--lib/Checker/LLVMConventionsChecker.cpp335
-rw-r--r--lib/Checker/Makefile21
-rw-r--r--lib/Checker/MallocChecker.cpp (renamed from lib/Analysis/MallocChecker.cpp)13
-rw-r--r--lib/Checker/ManagerRegistry.cpp (renamed from lib/Analysis/ManagerRegistry.cpp)2
-rw-r--r--lib/Checker/MemRegion.cpp (renamed from lib/Analysis/MemRegion.cpp)11
-rw-r--r--lib/Checker/NSAutoreleasePoolChecker.cpp (renamed from lib/Analysis/NSAutoreleasePoolChecker.cpp)6
-rw-r--r--lib/Checker/NSErrorChecker.cpp (renamed from lib/Analysis/NSErrorChecker.cpp)8
-rw-r--r--lib/Checker/NoReturnFunctionChecker.cpp (renamed from lib/Analysis/NoReturnFunctionChecker.cpp)2
-rw-r--r--lib/Checker/OSAtomicChecker.cpp (renamed from lib/Analysis/OSAtomicChecker.cpp)5
-rw-r--r--lib/Checker/PathDiagnostic.cpp (renamed from lib/Analysis/PathDiagnostic.cpp)2
-rw-r--r--lib/Checker/PointerArithChecker.cpp (renamed from lib/Analysis/PointerArithChecker.cpp)2
-rw-r--r--lib/Checker/PointerSubChecker.cpp (renamed from lib/Analysis/PointerSubChecker.cpp)2
-rw-r--r--lib/Checker/PthreadLockChecker.cpp (renamed from lib/Analysis/PthreadLockChecker.cpp)6
-rw-r--r--lib/Checker/RangeConstraintManager.cpp (renamed from lib/Analysis/RangeConstraintManager.cpp)8
-rw-r--r--lib/Checker/RegionStore.cpp (renamed from lib/Analysis/RegionStore.cpp)1052
-rw-r--r--lib/Checker/ReturnPointerRangeChecker.cpp (renamed from lib/Analysis/ReturnPointerRangeChecker.cpp)6
-rw-r--r--lib/Checker/ReturnStackAddressChecker.cpp125
-rw-r--r--lib/Checker/ReturnUndefChecker.cpp (renamed from lib/Analysis/ReturnUndefChecker.cpp)6
-rw-r--r--lib/Checker/SVals.cpp (renamed from lib/Analysis/SVals.cpp)8
-rw-r--r--lib/Checker/SValuator.cpp (renamed from lib/Analysis/SValuator.cpp)49
-rw-r--r--lib/Checker/SimpleConstraintManager.cpp (renamed from lib/Analysis/SimpleConstraintManager.cpp)6
-rw-r--r--lib/Checker/SimpleConstraintManager.h (renamed from lib/Analysis/SimpleConstraintManager.h)4
-rw-r--r--lib/Checker/SimpleSValuator.cpp (renamed from lib/Analysis/SimpleSValuator.cpp)6
-rw-r--r--lib/Checker/Store.cpp (renamed from lib/Analysis/Store.cpp)121
-rw-r--r--lib/Checker/SymbolManager.cpp (renamed from lib/Analysis/SymbolManager.cpp)4
-rw-r--r--lib/Checker/UndefBranchChecker.cpp (renamed from lib/Analysis/UndefBranchChecker.cpp)2
-rw-r--r--lib/Checker/UndefCapturedBlockVarChecker.cpp101
-rw-r--r--lib/Checker/UndefResultChecker.cpp (renamed from lib/Analysis/UndefResultChecker.cpp)6
-rw-r--r--lib/Checker/UndefinedArraySubscriptChecker.cpp (renamed from lib/Analysis/UndefinedArraySubscriptChecker.cpp)4
-rw-r--r--lib/Checker/UndefinedAssignmentChecker.cpp (renamed from lib/Analysis/UndefinedAssignmentChecker.cpp)4
-rw-r--r--lib/Checker/VLASizeChecker.cpp (renamed from lib/Analysis/VLASizeChecker.cpp)6
-rw-r--r--lib/Checker/ValueManager.cpp (renamed from lib/Analysis/ValueManager.cpp)4
-rw-r--r--lib/CodeGen/CGBlocks.cpp74
-rw-r--r--lib/CodeGen/CGBlocks.h5
-rw-r--r--lib/CodeGen/CGBuiltin.cpp3
-rw-r--r--lib/CodeGen/CGCXX.cpp8
-rw-r--r--lib/CodeGen/CGCall.cpp116
-rw-r--r--lib/CodeGen/CGCall.h9
-rw-r--r--lib/CodeGen/CGClass.cpp445
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp918
-rw-r--r--lib/CodeGen/CGDebugInfo.h45
-rw-r--r--lib/CodeGen/CGDecl.cpp91
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp118
-rw-r--r--lib/CodeGen/CGException.cpp26
-rw-r--r--lib/CodeGen/CGExpr.cpp149
-rw-r--r--lib/CodeGen/CGExprAgg.cpp86
-rw-r--r--lib/CodeGen/CGExprCXX.cpp125
-rw-r--r--lib/CodeGen/CGExprComplex.cpp12
-rw-r--r--lib/CodeGen/CGExprConstant.cpp175
-rw-r--r--lib/CodeGen/CGExprScalar.cpp57
-rw-r--r--lib/CodeGen/CGObjC.cpp26
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp135
-rw-r--r--lib/CodeGen/CGObjCMac.cpp29
-rw-r--r--lib/CodeGen/CGRTTI.cpp7
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp41
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.h15
-rw-r--r--lib/CodeGen/CGStmt.cpp22
-rw-r--r--lib/CodeGen/CGVtable.cpp1683
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp24
-rw-r--r--lib/CodeGen/CodeGenFunction.h61
-rw-r--r--lib/CodeGen/CodeGenModule.cpp149
-rw-r--r--lib/CodeGen/CodeGenModule.h18
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp32
-rw-r--r--lib/CodeGen/CodeGenTypes.h36
-rw-r--r--lib/CodeGen/GlobalDecl.h4
-rw-r--r--lib/CodeGen/Makefile1
-rw-r--r--lib/CodeGen/Mangle.cpp320
-rw-r--r--lib/CodeGen/TargetInfo.cpp126
-rw-r--r--lib/Driver/Driver.cpp81
-rw-r--r--lib/Driver/HostInfo.cpp11
-rw-r--r--lib/Driver/Makefile1
-rw-r--r--lib/Driver/ToolChains.cpp158
-rw-r--r--lib/Driver/ToolChains.h115
-rw-r--r--lib/Driver/Tools.cpp228
-rw-r--r--lib/Driver/Tools.h19
-rw-r--r--lib/Frontend/ASTConsumers.cpp2
-rw-r--r--lib/Frontend/ASTMerge.cpp103
-rw-r--r--lib/Frontend/ASTUnit.cpp30
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp161
-rw-r--r--lib/Frontend/Backend.cpp38
-rw-r--r--lib/Frontend/CMakeLists.txt1
-rw-r--r--lib/Frontend/CompilerInstance.cpp54
-rw-r--r--lib/Frontend/CompilerInvocation.cpp41
-rw-r--r--lib/Frontend/FrontendActions.cpp5
-rw-r--r--lib/Frontend/HTMLDiagnostics.cpp2
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp10
-rw-r--r--lib/Frontend/InitPreprocessor.cpp2
-rw-r--r--lib/Frontend/Makefile1
-rw-r--r--lib/Frontend/PCHReader.cpp44
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp13
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp33
-rw-r--r--lib/Frontend/PCHWriter.cpp35
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp1
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp21
-rw-r--r--lib/Frontend/PlistDiagnostics.cpp2
-rw-r--r--lib/Frontend/PrintParserCallbacks.cpp5
-rw-r--r--lib/Frontend/RewriteObjC.cpp448
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp26
-rw-r--r--lib/Headers/xmmintrin.h16
-rw-r--r--lib/Index/Makefile1
-rw-r--r--lib/Lex/Lexer.cpp16
-rw-r--r--lib/Lex/Makefile1
-rw-r--r--lib/Lex/PPCaching.cpp2
-rw-r--r--lib/Lex/PPDirectives.cpp17
-rw-r--r--lib/Lex/PPMacroExpansion.cpp38
-rw-r--r--lib/Lex/Preprocessor.cpp2
-rwxr-xr-xlib/Makefile2
-rw-r--r--lib/Parse/DeclSpec.cpp37
-rw-r--r--lib/Parse/Makefile1
-rw-r--r--lib/Parse/ParseDecl.cpp94
-rw-r--r--lib/Parse/ParseDeclCXX.cpp122
-rw-r--r--lib/Parse/ParseExpr.cpp41
-rw-r--r--lib/Parse/ParseExprCXX.cpp7
-rw-r--r--lib/Parse/ParseObjc.cpp24
-rw-r--r--lib/Parse/ParseStmt.cpp90
-rw-r--r--lib/Parse/ParseTemplate.cpp2
-rw-r--r--lib/Parse/ParseTentative.cpp9
-rw-r--r--lib/Parse/Parser.cpp23
-rw-r--r--lib/Rewrite/Makefile1
-rw-r--r--lib/Sema/IdentifierResolver.cpp38
-rw-r--r--lib/Sema/Lookup.h44
-rw-r--r--lib/Sema/Makefile1
-rw-r--r--lib/Sema/Sema.cpp280
-rw-r--r--lib/Sema/Sema.h327
-rw-r--r--lib/Sema/SemaAccess.cpp592
-rw-r--r--lib/Sema/SemaCXXCast.cpp59
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp4
-rw-r--r--lib/Sema/SemaChecking.cpp554
-rw-r--r--lib/Sema/SemaCodeComplete.cpp16
-rw-r--r--lib/Sema/SemaDecl.cpp682
-rw-r--r--lib/Sema/SemaDeclAttr.cpp211
-rw-r--r--lib/Sema/SemaDeclCXX.cpp730
-rw-r--r--lib/Sema/SemaDeclObjC.cpp219
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp83
-rw-r--r--lib/Sema/SemaExpr.cpp148
-rw-r--r--lib/Sema/SemaExprCXX.cpp127
-rw-r--r--lib/Sema/SemaExprObjC.cpp31
-rw-r--r--lib/Sema/SemaInit.cpp692
-rw-r--r--lib/Sema/SemaInit.h35
-rw-r--r--lib/Sema/SemaLookup.cpp318
-rw-r--r--lib/Sema/SemaOverload.cpp646
-rw-r--r--lib/Sema/SemaOverload.h62
-rw-r--r--lib/Sema/SemaStmt.cpp178
-rw-r--r--lib/Sema/SemaTemplate.cpp199
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp361
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp242
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp182
-rw-r--r--lib/Sema/SemaType.cpp188
-rw-r--r--lib/Sema/TargetAttributesSema.cpp44
-rw-r--r--lib/Sema/TreeTransform.h160
226 files changed, 16999 insertions, 7512 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index c1bc70989d4e..c23babb9a4a5 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -56,6 +56,10 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
}
ASTContext::~ASTContext() {
+ // Release the DenseMaps associated with DeclContext objects.
+ // FIXME: Is this the ideal solution?
+ ReleaseDeclContextMaps();
+
if (FreeMemory) {
// Deallocate all the types.
while (!Types.empty()) {
@@ -533,12 +537,12 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
}
}
-/// getDeclAlignInBytes - Return a conservative estimate of the alignment of the
+/// getDeclAlign - Return a conservative estimate of the alignment of the
/// specified decl. Note that bitfields do not have a valid alignment, so
/// this method will assert on them.
/// If @p RefAsPointee, references are treated like their underlying type
/// (for alignof), else they're treated like pointers (for CodeGen).
-unsigned ASTContext::getDeclAlignInBytes(const Decl *D, bool RefAsPointee) {
+CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) {
unsigned Align = Target.getCharWidth();
if (const AlignedAttr* AA = D->getAttr<AlignedAttr>())
@@ -561,7 +565,7 @@ unsigned ASTContext::getDeclAlignInBytes(const Decl *D, bool RefAsPointee) {
}
}
- return Align / Target.getCharWidth();
+ return CharUnits::fromQuantity(Align / Target.getCharWidth());
}
/// getTypeSize - Return the size of the specified type, in bits. This method
@@ -820,6 +824,15 @@ CharUnits ASTContext::getTypeSizeInChars(const Type *T) {
return CharUnits::fromQuantity(getTypeSize(T) / getCharWidth());
}
+/// getTypeAlignInChars - Return the ABI-specified alignment of a type, in
+/// characters. This method does not work on incomplete types.
+CharUnits ASTContext::getTypeAlignInChars(QualType T) {
+ return CharUnits::fromQuantity(getTypeAlign(T) / getCharWidth());
+}
+CharUnits ASTContext::getTypeAlignInChars(const Type *T) {
+ return CharUnits::fromQuantity(getTypeAlign(T) / getCharWidth());
+}
+
/// getPreferredTypeAlign - Return the "preferred" alignment of the specified
/// type for the current target in bits. This can be different than the ABI
/// alignment in cases where it is beneficial for performance to overalign
@@ -904,12 +917,12 @@ void ASTContext::CollectSynthesizedIvars(const ObjCInterfaceDecl *OI,
/// CollectInheritedProtocols - Collect all protocols in current class and
/// those inherited by it.
void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
- llvm::SmallVectorImpl<ObjCProtocolDecl*> &Protocols) {
+ llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols) {
if (const ObjCInterfaceDecl *OI = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(),
PE = OI->protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
- Protocols.push_back(Proto);
+ Protocols.insert(Proto);
for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
PE = Proto->protocol_end(); P != PE; ++P)
CollectInheritedProtocols(*P, Protocols);
@@ -930,7 +943,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
for (ObjCInterfaceDecl::protocol_iterator P = OC->protocol_begin(),
PE = OC->protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
- Protocols.push_back(Proto);
+ Protocols.insert(Proto);
for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
PE = Proto->protocol_end(); P != PE; ++P)
CollectInheritedProtocols(*P, Protocols);
@@ -941,7 +954,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
for (ObjCProtocolDecl::protocol_iterator P = OP->protocol_begin(),
PE = OP->protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
- Protocols.push_back(Proto);
+ Protocols.insert(Proto);
for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
PE = Proto->protocol_end(); P != PE; ++P)
CollectInheritedProtocols(*P, Protocols);
@@ -1088,7 +1101,7 @@ ASTContext::getASTObjCImplementationLayout(const ObjCImplementationDecl *D) {
/// specified record (struct/union/class), which indicates its size and field
/// position information.
const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
- D = D->getDefinition(*this);
+ D = D->getDefinition();
assert(D && "Cannot get layout of forward declarations!");
// Look up this layout, if already laid out, return what we have.
@@ -1105,7 +1118,7 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
}
const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
- RD = cast<CXXRecordDecl>(RD->getDefinition(*this));
+ RD = cast<CXXRecordDecl>(RD->getDefinition());
assert(RD && "Cannot get key function for forward declarations!");
const CXXMethodDecl *&Entry = KeyFunctions[RD];
@@ -1519,12 +1532,12 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy,
void *InsertPos = 0;
DependentSizedArrayType *Canon = 0;
+ llvm::FoldingSetNodeID ID;
if (NumElts) {
// Dependently-sized array types that do not have a specified
// number of elements will have their sizes deduced from an
// initializer.
- llvm::FoldingSetNodeID ID;
DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM,
EltTypeQuals, NumElts);
@@ -1545,8 +1558,13 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy,
DependentSizedArrayType(*this, EltTy, QualType(),
NumElts, ASM, EltTypeQuals, Brackets);
- if (NumElts)
+ if (NumElts) {
+ DependentSizedArrayType *CanonCheck
+ = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!CanonCheck && "Dependent-sized canonical array type broken");
+ (void)CanonCheck;
DependentSizedArrayTypes.InsertNode(New, InsertPos);
+ }
} else {
QualType Canon = getDependentSizedArrayType(CanonEltTy, NumElts,
ASM, EltTypeQuals,
@@ -1596,7 +1614,8 @@ QualType ASTContext::getIncompleteArrayType(QualType EltTy,
/// getVectorType - Return the unique reference to a vector type of
/// the specified element type and size. VectorType must be a built-in type.
-QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) {
+QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts,
+ bool IsAltiVec, bool IsPixel) {
BuiltinType *baseType;
baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr());
@@ -1604,7 +1623,8 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) {
// Check if we've already instantiated a vector of this type.
llvm::FoldingSetNodeID ID;
- VectorType::Profile(ID, vecType, NumElts, Type::Vector);
+ VectorType::Profile(ID, vecType, NumElts, Type::Vector,
+ IsAltiVec, IsPixel);
void *InsertPos = 0;
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(VTP, 0);
@@ -1612,15 +1632,16 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) {
// If the element type isn't canonical, this won't be a canonical type either,
// so fill in the canonical type field.
QualType Canonical;
- if (!vecType.isCanonical()) {
- Canonical = getVectorType(getCanonicalType(vecType), NumElts);
+ if (!vecType.isCanonical() || IsAltiVec || IsPixel) {
+ Canonical = getVectorType(getCanonicalType(vecType),
+ NumElts, false, false);
// Get the new insert position for the node we care about.
VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
}
VectorType *New = new (*this, TypeAlignment)
- VectorType(vecType, NumElts, Canonical);
+ VectorType(vecType, NumElts, Canonical, IsAltiVec, IsPixel);
VectorTypes.InsertNode(New, InsertPos);
Types.push_back(New);
return QualType(New, 0);
@@ -1636,7 +1657,7 @@ QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) {
// Check if we've already instantiated a vector of this type.
llvm::FoldingSetNodeID ID;
- VectorType::Profile(ID, vecType, NumElts, Type::ExtVector);
+ VectorType::Profile(ID, vecType, NumElts, Type::ExtVector, false, false);
void *InsertPos = 0;
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(VTP, 0);
@@ -1681,6 +1702,11 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType,
New = new (*this, TypeAlignment)
DependentSizedExtVectorType(*this, vecType, QualType(), SizeExpr,
AttrLoc);
+
+ DependentSizedExtVectorType *CanonCheck
+ = DependentSizedExtVectorTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!CanonCheck && "Dependent-sized ext_vector canonical type broken");
+ (void)CanonCheck;
DependentSizedExtVectorTypes.InsertNode(New, InsertPos);
} else {
QualType Canon = getDependentSizedExtVectorType(CanonVecTy, SizeExpr,
@@ -1694,12 +1720,6 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType,
return QualType(New, 0);
}
-static CallingConv getCanonicalCallingConv(CallingConv CC) {
- if (CC == CC_C)
- return CC_Default;
- return CC;
-}
-
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
///
QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
@@ -1707,7 +1727,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
- FunctionNoProtoType::Profile(ID, ResultTy, NoReturn);
+ FunctionNoProtoType::Profile(ID, ResultTy, NoReturn, CallConv);
void *InsertPos = 0;
if (FunctionNoProtoType *FT =
@@ -1716,9 +1736,9 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
QualType Canonical;
if (!ResultTy.isCanonical() ||
- getCanonicalCallingConv(CallConv) != CallConv) {
+ getCanonicalCallConv(CallConv) != CallConv) {
Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn,
- getCanonicalCallingConv(CallConv));
+ getCanonicalCallConv(CallConv));
// Get the new insert position for the node we care about.
FunctionNoProtoType *NewIP =
@@ -1727,7 +1747,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
}
FunctionNoProtoType *New = new (*this, TypeAlignment)
- FunctionNoProtoType(ResultTy, Canonical, NoReturn);
+ FunctionNoProtoType(ResultTy, Canonical, NoReturn, CallConv);
Types.push_back(New);
FunctionNoProtoTypes.InsertNode(New, InsertPos);
return QualType(New, 0);
@@ -1746,7 +1766,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
llvm::FoldingSetNodeID ID;
FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic,
TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
- NumExs, ExArray, NoReturn);
+ NumExs, ExArray, NoReturn, CallConv);
void *InsertPos = 0;
if (FunctionProtoType *FTP =
@@ -1762,7 +1782,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
// If this type isn't canonical, get the canonical version of it.
// The exception spec is not part of the canonical type.
QualType Canonical;
- if (!isCanonical || getCanonicalCallingConv(CallConv) != CallConv) {
+ if (!isCanonical || getCanonicalCallConv(CallConv) != CallConv) {
llvm::SmallVector<QualType, 16> CanonicalArgs;
CanonicalArgs.reserve(NumArgs);
for (unsigned i = 0; i != NumArgs; ++i)
@@ -1772,7 +1792,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
CanonicalArgs.data(), NumArgs,
isVariadic, TypeQuals, false,
false, 0, 0, NoReturn,
- getCanonicalCallingConv(CallConv));
+ getCanonicalCallConv(CallConv));
// Get the new insert position for the node we care about.
FunctionProtoType *NewIP =
@@ -1797,29 +1817,30 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
/// getTypeDeclType - Return the unique reference to the type for the
/// specified type declaration.
-QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) {
+QualType ASTContext::getTypeDeclType(const TypeDecl *Decl,
+ const TypeDecl* PrevDecl) {
assert(Decl && "Passed null for Decl param");
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
- if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl))
+ if (const TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl))
return getTypedefType(Typedef);
else if (isa<TemplateTypeParmDecl>(Decl)) {
assert(false && "Template type parameter types are always available.");
- } else if (ObjCInterfaceDecl *ObjCInterface
+ } else if (const ObjCInterfaceDecl *ObjCInterface
= dyn_cast<ObjCInterfaceDecl>(Decl))
return getObjCInterfaceType(ObjCInterface);
- if (RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) {
+ if (const RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) {
if (PrevDecl)
Decl->TypeForDecl = PrevDecl->TypeForDecl;
else
Decl->TypeForDecl = new (*this, TypeAlignment) RecordType(Record);
- } else if (EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) {
+ } else if (const EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) {
if (PrevDecl)
Decl->TypeForDecl = PrevDecl->TypeForDecl;
else
Decl->TypeForDecl = new (*this, TypeAlignment) EnumType(Enum);
- } else if (UnresolvedUsingTypenameDecl *Using =
+ } else if (const UnresolvedUsingTypenameDecl *Using =
dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) {
Decl->TypeForDecl = new (*this, TypeAlignment) UnresolvedUsingType(Using);
} else
@@ -1831,7 +1852,7 @@ QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) {
/// getTypedefType - Return the unique reference to the type for the
/// specified typename decl.
-QualType ASTContext::getTypedefType(TypedefDecl *Decl) {
+QualType ASTContext::getTypedefType(const TypedefDecl *Decl) {
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
QualType Canonical = getCanonicalType(Decl->getUnderlyingType());
@@ -1883,6 +1904,11 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
QualType Canon = getTemplateTypeParmType(Depth, Index, ParameterPack);
TypeParm = new (*this, TypeAlignment)
TemplateTypeParmType(Depth, Index, ParameterPack, Name, Canon);
+
+ TemplateTypeParmType *TypeCheck
+ = TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!TypeCheck && "Template type parameter canonical type broken");
+ (void)TypeCheck;
} else
TypeParm = new (*this, TypeAlignment)
TemplateTypeParmType(Depth, Index, ParameterPack);
@@ -1976,8 +2002,16 @@ ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS,
if (T)
return QualType(T, 0);
- T = new (*this) QualifiedNameType(NNS, NamedType,
- getCanonicalType(NamedType));
+ QualType Canon = NamedType;
+ if (!Canon.isCanonical()) {
+ Canon = getCanonicalType(NamedType);
+ QualifiedNameType *CheckT
+ = QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!CheckT && "Qualified name canonical type broken");
+ (void)CheckT;
+ }
+
+ T = new (*this) QualifiedNameType(NNS, NamedType, Canon);
Types.push_back(T);
QualifiedNameTypes.InsertNode(T, InsertPos);
return QualType(T, 0);
@@ -2015,6 +2049,15 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS,
QualType Canon) {
assert(NNS->isDependent() && "nested-name-specifier must be dependent");
+ llvm::FoldingSetNodeID ID;
+ TypenameType::Profile(ID, NNS, TemplateId);
+
+ void *InsertPos = 0;
+ TypenameType *T
+ = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
+ if (T)
+ return QualType(T, 0);
+
if (Canon.isNull()) {
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
QualType CanonType = getCanonicalType(QualType(TemplateId, 0));
@@ -2025,16 +2068,11 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS,
"Canonical type must also be a template specialization type");
Canon = getTypenameType(CanonNNS, CanonTemplateId);
}
- }
- llvm::FoldingSetNodeID ID;
- TypenameType::Profile(ID, NNS, TemplateId);
-
- void *InsertPos = 0;
- TypenameType *T
- = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
- if (T)
- return QualType(T, 0);
+ TypenameType *CheckT
+ = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!CheckT && "Typename canonical type is broken"); (void)CheckT;
+ }
T = new (*this) TypenameType(NNS, TemplateId, Canon);
Types.push_back(T);
@@ -2053,7 +2091,12 @@ ASTContext::getElaboratedType(QualType UnderlyingType,
if (T)
return QualType(T, 0);
- QualType Canon = getCanonicalType(UnderlyingType);
+ QualType Canon = UnderlyingType;
+ if (!Canon.isCanonical()) {
+ Canon = getCanonicalType(Canon);
+ ElaboratedType *CheckT = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!CheckT && "Elaborated canonical type is broken"); (void)CheckT;
+ }
T = new (*this) ElaboratedType(UnderlyingType, Tag, Canon);
Types.push_back(T);
@@ -2125,10 +2168,14 @@ QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT,
ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos);
}
- // No Match;
- ObjCObjectPointerType *QType = new (*this, TypeAlignment)
- ObjCObjectPointerType(*this, Canonical, InterfaceT, Protocols,
- NumProtocols);
+ // No match.
+ unsigned Size = sizeof(ObjCObjectPointerType)
+ + NumProtocols * sizeof(ObjCProtocolDecl *);
+ void *Mem = Allocate(Size, TypeAlignment);
+ ObjCObjectPointerType *QType = new (Mem) ObjCObjectPointerType(Canonical,
+ InterfaceT,
+ Protocols,
+ NumProtocols);
Types.push_back(QType);
ObjCObjectPointerTypes.InsertNode(QType, InsertPos);
@@ -2161,9 +2208,13 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos);
}
- ObjCInterfaceType *QType = new (*this, TypeAlignment)
- ObjCInterfaceType(*this, Canonical, const_cast<ObjCInterfaceDecl*>(Decl),
- Protocols, NumProtocols);
+ unsigned Size = sizeof(ObjCInterfaceType)
+ + NumProtocols * sizeof(ObjCProtocolDecl *);
+ void *Mem = Allocate(Size, TypeAlignment);
+ ObjCInterfaceType *QType = new (Mem) ObjCInterfaceType(Canonical,
+ const_cast<ObjCInterfaceDecl*>(Decl),
+ Protocols,
+ NumProtocols);
Types.push_back(QType);
ObjCInterfaceTypes.InsertNode(QType, InsertPos);
@@ -2858,6 +2909,7 @@ QualType ASTContext::getCFConstantStringType() {
CFConstantStringTypeDecl =
CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
&Idents.get("NSConstantString"));
+ CFConstantStringTypeDecl->startDefinition();
QualType FieldTypes[4];
@@ -2880,7 +2932,7 @@ QualType ASTContext::getCFConstantStringType() {
CFConstantStringTypeDecl->addDecl(Field);
}
- CFConstantStringTypeDecl->completeDefinition(*this);
+ CFConstantStringTypeDecl->completeDefinition();
}
return getTagDeclType(CFConstantStringTypeDecl);
@@ -2897,6 +2949,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() {
ObjCFastEnumerationStateTypeDecl =
CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
&Idents.get("__objcFastEnumerationState"));
+ ObjCFastEnumerationStateTypeDecl->startDefinition();
QualType FieldTypes[] = {
UnsignedLongTy,
@@ -2916,7 +2969,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() {
ObjCFastEnumerationStateTypeDecl->addDecl(Field);
}
- ObjCFastEnumerationStateTypeDecl->completeDefinition(*this);
+ ObjCFastEnumerationStateTypeDecl->completeDefinition();
}
return getTagDeclType(ObjCFastEnumerationStateTypeDecl);
@@ -2930,6 +2983,7 @@ QualType ASTContext::getBlockDescriptorType() {
// FIXME: Needs the FlagAppleBlock bit.
T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
&Idents.get("__block_descriptor"));
+ T->startDefinition();
QualType FieldTypes[] = {
UnsignedLongTy,
@@ -2952,7 +3006,7 @@ QualType ASTContext::getBlockDescriptorType() {
T->addDecl(Field);
}
- T->completeDefinition(*this);
+ T->completeDefinition();
BlockDescriptorType = T;
@@ -2973,6 +3027,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() {
// FIXME: Needs the FlagAppleBlock bit.
T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
&Idents.get("__block_descriptor_withcopydispose"));
+ T->startDefinition();
QualType FieldTypes[] = {
UnsignedLongTy,
@@ -2999,7 +3054,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() {
T->addDecl(Field);
}
- T->completeDefinition(*this);
+ T->completeDefinition();
BlockDescriptorExtendedType = T;
@@ -3076,7 +3131,7 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) {
T->addDecl(Field);
}
- T->completeDefinition(*this);
+ T->completeDefinition();
return getPointerType(getTagDeclType(T));
}
@@ -3093,6 +3148,7 @@ QualType ASTContext::getBlockParmType(
RecordDecl *T;
T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
&Idents.get(Name.str()));
+ T->startDefinition();
QualType FieldTypes[] = {
getPointerType(VoidPtrTy),
IntTy,
@@ -3139,7 +3195,7 @@ QualType ASTContext::getBlockParmType(
T->addDecl(Field);
}
- T->completeDefinition(*this);
+ T->completeDefinition();
return getPointerType(getTagDeclType(T));
}
@@ -3786,6 +3842,7 @@ TemplateName ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin,
TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
bool TemplateKeyword,
TemplateDecl *Template) {
+ // FIXME: Canonicalization?
llvm::FoldingSetNodeID ID;
QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template);
@@ -3823,6 +3880,10 @@ TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
} else {
TemplateName Canon = getDependentTemplateName(CanonNNS, Name);
QTN = new (*this,4) DependentTemplateName(NNS, Name, Canon);
+ DependentTemplateName *CheckQTN =
+ DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!CheckQTN && "Dependent type name canonicalization broken");
+ (void)CheckQTN;
}
DependentTemplateNames.InsertNode(QTN, InsertPos);
@@ -3841,8 +3902,8 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
DependentTemplateName::Profile(ID, NNS, Operator);
void *InsertPos = 0;
- DependentTemplateName *QTN =
- DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
+ DependentTemplateName *QTN
+ = DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
if (QTN)
return TemplateName(QTN);
@@ -3853,6 +3914,11 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
} else {
TemplateName Canon = getDependentTemplateName(CanonNNS, Operator);
QTN = new (*this,4) DependentTemplateName(NNS, Operator, Canon);
+
+ DependentTemplateName *CheckQTN
+ = DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!CheckQTN && "Dependent template name canonicalization broken");
+ (void)CheckQTN;
}
DependentTemplateNames.InsertNode(QTN, InsertPos);
@@ -4123,8 +4189,8 @@ void getIntersectionOfProtocols(ASTContext &Context,
if (LHSNumProtocols > 0)
InheritedProtocolSet.insert(LHS->qual_begin(), LHS->qual_end());
else {
- llvm::SmallVector<ObjCProtocolDecl *, 8> LHSInheritedProtocols;
- Context.CollectInheritedProtocols(LHS->getDecl(), LHSInheritedProtocols);
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSInheritedProtocols;
+ Context.CollectInheritedProtocols(LHS->getDecl(), LHSInheritedProtocols);
InheritedProtocolSet.insert(LHSInheritedProtocols.begin(),
LHSInheritedProtocols.end());
}
@@ -4137,13 +4203,13 @@ void getIntersectionOfProtocols(ASTContext &Context,
IntersectionOfProtocols.push_back(RHSProtocols[i]);
}
else {
- llvm::SmallVector<ObjCProtocolDecl *, 8> RHSInheritedProtocols;
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSInheritedProtocols;
Context.CollectInheritedProtocols(RHS->getDecl(), RHSInheritedProtocols);
- // FIXME. This may cause duplication of protocols in the list, but should
- // be harmless.
- for (unsigned i = 0, len = RHSInheritedProtocols.size(); i < len; ++i)
- if (InheritedProtocolSet.count(RHSInheritedProtocols[i]))
- IntersectionOfProtocols.push_back(RHSInheritedProtocols[i]);
+ for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I =
+ RHSInheritedProtocols.begin(),
+ E = RHSInheritedProtocols.end(); I != E; ++I)
+ if (InheritedProtocolSet.count((*I)))
+ IntersectionOfProtocols.push_back((*I));
}
}
@@ -4235,13 +4301,12 @@ bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) {
/// C99 6.2.7p1: Two types have compatible types if their types are the
/// same. See 6.7.[2,3,5] for additional rules.
bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) {
+ if (getLangOptions().CPlusPlus)
+ return hasSameType(LHS, RHS);
+
return !mergeTypes(LHS, RHS).isNull();
}
-static bool isSameCallingConvention(CallingConv lcc, CallingConv rcc) {
- return (getCanonicalCallingConv(lcc) == getCanonicalCallingConv(rcc));
-}
-
QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
const FunctionType *lbase = lhs->getAs<FunctionType>();
const FunctionType *rbase = rhs->getAs<FunctionType>();
@@ -4266,7 +4331,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
CallingConv lcc = lbase->getCallConv();
CallingConv rcc = rbase->getCallConv();
// Compatible functions must have compatible calling conventions
- if (!isSameCallingConvention(lcc, rcc))
+ if (!isSameCallConv(lcc, rcc))
return QualType();
if (lproto && rproto) { // two C99 style function prototypes
@@ -4303,7 +4368,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
if (allRTypes) return rhs;
return getFunctionType(retType, types.begin(), types.size(),
lproto->isVariadic(), lproto->getTypeQuals(),
- NoReturn, lcc);
+ false, false, 0, 0, NoReturn, lcc);
}
if (lproto) allRTypes = false;
@@ -4321,6 +4386,12 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
unsigned proto_nargs = proto->getNumArgs();
for (unsigned i = 0; i < proto_nargs; ++i) {
QualType argTy = proto->getArgType(i);
+
+ // Look at the promotion type of enum types, since that is the type used
+ // to pass enum values.
+ if (const EnumType *Enum = argTy->getAs<EnumType>())
+ argTy = Enum->getDecl()->getPromotionType();
+
if (argTy->isPromotableIntegerType() ||
getCanonicalType(argTy).getUnqualifiedType() == FloatTy)
return QualType();
@@ -4344,15 +4415,9 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
// designates the object or function denoted by the reference, and the
// expression is an lvalue unless the reference is an rvalue reference and
// the expression is a function call (possibly inside parentheses).
- // FIXME: C++ shouldn't be going through here! The rules are different
- // enough that they should be handled separately.
- // FIXME: Merging of lvalue and rvalue references is incorrect. C++ *really*
- // shouldn't be going through here!
- if (const ReferenceType *RT = LHS->getAs<ReferenceType>())
- LHS = RT->getPointeeType();
- if (const ReferenceType *RT = RHS->getAs<ReferenceType>())
- RHS = RT->getPointeeType();
-
+ assert(!LHS->getAs<ReferenceType>() && "LHS is a reference type?");
+ assert(!RHS->getAs<ReferenceType>() && "RHS is a reference type?");
+
QualType LHSCan = getCanonicalType(LHS),
RHSCan = getCanonicalType(RHS);
@@ -4582,7 +4647,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) {
// Turn <4 x signed int> -> <4 x unsigned int>
if (const VectorType *VTy = T->getAs<VectorType>())
return getVectorType(getCorrespondingUnsignedType(VTy->getElementType()),
- VTy->getNumElements());
+ VTy->getNumElements(), VTy->isAltiVec(), VTy->isPixel());
// For enums, we return the unsigned version of the base type.
if (const EnumType *ETy = T->getAs<EnumType>())
@@ -4739,7 +4804,8 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
Str = End;
QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false);
- Type = Context.getVectorType(ElementType, NumElements);
+ // FIXME: Don't know what to do about AltiVec.
+ Type = Context.getVectorType(ElementType, NumElements, false, false);
break;
}
case 'X': {
@@ -4784,6 +4850,9 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
case 'C':
Type = Type.withConst();
break;
+ case 'D':
+ Type = Context.getVolatileType(Type);
+ break;
}
}
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
new file mode 100644
index 000000000000..7402b7dda4ec
--- /dev/null
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -0,0 +1,266 @@
+//===--- ASTDiagnostic.cpp - Diagnostic Printing Hooks for AST Nodes ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a diagnostic formatting hook for AST elements.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/ASTDiagnostic.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Type.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+/// Determines whether we should have an a.k.a. clause when
+/// pretty-printing a type. There are three main criteria:
+///
+/// 1) Some types provide very minimal sugar that doesn't impede the
+/// user's understanding --- for example, elaborated type
+/// specifiers. If this is all the sugar we see, we don't want an
+/// a.k.a. clause.
+/// 2) Some types are technically sugared but are much more familiar
+/// when seen in their sugared form --- for example, va_list,
+/// vector types, and the magic Objective C types. We don't
+/// want to desugar these, even if we do produce an a.k.a. clause.
+/// 3) Some types may have already been desugared previously in this diagnostic.
+/// if this is the case, doing another "aka" would just be clutter.
+///
+static bool ShouldAKA(ASTContext &Context, QualType QT,
+ const Diagnostic::ArgumentValue *PrevArgs,
+ unsigned NumPrevArgs,
+ QualType &DesugaredQT) {
+ QualType InputTy = QT;
+
+ bool AKA = false;
+ QualifierCollector Qc;
+
+ while (true) {
+ const Type *Ty = Qc.strip(QT);
+
+ // Don't aka just because we saw an elaborated type...
+ if (isa<ElaboratedType>(Ty)) {
+ QT = cast<ElaboratedType>(Ty)->desugar();
+ continue;
+ }
+
+ // ...or a qualified name type...
+ if (isa<QualifiedNameType>(Ty)) {
+ QT = cast<QualifiedNameType>(Ty)->desugar();
+ continue;
+ }
+
+ // ...or a substituted template type parameter.
+ if (isa<SubstTemplateTypeParmType>(Ty)) {
+ QT = cast<SubstTemplateTypeParmType>(Ty)->desugar();
+ continue;
+ }
+
+ // Don't desugar template specializations.
+ if (isa<TemplateSpecializationType>(Ty))
+ break;
+
+ // Don't desugar magic Objective-C types.
+ if (QualType(Ty,0) == Context.getObjCIdType() ||
+ QualType(Ty,0) == Context.getObjCClassType() ||
+ QualType(Ty,0) == Context.getObjCSelType() ||
+ QualType(Ty,0) == Context.getObjCProtoType())
+ break;
+
+ // Don't desugar va_list.
+ if (QualType(Ty,0) == Context.getBuiltinVaListType())
+ break;
+
+ // Otherwise, do a single-step desugar.
+ QualType Underlying;
+ bool IsSugar = false;
+ switch (Ty->getTypeClass()) {
+#define ABSTRACT_TYPE(Class, Base)
+#define TYPE(Class, Base) \
+case Type::Class: { \
+const Class##Type *CTy = cast<Class##Type>(Ty); \
+if (CTy->isSugared()) { \
+IsSugar = true; \
+Underlying = CTy->desugar(); \
+} \
+break; \
+}
+#include "clang/AST/TypeNodes.def"
+ }
+
+ // If it wasn't sugared, we're done.
+ if (!IsSugar)
+ break;
+
+ // If the desugared type is a vector type, we don't want to expand
+ // it, it will turn into an attribute mess. People want their "vec4".
+ if (isa<VectorType>(Underlying))
+ break;
+
+ // Don't desugar through the primary typedef of an anonymous type.
+ if (isa<TagType>(Underlying) && isa<TypedefType>(QT))
+ if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() ==
+ cast<TypedefType>(QT)->getDecl())
+ break;
+
+ // Otherwise, we're tearing through something opaque; note that
+ // we'll eventually need an a.k.a. clause and keep going.
+ AKA = true;
+ QT = Underlying;
+ continue;
+ }
+
+ // If we never tore through opaque sugar, don't print aka.
+ if (!AKA) return false;
+
+ // If we did, check to see if we already desugared this type in this
+ // diagnostic. If so, don't do it again.
+ for (unsigned i = 0; i != NumPrevArgs; ++i) {
+ // TODO: Handle ak_declcontext case.
+ if (PrevArgs[i].first == Diagnostic::ak_qualtype) {
+ void *Ptr = (void*)PrevArgs[i].second;
+ QualType PrevTy(QualType::getFromOpaquePtr(Ptr));
+ if (PrevTy == InputTy)
+ return false;
+ }
+ }
+
+ DesugaredQT = Qc.apply(QT);
+ return true;
+}
+
+/// \brief Convert the given type to a string suitable for printing as part of
+/// a diagnostic.
+///
+/// \param Context the context in which the type was allocated
+/// \param Ty the type to print
+static std::string
+ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
+ const Diagnostic::ArgumentValue *PrevArgs,
+ unsigned NumPrevArgs) {
+ // FIXME: Playing with std::string is really slow.
+ std::string S = Ty.getAsString(Context.PrintingPolicy);
+
+ // Consider producing an a.k.a. clause if removing all the direct
+ // sugar gives us something "significantly different".
+
+ QualType DesugaredTy;
+ if (ShouldAKA(Context, Ty, PrevArgs, NumPrevArgs, DesugaredTy)) {
+ S = "'"+S+"' (aka '";
+ S += DesugaredTy.getAsString(Context.PrintingPolicy);
+ S += "')";
+ return S;
+ }
+
+ S = "'" + S + "'";
+ return S;
+}
+
+void clang::FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind,
+ intptr_t Val,
+ const char *Modifier,
+ unsigned ModLen,
+ const char *Argument,
+ unsigned ArgLen,
+ const Diagnostic::ArgumentValue *PrevArgs,
+ unsigned NumPrevArgs,
+ llvm::SmallVectorImpl<char> &Output,
+ void *Cookie) {
+ ASTContext &Context = *static_cast<ASTContext*>(Cookie);
+
+ std::string S;
+ bool NeedQuotes = true;
+
+ switch (Kind) {
+ default: assert(0 && "unknown ArgumentKind");
+ case Diagnostic::ak_qualtype: {
+ assert(ModLen == 0 && ArgLen == 0 &&
+ "Invalid modifier for QualType argument");
+
+ QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
+ S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs);
+ NeedQuotes = false;
+ break;
+ }
+ case Diagnostic::ak_declarationname: {
+ DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
+ S = N.getAsString();
+
+ if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0)
+ S = '+' + S;
+ else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12)
+ && ArgLen==0)
+ S = '-' + S;
+ else
+ assert(ModLen == 0 && ArgLen == 0 &&
+ "Invalid modifier for DeclarationName argument");
+ break;
+ }
+ case Diagnostic::ak_nameddecl: {
+ bool Qualified;
+ if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
+ Qualified = true;
+ else {
+ assert(ModLen == 0 && ArgLen == 0 &&
+ "Invalid modifier for NamedDecl* argument");
+ Qualified = false;
+ }
+ reinterpret_cast<NamedDecl*>(Val)->
+ getNameForDiagnostic(S, Context.PrintingPolicy, Qualified);
+ break;
+ }
+ case Diagnostic::ak_nestednamespec: {
+ llvm::raw_string_ostream OS(S);
+ reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS,
+ Context.PrintingPolicy);
+ NeedQuotes = false;
+ break;
+ }
+ case Diagnostic::ak_declcontext: {
+ DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
+ assert(DC && "Should never have a null declaration context");
+
+ if (DC->isTranslationUnit()) {
+ // FIXME: Get these strings from some localized place
+ if (Context.getLangOptions().CPlusPlus)
+ S = "the global namespace";
+ else
+ S = "the global scope";
+ } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
+ S = ConvertTypeToDiagnosticString(Context,
+ Context.getTypeDeclType(Type),
+ PrevArgs, NumPrevArgs);
+ } else {
+ // FIXME: Get these strings from some localized place
+ NamedDecl *ND = cast<NamedDecl>(DC);
+ if (isa<NamespaceDecl>(ND))
+ S += "namespace ";
+ else if (isa<ObjCMethodDecl>(ND))
+ S += "method ";
+ else if (isa<FunctionDecl>(ND))
+ S += "function ";
+
+ S += "'";
+ ND->getNameForDiagnostic(S, Context.PrintingPolicy, true);
+ S += "'";
+ }
+ NeedQuotes = false;
+ break;
+ }
+ }
+
+ if (NeedQuotes)
+ Output.push_back('\'');
+
+ Output.append(S.begin(), S.end());
+
+ if (NeedQuotes)
+ Output.push_back('\'');
+}
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
new file mode 100644
index 000000000000..dee0d2b342fc
--- /dev/null
+++ b/lib/AST/ASTImporter.cpp
@@ -0,0 +1,2394 @@
+//===--- ASTImporter.cpp - Importing ASTs from other Contexts ---*- 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 ASTImporter class which imports AST nodes from one
+// context into another context.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/ASTImporter.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/AST/TypeVisitor.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <deque>
+
+using namespace clang;
+
+namespace {
+ class ASTNodeImporter : public TypeVisitor<ASTNodeImporter, QualType>,
+ public DeclVisitor<ASTNodeImporter, Decl *>,
+ public StmtVisitor<ASTNodeImporter, Stmt *> {
+ ASTImporter &Importer;
+
+ public:
+ explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) { }
+
+ using TypeVisitor<ASTNodeImporter, QualType>::Visit;
+ using DeclVisitor<ASTNodeImporter, Decl *>::Visit;
+ using StmtVisitor<ASTNodeImporter, Stmt *>::Visit;
+
+ // Importing types
+ QualType VisitType(Type *T);
+ QualType VisitBuiltinType(BuiltinType *T);
+ QualType VisitComplexType(ComplexType *T);
+ QualType VisitPointerType(PointerType *T);
+ QualType VisitBlockPointerType(BlockPointerType *T);
+ QualType VisitLValueReferenceType(LValueReferenceType *T);
+ QualType VisitRValueReferenceType(RValueReferenceType *T);
+ QualType VisitMemberPointerType(MemberPointerType *T);
+ QualType VisitConstantArrayType(ConstantArrayType *T);
+ QualType VisitIncompleteArrayType(IncompleteArrayType *T);
+ QualType VisitVariableArrayType(VariableArrayType *T);
+ // FIXME: DependentSizedArrayType
+ // FIXME: DependentSizedExtVectorType
+ QualType VisitVectorType(VectorType *T);
+ QualType VisitExtVectorType(ExtVectorType *T);
+ QualType VisitFunctionNoProtoType(FunctionNoProtoType *T);
+ QualType VisitFunctionProtoType(FunctionProtoType *T);
+ // FIXME: UnresolvedUsingType
+ QualType VisitTypedefType(TypedefType *T);
+ QualType VisitTypeOfExprType(TypeOfExprType *T);
+ // FIXME: DependentTypeOfExprType
+ QualType VisitTypeOfType(TypeOfType *T);
+ QualType VisitDecltypeType(DecltypeType *T);
+ // FIXME: DependentDecltypeType
+ QualType VisitRecordType(RecordType *T);
+ QualType VisitEnumType(EnumType *T);
+ QualType VisitElaboratedType(ElaboratedType *T);
+ // FIXME: TemplateTypeParmType
+ // FIXME: SubstTemplateTypeParmType
+ // FIXME: TemplateSpecializationType
+ QualType VisitQualifiedNameType(QualifiedNameType *T);
+ // FIXME: TypenameType
+ QualType VisitObjCInterfaceType(ObjCInterfaceType *T);
+ QualType VisitObjCObjectPointerType(ObjCObjectPointerType *T);
+
+ // Importing declarations
+ bool ImportDeclParts(NamedDecl *D, DeclContext *&DC,
+ DeclContext *&LexicalDC, DeclarationName &Name,
+ SourceLocation &Loc);
+ bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord);
+ bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord);
+ Decl *VisitDecl(Decl *D);
+ Decl *VisitTypedefDecl(TypedefDecl *D);
+ Decl *VisitEnumDecl(EnumDecl *D);
+ Decl *VisitRecordDecl(RecordDecl *D);
+ Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
+ Decl *VisitFunctionDecl(FunctionDecl *D);
+ Decl *VisitFieldDecl(FieldDecl *D);
+ Decl *VisitVarDecl(VarDecl *D);
+ Decl *VisitParmVarDecl(ParmVarDecl *D);
+ Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
+
+ // Importing statements
+ Stmt *VisitStmt(Stmt *S);
+
+ // Importing expressions
+ Expr *VisitExpr(Expr *E);
+ Expr *VisitIntegerLiteral(IntegerLiteral *E);
+ Expr *VisitImplicitCastExpr(ImplicitCastExpr *E);
+ };
+}
+
+//----------------------------------------------------------------------------
+// Structural Equivalence
+//----------------------------------------------------------------------------
+
+namespace {
+ struct StructuralEquivalenceContext {
+ /// \brief AST contexts for which we are checking structural equivalence.
+ ASTContext &C1, &C2;
+
+ /// \brief Diagnostic object used to emit diagnostics.
+ Diagnostic &Diags;
+
+ /// \brief The set of "tentative" equivalences between two canonical
+ /// declarations, mapping from a declaration in the first context to the
+ /// declaration in the second context that we believe to be equivalent.
+ llvm::DenseMap<Decl *, Decl *> TentativeEquivalences;
+
+ /// \brief Queue of declarations in the first context whose equivalence
+ /// with a declaration in the second context still needs to be verified.
+ std::deque<Decl *> DeclsToCheck;
+
+ /// \brief Declaration (from, to) pairs that are known not to be equivalent
+ /// (which we have already complained about).
+ llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls;
+
+ /// \brief Whether we're being strict about the spelling of types when
+ /// unifying two types.
+ bool StrictTypeSpelling;
+
+ StructuralEquivalenceContext(ASTContext &C1, ASTContext &C2,
+ Diagnostic &Diags,
+ llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls,
+ bool StrictTypeSpelling = false)
+ : C1(C1), C2(C2), Diags(Diags), NonEquivalentDecls(NonEquivalentDecls),
+ StrictTypeSpelling(StrictTypeSpelling) { }
+
+ /// \brief Determine whether the two declarations are structurally
+ /// equivalent.
+ bool IsStructurallyEquivalent(Decl *D1, Decl *D2);
+
+ /// \brief Determine whether the two types are structurally equivalent.
+ bool IsStructurallyEquivalent(QualType T1, QualType T2);
+
+ private:
+ /// \brief Finish checking all of the structural equivalences.
+ ///
+ /// \returns true if an error occurred, false otherwise.
+ bool Finish();
+
+ public:
+ DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) {
+ return Diags.Report(FullSourceLoc(Loc, C1.getSourceManager()), DiagID);
+ }
+
+ DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) {
+ return Diags.Report(FullSourceLoc(Loc, C2.getSourceManager()), DiagID);
+ }
+ };
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ QualType T1, QualType T2);
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ Decl *D1, Decl *D2);
+
+/// \brief Determine if two APInts have the same value, after zero-extending
+/// one of them (if needed!) to ensure that the bit-widths match.
+static bool IsSameValue(const llvm::APInt &I1, const llvm::APInt &I2) {
+ if (I1.getBitWidth() == I2.getBitWidth())
+ return I1 == I2;
+
+ if (I1.getBitWidth() > I2.getBitWidth())
+ return I1 == llvm::APInt(I2).zext(I1.getBitWidth());
+
+ return llvm::APInt(I1).zext(I2.getBitWidth()) == I2;
+}
+
+/// \brief Determine if two APSInts have the same value, zero- or sign-extending
+/// as needed.
+static bool IsSameValue(const llvm::APSInt &I1, const llvm::APSInt &I2) {
+ if (I1.getBitWidth() == I2.getBitWidth() && I1.isSigned() == I2.isSigned())
+ return I1 == I2;
+
+ // Check for a bit-width mismatch.
+ if (I1.getBitWidth() > I2.getBitWidth())
+ return IsSameValue(I1, llvm::APSInt(I2).extend(I1.getBitWidth()));
+ else if (I2.getBitWidth() > I1.getBitWidth())
+ return IsSameValue(llvm::APSInt(I1).extend(I2.getBitWidth()), I2);
+
+ // We have a signedness mismatch. Turn the signed value into an unsigned
+ // value.
+ if (I1.isSigned()) {
+ if (I1.isNegative())
+ return false;
+
+ return llvm::APSInt(I1, true) == I2;
+ }
+
+ if (I2.isNegative())
+ return false;
+
+ return I1 == llvm::APSInt(I2, true);
+}
+
+/// \brief Determine structural equivalence of two expressions.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ Expr *E1, Expr *E2) {
+ if (!E1 || !E2)
+ return E1 == E2;
+
+ // FIXME: Actually perform a structural comparison!
+ return true;
+}
+
+/// \brief Determine whether two identifiers are equivalent.
+static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
+ const IdentifierInfo *Name2) {
+ if (!Name1 || !Name2)
+ return Name1 == Name2;
+
+ return Name1->getName() == Name2->getName();
+}
+
+/// \brief Determine whether two nested-name-specifiers are equivalent.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ NestedNameSpecifier *NNS1,
+ NestedNameSpecifier *NNS2) {
+ // FIXME: Implement!
+ return true;
+}
+
+/// \brief Determine whether two template arguments are equivalent.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const TemplateArgument &Arg1,
+ const TemplateArgument &Arg2) {
+ // FIXME: Implement!
+ return true;
+}
+
+/// \brief Determine structural equivalence for the common part of array
+/// types.
+static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const ArrayType *Array1,
+ const ArrayType *Array2) {
+ if (!IsStructurallyEquivalent(Context,
+ Array1->getElementType(),
+ Array2->getElementType()))
+ return false;
+ if (Array1->getSizeModifier() != Array2->getSizeModifier())
+ return false;
+ if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers())
+ return false;
+
+ return true;
+}
+
+/// \brief Determine structural equivalence of two types.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ QualType T1, QualType T2) {
+ if (T1.isNull() || T2.isNull())
+ return T1.isNull() && T2.isNull();
+
+ if (!Context.StrictTypeSpelling) {
+ // We aren't being strict about token-to-token equivalence of types,
+ // so map down to the canonical type.
+ T1 = Context.C1.getCanonicalType(T1);
+ T2 = Context.C2.getCanonicalType(T2);
+ }
+
+ if (T1.getQualifiers() != T2.getQualifiers())
+ return false;
+
+ Type::TypeClass TC = T1->getTypeClass();
+
+ if (T1->getTypeClass() != T2->getTypeClass()) {
+ // Compare function types with prototypes vs. without prototypes as if
+ // both did not have prototypes.
+ if (T1->getTypeClass() == Type::FunctionProto &&
+ T2->getTypeClass() == Type::FunctionNoProto)
+ TC = Type::FunctionNoProto;
+ else if (T1->getTypeClass() == Type::FunctionNoProto &&
+ T2->getTypeClass() == Type::FunctionProto)
+ TC = Type::FunctionNoProto;
+ else
+ return false;
+ }
+
+ switch (TC) {
+ case Type::Builtin:
+ // FIXME: Deal with Char_S/Char_U.
+ if (cast<BuiltinType>(T1)->getKind() != cast<BuiltinType>(T2)->getKind())
+ return false;
+ break;
+
+ case Type::Complex:
+ if (!IsStructurallyEquivalent(Context,
+ cast<ComplexType>(T1)->getElementType(),
+ cast<ComplexType>(T2)->getElementType()))
+ return false;
+ break;
+
+ case Type::Pointer:
+ if (!IsStructurallyEquivalent(Context,
+ cast<PointerType>(T1)->getPointeeType(),
+ cast<PointerType>(T2)->getPointeeType()))
+ return false;
+ break;
+
+ case Type::BlockPointer:
+ if (!IsStructurallyEquivalent(Context,
+ cast<BlockPointerType>(T1)->getPointeeType(),
+ cast<BlockPointerType>(T2)->getPointeeType()))
+ return false;
+ break;
+
+ case Type::LValueReference:
+ case Type::RValueReference: {
+ const ReferenceType *Ref1 = cast<ReferenceType>(T1);
+ const ReferenceType *Ref2 = cast<ReferenceType>(T2);
+ if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue())
+ return false;
+ if (Ref1->isInnerRef() != Ref2->isInnerRef())
+ return false;
+ if (!IsStructurallyEquivalent(Context,
+ Ref1->getPointeeTypeAsWritten(),
+ Ref2->getPointeeTypeAsWritten()))
+ return false;
+ break;
+ }
+
+ case Type::MemberPointer: {
+ const MemberPointerType *MemPtr1 = cast<MemberPointerType>(T1);
+ const MemberPointerType *MemPtr2 = cast<MemberPointerType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ MemPtr1->getPointeeType(),
+ MemPtr2->getPointeeType()))
+ return false;
+ if (!IsStructurallyEquivalent(Context,
+ QualType(MemPtr1->getClass(), 0),
+ QualType(MemPtr2->getClass(), 0)))
+ return false;
+ break;
+ }
+
+ case Type::ConstantArray: {
+ const ConstantArrayType *Array1 = cast<ConstantArrayType>(T1);
+ const ConstantArrayType *Array2 = cast<ConstantArrayType>(T2);
+ if (!IsSameValue(Array1->getSize(), Array2->getSize()))
+ return false;
+
+ if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
+ return false;
+ break;
+ }
+
+ case Type::IncompleteArray:
+ if (!IsArrayStructurallyEquivalent(Context,
+ cast<ArrayType>(T1),
+ cast<ArrayType>(T2)))
+ return false;
+ break;
+
+ case Type::VariableArray: {
+ const VariableArrayType *Array1 = cast<VariableArrayType>(T1);
+ const VariableArrayType *Array2 = cast<VariableArrayType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Array1->getSizeExpr(), Array2->getSizeExpr()))
+ return false;
+
+ if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
+ return false;
+
+ break;
+ }
+
+ case Type::DependentSizedArray: {
+ const DependentSizedArrayType *Array1 = cast<DependentSizedArrayType>(T1);
+ const DependentSizedArrayType *Array2 = cast<DependentSizedArrayType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Array1->getSizeExpr(), Array2->getSizeExpr()))
+ return false;
+
+ if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
+ return false;
+
+ break;
+ }
+
+ case Type::DependentSizedExtVector: {
+ const DependentSizedExtVectorType *Vec1
+ = cast<DependentSizedExtVectorType>(T1);
+ const DependentSizedExtVectorType *Vec2
+ = cast<DependentSizedExtVectorType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Vec1->getSizeExpr(), Vec2->getSizeExpr()))
+ return false;
+ if (!IsStructurallyEquivalent(Context,
+ Vec1->getElementType(),
+ Vec2->getElementType()))
+ return false;
+ break;
+ }
+
+ case Type::Vector:
+ case Type::ExtVector: {
+ const VectorType *Vec1 = cast<VectorType>(T1);
+ const VectorType *Vec2 = cast<VectorType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Vec1->getElementType(),
+ Vec2->getElementType()))
+ return false;
+ if (Vec1->getNumElements() != Vec2->getNumElements())
+ return false;
+ if (Vec1->isAltiVec() != Vec2->isAltiVec())
+ return false;
+ if (Vec1->isPixel() != Vec2->isPixel())
+ return false;
+ }
+
+ case Type::FunctionProto: {
+ const FunctionProtoType *Proto1 = cast<FunctionProtoType>(T1);
+ const FunctionProtoType *Proto2 = cast<FunctionProtoType>(T2);
+ if (Proto1->getNumArgs() != Proto2->getNumArgs())
+ return false;
+ for (unsigned I = 0, N = Proto1->getNumArgs(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context,
+ Proto1->getArgType(I),
+ Proto2->getArgType(I)))
+ return false;
+ }
+ if (Proto1->isVariadic() != Proto2->isVariadic())
+ return false;
+ if (Proto1->hasExceptionSpec() != Proto2->hasExceptionSpec())
+ return false;
+ if (Proto1->hasAnyExceptionSpec() != Proto2->hasAnyExceptionSpec())
+ return false;
+ if (Proto1->getNumExceptions() != Proto2->getNumExceptions())
+ return false;
+ for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context,
+ Proto1->getExceptionType(I),
+ Proto2->getExceptionType(I)))
+ return false;
+ }
+ if (Proto1->getTypeQuals() != Proto2->getTypeQuals())
+ return false;
+
+ // Fall through to check the bits common with FunctionNoProtoType.
+ }
+
+ case Type::FunctionNoProto: {
+ const FunctionType *Function1 = cast<FunctionType>(T1);
+ const FunctionType *Function2 = cast<FunctionType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Function1->getResultType(),
+ Function2->getResultType()))
+ return false;
+ if (Function1->getNoReturnAttr() != Function2->getNoReturnAttr())
+ return false;
+ if (Function1->getCallConv() != Function2->getCallConv())
+ return false;
+ break;
+ }
+
+ case Type::UnresolvedUsing:
+ if (!IsStructurallyEquivalent(Context,
+ cast<UnresolvedUsingType>(T1)->getDecl(),
+ cast<UnresolvedUsingType>(T2)->getDecl()))
+ return false;
+
+ break;
+
+ case Type::Typedef:
+ if (!IsStructurallyEquivalent(Context,
+ cast<TypedefType>(T1)->getDecl(),
+ cast<TypedefType>(T2)->getDecl()))
+ return false;
+ break;
+
+ case Type::TypeOfExpr:
+ if (!IsStructurallyEquivalent(Context,
+ cast<TypeOfExprType>(T1)->getUnderlyingExpr(),
+ cast<TypeOfExprType>(T2)->getUnderlyingExpr()))
+ return false;
+ break;
+
+ case Type::TypeOf:
+ if (!IsStructurallyEquivalent(Context,
+ cast<TypeOfType>(T1)->getUnderlyingType(),
+ cast<TypeOfType>(T2)->getUnderlyingType()))
+ return false;
+ break;
+
+ case Type::Decltype:
+ if (!IsStructurallyEquivalent(Context,
+ cast<DecltypeType>(T1)->getUnderlyingExpr(),
+ cast<DecltypeType>(T2)->getUnderlyingExpr()))
+ return false;
+ break;
+
+ case Type::Record:
+ case Type::Enum:
+ if (!IsStructurallyEquivalent(Context,
+ cast<TagType>(T1)->getDecl(),
+ cast<TagType>(T2)->getDecl()))
+ return false;
+ break;
+
+ case Type::Elaborated: {
+ const ElaboratedType *Elab1 = cast<ElaboratedType>(T1);
+ const ElaboratedType *Elab2 = cast<ElaboratedType>(T2);
+ if (Elab1->getTagKind() != Elab2->getTagKind())
+ return false;
+ if (!IsStructurallyEquivalent(Context,
+ Elab1->getUnderlyingType(),
+ Elab2->getUnderlyingType()))
+ return false;
+ break;
+ }
+
+ case Type::TemplateTypeParm: {
+ const TemplateTypeParmType *Parm1 = cast<TemplateTypeParmType>(T1);
+ const TemplateTypeParmType *Parm2 = cast<TemplateTypeParmType>(T2);
+ if (Parm1->getDepth() != Parm2->getDepth())
+ return false;
+ if (Parm1->getIndex() != Parm2->getIndex())
+ return false;
+ if (Parm1->isParameterPack() != Parm2->isParameterPack())
+ return false;
+
+ // Names of template type parameters are never significant.
+ break;
+ }
+
+ case Type::SubstTemplateTypeParm: {
+ const SubstTemplateTypeParmType *Subst1
+ = cast<SubstTemplateTypeParmType>(T1);
+ const SubstTemplateTypeParmType *Subst2
+ = cast<SubstTemplateTypeParmType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ QualType(Subst1->getReplacedParameter(), 0),
+ QualType(Subst2->getReplacedParameter(), 0)))
+ return false;
+ if (!IsStructurallyEquivalent(Context,
+ Subst1->getReplacementType(),
+ Subst2->getReplacementType()))
+ return false;
+ break;
+ }
+
+ case Type::TemplateSpecialization: {
+ const TemplateSpecializationType *Spec1
+ = cast<TemplateSpecializationType>(T1);
+ const TemplateSpecializationType *Spec2
+ = cast<TemplateSpecializationType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Spec1->getTemplateName(),
+ Spec2->getTemplateName()))
+ return false;
+ if (Spec1->getNumArgs() != Spec2->getNumArgs())
+ return false;
+ for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context,
+ Spec1->getArg(I), Spec2->getArg(I)))
+ return false;
+ }
+ break;
+ }
+
+ case Type::QualifiedName: {
+ const QualifiedNameType *Qual1 = cast<QualifiedNameType>(T1);
+ const QualifiedNameType *Qual2 = cast<QualifiedNameType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Qual1->getQualifier(),
+ Qual2->getQualifier()))
+ return false;
+ if (!IsStructurallyEquivalent(Context,
+ Qual1->getNamedType(),
+ Qual2->getNamedType()))
+ return false;
+ break;
+ }
+
+ case Type::Typename: {
+ const TypenameType *Typename1 = cast<TypenameType>(T1);
+ const TypenameType *Typename2 = cast<TypenameType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Typename1->getQualifier(),
+ Typename2->getQualifier()))
+ return false;
+ if (!IsStructurallyEquivalent(Typename1->getIdentifier(),
+ Typename2->getIdentifier()))
+ return false;
+ if (!IsStructurallyEquivalent(Context,
+ QualType(Typename1->getTemplateId(), 0),
+ QualType(Typename2->getTemplateId(), 0)))
+ return false;
+
+ break;
+ }
+
+ case Type::ObjCInterface: {
+ const ObjCInterfaceType *Iface1 = cast<ObjCInterfaceType>(T1);
+ const ObjCInterfaceType *Iface2 = cast<ObjCInterfaceType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Iface1->getDecl(), Iface2->getDecl()))
+ return false;
+ if (Iface1->getNumProtocols() != Iface2->getNumProtocols())
+ return false;
+ for (unsigned I = 0, N = Iface1->getNumProtocols(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context,
+ Iface1->getProtocol(I),
+ Iface2->getProtocol(I)))
+ return false;
+ }
+ break;
+ }
+
+ case Type::ObjCObjectPointer: {
+ const ObjCObjectPointerType *Ptr1 = cast<ObjCObjectPointerType>(T1);
+ const ObjCObjectPointerType *Ptr2 = cast<ObjCObjectPointerType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Ptr1->getPointeeType(),
+ Ptr2->getPointeeType()))
+ return false;
+ if (Ptr1->getNumProtocols() != Ptr2->getNumProtocols())
+ return false;
+ for (unsigned I = 0, N = Ptr1->getNumProtocols(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context,
+ Ptr1->getProtocol(I),
+ Ptr2->getProtocol(I)))
+ return false;
+ }
+ break;
+ }
+
+ } // end switch
+
+ return true;
+}
+
+/// \brief Determine structural equivalence of two records.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ RecordDecl *D1, RecordDecl *D2) {
+ if (D1->isUnion() != D2->isUnion()) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)
+ << D1->getDeclName() << (unsigned)D1->getTagKind();
+ return false;
+ }
+
+ // Compare the definitions of these two records. If either or both are
+ // incomplete, we assume that they are equivalent.
+ D1 = D1->getDefinition();
+ D2 = D2->getDefinition();
+ if (!D1 || !D2)
+ return true;
+
+ if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D1)) {
+ if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) {
+ if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
+ << D2CXX->getNumBases();
+ Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)
+ << D1CXX->getNumBases();
+ return false;
+ }
+
+ // Check the base classes.
+ for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(),
+ BaseEnd1 = D1CXX->bases_end(),
+ Base2 = D2CXX->bases_begin();
+ Base1 != BaseEnd1;
+ ++Base1, ++Base2) {
+ if (!IsStructurallyEquivalent(Context,
+ Base1->getType(), Base2->getType())) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(Base2->getSourceRange().getBegin(), diag::note_odr_base)
+ << Base2->getType()
+ << Base2->getSourceRange();
+ Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base)
+ << Base1->getType()
+ << Base1->getSourceRange();
+ return false;
+ }
+
+ // Check virtual vs. non-virtual inheritance mismatch.
+ if (Base1->isVirtual() != Base2->isVirtual()) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(Base2->getSourceRange().getBegin(),
+ diag::note_odr_virtual_base)
+ << Base2->isVirtual() << Base2->getSourceRange();
+ Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base)
+ << Base1->isVirtual()
+ << Base1->getSourceRange();
+ return false;
+ }
+ }
+ } else if (D1CXX->getNumBases() > 0) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();
+ Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base)
+ << Base1->getType()
+ << Base1->getSourceRange();
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_base);
+ return false;
+ }
+ }
+
+ // Check the fields for consistency.
+ CXXRecordDecl::field_iterator Field2 = D2->field_begin(),
+ Field2End = D2->field_end();
+ for (CXXRecordDecl::field_iterator Field1 = D1->field_begin(),
+ Field1End = D1->field_end();
+ Field1 != Field1End;
+ ++Field1, ++Field2) {
+ if (Field2 == Field2End) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag1(Field1->getLocation(), diag::note_odr_field)
+ << Field1->getDeclName() << Field1->getType();
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_field);
+ return false;
+ }
+
+ if (!IsStructurallyEquivalent(Context,
+ Field1->getType(), Field2->getType())) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_field)
+ << Field2->getDeclName() << Field2->getType();
+ Context.Diag1(Field1->getLocation(), diag::note_odr_field)
+ << Field1->getDeclName() << Field1->getType();
+ return false;
+ }
+
+ if (Field1->isBitField() != Field2->isBitField()) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ if (Field1->isBitField()) {
+ llvm::APSInt Bits;
+ Field1->getBitWidth()->isIntegerConstantExpr(Bits, Context.C1);
+ Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
+ << Field1->getDeclName() << Field1->getType()
+ << Bits.toString(10, false);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field)
+ << Field2->getDeclName();
+ } else {
+ llvm::APSInt Bits;
+ Field2->getBitWidth()->isIntegerConstantExpr(Bits, Context.C2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
+ << Field2->getDeclName() << Field2->getType()
+ << Bits.toString(10, false);
+ Context.Diag1(Field1->getLocation(),
+ diag::note_odr_not_bit_field)
+ << Field1->getDeclName();
+ }
+ return false;
+ }
+
+ if (Field1->isBitField()) {
+ // Make sure that the bit-fields are the same length.
+ llvm::APSInt Bits1, Bits2;
+ if (!Field1->getBitWidth()->isIntegerConstantExpr(Bits1, Context.C1))
+ return false;
+ if (!Field2->getBitWidth()->isIntegerConstantExpr(Bits2, Context.C2))
+ return false;
+
+ if (!IsSameValue(Bits1, Bits2)) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
+ << Field2->getDeclName() << Field2->getType()
+ << Bits2.toString(10, false);
+ Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
+ << Field1->getDeclName() << Field1->getType()
+ << Bits1.toString(10, false);
+ return false;
+ }
+ }
+ }
+
+ if (Field2 != Field2End) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_field)
+ << Field2->getDeclName() << Field2->getType();
+ Context.Diag1(D1->getLocation(), diag::note_odr_missing_field);
+ return false;
+ }
+
+ return true;
+}
+
+/// \brief Determine structural equivalence of two enums.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ EnumDecl *D1, EnumDecl *D2) {
+ EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(),
+ EC2End = D2->enumerator_end();
+ for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(),
+ EC1End = D1->enumerator_end();
+ EC1 != EC1End; ++EC1, ++EC2) {
+ if (EC2 == EC2End) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
+ << EC1->getDeclName()
+ << EC1->getInitVal().toString(10);
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator);
+ return false;
+ }
+
+ llvm::APSInt Val1 = EC1->getInitVal();
+ llvm::APSInt Val2 = EC2->getInitVal();
+ if (!IsSameValue(Val1, Val2) ||
+ !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
+ << EC2->getDeclName()
+ << EC2->getInitVal().toString(10);
+ Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
+ << EC1->getDeclName()
+ << EC1->getInitVal().toString(10);
+ return false;
+ }
+ }
+
+ if (EC2 != EC2End) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
+ << EC2->getDeclName()
+ << EC2->getInitVal().toString(10);
+ Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator);
+ return false;
+ }
+
+ return true;
+}
+
+/// \brief Determine structural equivalence of two declarations.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ Decl *D1, Decl *D2) {
+ // FIXME: Check for known structural equivalences via a callback of some sort.
+
+ // Check whether we already know that these two declarations are not
+ // structurally equivalent.
+ if (Context.NonEquivalentDecls.count(std::make_pair(D1->getCanonicalDecl(),
+ D2->getCanonicalDecl())))
+ return false;
+
+ // Determine whether we've already produced a tentative equivalence for D1.
+ Decl *&EquivToD1 = Context.TentativeEquivalences[D1->getCanonicalDecl()];
+ if (EquivToD1)
+ return EquivToD1 == D2->getCanonicalDecl();
+
+ // Produce a tentative equivalence D1 <-> D2, which will be checked later.
+ EquivToD1 = D2->getCanonicalDecl();
+ Context.DeclsToCheck.push_back(D1->getCanonicalDecl());
+ return true;
+}
+
+bool StructuralEquivalenceContext::IsStructurallyEquivalent(Decl *D1,
+ Decl *D2) {
+ if (!::IsStructurallyEquivalent(*this, D1, D2))
+ return false;
+
+ return !Finish();
+}
+
+bool StructuralEquivalenceContext::IsStructurallyEquivalent(QualType T1,
+ QualType T2) {
+ if (!::IsStructurallyEquivalent(*this, T1, T2))
+ return false;
+
+ return !Finish();
+}
+
+bool StructuralEquivalenceContext::Finish() {
+ while (!DeclsToCheck.empty()) {
+ // Check the next declaration.
+ Decl *D1 = DeclsToCheck.front();
+ DeclsToCheck.pop_front();
+
+ Decl *D2 = TentativeEquivalences[D1];
+ assert(D2 && "Unrecorded tentative equivalence?");
+
+ bool Equivalent = true;
+
+ // FIXME: Switch on all declaration kinds. For now, we're just going to
+ // check the obvious ones.
+ if (RecordDecl *Record1 = dyn_cast<RecordDecl>(D1)) {
+ if (RecordDecl *Record2 = dyn_cast<RecordDecl>(D2)) {
+ // Check for equivalent structure names.
+ IdentifierInfo *Name1 = Record1->getIdentifier();
+ if (!Name1 && Record1->getTypedefForAnonDecl())
+ Name1 = Record1->getTypedefForAnonDecl()->getIdentifier();
+ IdentifierInfo *Name2 = Record2->getIdentifier();
+ if (!Name2 && Record2->getTypedefForAnonDecl())
+ Name2 = Record2->getTypedefForAnonDecl()->getIdentifier();
+ if (!::IsStructurallyEquivalent(Name1, Name2) ||
+ !::IsStructurallyEquivalent(*this, Record1, Record2))
+ Equivalent = false;
+ } else {
+ // Record/non-record mismatch.
+ Equivalent = false;
+ }
+ } else if (EnumDecl *Enum1 = dyn_cast<EnumDecl>(D1)) {
+ if (EnumDecl *Enum2 = dyn_cast<EnumDecl>(D2)) {
+ // Check for equivalent enum names.
+ IdentifierInfo *Name1 = Enum1->getIdentifier();
+ if (!Name1 && Enum1->getTypedefForAnonDecl())
+ Name1 = Enum1->getTypedefForAnonDecl()->getIdentifier();
+ IdentifierInfo *Name2 = Enum2->getIdentifier();
+ if (!Name2 && Enum2->getTypedefForAnonDecl())
+ Name2 = Enum2->getTypedefForAnonDecl()->getIdentifier();
+ if (!::IsStructurallyEquivalent(Name1, Name2) ||
+ !::IsStructurallyEquivalent(*this, Enum1, Enum2))
+ Equivalent = false;
+ } else {
+ // Enum/non-enum mismatch
+ Equivalent = false;
+ }
+ } else if (TypedefDecl *Typedef1 = dyn_cast<TypedefDecl>(D1)) {
+ if (TypedefDecl *Typedef2 = dyn_cast<TypedefDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(),
+ Typedef2->getIdentifier()) ||
+ !::IsStructurallyEquivalent(*this,
+ Typedef1->getUnderlyingType(),
+ Typedef2->getUnderlyingType()))
+ Equivalent = false;
+ } else {
+ // Typedef/non-typedef mismatch.
+ Equivalent = false;
+ }
+ }
+
+ if (!Equivalent) {
+ // Note that these two declarations are not equivalent (and we already
+ // know about it).
+ NonEquivalentDecls.insert(std::make_pair(D1->getCanonicalDecl(),
+ D2->getCanonicalDecl()));
+ return true;
+ }
+ // FIXME: Check other declaration kinds!
+ }
+
+ return false;
+}
+
+//----------------------------------------------------------------------------
+// Import Types
+//----------------------------------------------------------------------------
+
+QualType ASTNodeImporter::VisitType(Type *T) {
+ Importer.FromDiag(SourceLocation(), diag::err_unsupported_ast_node)
+ << T->getTypeClassName();
+ return QualType();
+}
+
+QualType ASTNodeImporter::VisitBuiltinType(BuiltinType *T) {
+ switch (T->getKind()) {
+ case BuiltinType::Void: return Importer.getToContext().VoidTy;
+ case BuiltinType::Bool: return Importer.getToContext().BoolTy;
+
+ case BuiltinType::Char_U:
+ // The context we're importing from has an unsigned 'char'. If we're
+ // importing into a context with a signed 'char', translate to
+ // 'unsigned char' instead.
+ if (Importer.getToContext().getLangOptions().CharIsSigned)
+ return Importer.getToContext().UnsignedCharTy;
+
+ return Importer.getToContext().CharTy;
+
+ case BuiltinType::UChar: return Importer.getToContext().UnsignedCharTy;
+
+ case BuiltinType::Char16:
+ // FIXME: Make sure that the "to" context supports C++!
+ return Importer.getToContext().Char16Ty;
+
+ case BuiltinType::Char32:
+ // FIXME: Make sure that the "to" context supports C++!
+ return Importer.getToContext().Char32Ty;
+
+ case BuiltinType::UShort: return Importer.getToContext().UnsignedShortTy;
+ case BuiltinType::UInt: return Importer.getToContext().UnsignedIntTy;
+ case BuiltinType::ULong: return Importer.getToContext().UnsignedLongTy;
+ case BuiltinType::ULongLong:
+ return Importer.getToContext().UnsignedLongLongTy;
+ case BuiltinType::UInt128: return Importer.getToContext().UnsignedInt128Ty;
+
+ case BuiltinType::Char_S:
+ // The context we're importing from has an unsigned 'char'. If we're
+ // importing into a context with a signed 'char', translate to
+ // 'unsigned char' instead.
+ if (!Importer.getToContext().getLangOptions().CharIsSigned)
+ return Importer.getToContext().SignedCharTy;
+
+ return Importer.getToContext().CharTy;
+
+ case BuiltinType::SChar: return Importer.getToContext().SignedCharTy;
+ case BuiltinType::WChar:
+ // FIXME: If not in C++, shall we translate to the C equivalent of
+ // wchar_t?
+ return Importer.getToContext().WCharTy;
+
+ case BuiltinType::Short : return Importer.getToContext().ShortTy;
+ case BuiltinType::Int : return Importer.getToContext().IntTy;
+ case BuiltinType::Long : return Importer.getToContext().LongTy;
+ case BuiltinType::LongLong : return Importer.getToContext().LongLongTy;
+ case BuiltinType::Int128 : return Importer.getToContext().Int128Ty;
+ case BuiltinType::Float: return Importer.getToContext().FloatTy;
+ case BuiltinType::Double: return Importer.getToContext().DoubleTy;
+ case BuiltinType::LongDouble: return Importer.getToContext().LongDoubleTy;
+
+ case BuiltinType::NullPtr:
+ // FIXME: Make sure that the "to" context supports C++0x!
+ return Importer.getToContext().NullPtrTy;
+
+ case BuiltinType::Overload: return Importer.getToContext().OverloadTy;
+ case BuiltinType::Dependent: return Importer.getToContext().DependentTy;
+ case BuiltinType::UndeducedAuto:
+ // FIXME: Make sure that the "to" context supports C++0x!
+ return Importer.getToContext().UndeducedAutoTy;
+
+ case BuiltinType::ObjCId:
+ // FIXME: Make sure that the "to" context supports Objective-C!
+ return Importer.getToContext().ObjCBuiltinIdTy;
+
+ case BuiltinType::ObjCClass:
+ return Importer.getToContext().ObjCBuiltinClassTy;
+
+ case BuiltinType::ObjCSel:
+ return Importer.getToContext().ObjCBuiltinSelTy;
+ }
+
+ return QualType();
+}
+
+QualType ASTNodeImporter::VisitComplexType(ComplexType *T) {
+ QualType ToElementType = Importer.Import(T->getElementType());
+ if (ToElementType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getComplexType(ToElementType);
+}
+
+QualType ASTNodeImporter::VisitPointerType(PointerType *T) {
+ QualType ToPointeeType = Importer.Import(T->getPointeeType());
+ if (ToPointeeType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getPointerType(ToPointeeType);
+}
+
+QualType ASTNodeImporter::VisitBlockPointerType(BlockPointerType *T) {
+ // FIXME: Check for blocks support in "to" context.
+ QualType ToPointeeType = Importer.Import(T->getPointeeType());
+ if (ToPointeeType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getBlockPointerType(ToPointeeType);
+}
+
+QualType ASTNodeImporter::VisitLValueReferenceType(LValueReferenceType *T) {
+ // FIXME: Check for C++ support in "to" context.
+ QualType ToPointeeType = Importer.Import(T->getPointeeTypeAsWritten());
+ if (ToPointeeType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getLValueReferenceType(ToPointeeType);
+}
+
+QualType ASTNodeImporter::VisitRValueReferenceType(RValueReferenceType *T) {
+ // FIXME: Check for C++0x support in "to" context.
+ QualType ToPointeeType = Importer.Import(T->getPointeeTypeAsWritten());
+ if (ToPointeeType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getRValueReferenceType(ToPointeeType);
+}
+
+QualType ASTNodeImporter::VisitMemberPointerType(MemberPointerType *T) {
+ // FIXME: Check for C++ support in "to" context.
+ QualType ToPointeeType = Importer.Import(T->getPointeeType());
+ if (ToPointeeType.isNull())
+ return QualType();
+
+ QualType ClassType = Importer.Import(QualType(T->getClass(), 0));
+ return Importer.getToContext().getMemberPointerType(ToPointeeType,
+ ClassType.getTypePtr());
+}
+
+QualType ASTNodeImporter::VisitConstantArrayType(ConstantArrayType *T) {
+ QualType ToElementType = Importer.Import(T->getElementType());
+ if (ToElementType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getConstantArrayType(ToElementType,
+ T->getSize(),
+ T->getSizeModifier(),
+ T->getIndexTypeCVRQualifiers());
+}
+
+QualType ASTNodeImporter::VisitIncompleteArrayType(IncompleteArrayType *T) {
+ QualType ToElementType = Importer.Import(T->getElementType());
+ if (ToElementType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getIncompleteArrayType(ToElementType,
+ T->getSizeModifier(),
+ T->getIndexTypeCVRQualifiers());
+}
+
+QualType ASTNodeImporter::VisitVariableArrayType(VariableArrayType *T) {
+ QualType ToElementType = Importer.Import(T->getElementType());
+ if (ToElementType.isNull())
+ return QualType();
+
+ Expr *Size = Importer.Import(T->getSizeExpr());
+ if (!Size)
+ return QualType();
+
+ SourceRange Brackets = Importer.Import(T->getBracketsRange());
+ return Importer.getToContext().getVariableArrayType(ToElementType, Size,
+ T->getSizeModifier(),
+ T->getIndexTypeCVRQualifiers(),
+ Brackets);
+}
+
+QualType ASTNodeImporter::VisitVectorType(VectorType *T) {
+ QualType ToElementType = Importer.Import(T->getElementType());
+ if (ToElementType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getVectorType(ToElementType,
+ T->getNumElements(),
+ T->isAltiVec(),
+ T->isPixel());
+}
+
+QualType ASTNodeImporter::VisitExtVectorType(ExtVectorType *T) {
+ QualType ToElementType = Importer.Import(T->getElementType());
+ if (ToElementType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getExtVectorType(ToElementType,
+ T->getNumElements());
+}
+
+QualType ASTNodeImporter::VisitFunctionNoProtoType(FunctionNoProtoType *T) {
+ // FIXME: What happens if we're importing a function without a prototype
+ // into C++? Should we make it variadic?
+ QualType ToResultType = Importer.Import(T->getResultType());
+ if (ToResultType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getFunctionNoProtoType(ToResultType,
+ T->getNoReturnAttr(),
+ T->getCallConv());
+}
+
+QualType ASTNodeImporter::VisitFunctionProtoType(FunctionProtoType *T) {
+ QualType ToResultType = Importer.Import(T->getResultType());
+ if (ToResultType.isNull())
+ return QualType();
+
+ // Import argument types
+ llvm::SmallVector<QualType, 4> ArgTypes;
+ for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(),
+ AEnd = T->arg_type_end();
+ A != AEnd; ++A) {
+ QualType ArgType = Importer.Import(*A);
+ if (ArgType.isNull())
+ return QualType();
+ ArgTypes.push_back(ArgType);
+ }
+
+ // Import exception types
+ llvm::SmallVector<QualType, 4> ExceptionTypes;
+ for (FunctionProtoType::exception_iterator E = T->exception_begin(),
+ EEnd = T->exception_end();
+ E != EEnd; ++E) {
+ QualType ExceptionType = Importer.Import(*E);
+ if (ExceptionType.isNull())
+ return QualType();
+ ExceptionTypes.push_back(ExceptionType);
+ }
+
+ return Importer.getToContext().getFunctionType(ToResultType, ArgTypes.data(),
+ ArgTypes.size(),
+ T->isVariadic(),
+ T->getTypeQuals(),
+ T->hasExceptionSpec(),
+ T->hasAnyExceptionSpec(),
+ ExceptionTypes.size(),
+ ExceptionTypes.data(),
+ T->getNoReturnAttr(),
+ T->getCallConv());
+}
+
+QualType ASTNodeImporter::VisitTypedefType(TypedefType *T) {
+ TypedefDecl *ToDecl
+ = dyn_cast_or_null<TypedefDecl>(Importer.Import(T->getDecl()));
+ if (!ToDecl)
+ return QualType();
+
+ return Importer.getToContext().getTypeDeclType(ToDecl);
+}
+
+QualType ASTNodeImporter::VisitTypeOfExprType(TypeOfExprType *T) {
+ Expr *ToExpr = Importer.Import(T->getUnderlyingExpr());
+ if (!ToExpr)
+ return QualType();
+
+ return Importer.getToContext().getTypeOfExprType(ToExpr);
+}
+
+QualType ASTNodeImporter::VisitTypeOfType(TypeOfType *T) {
+ QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType());
+ if (ToUnderlyingType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getTypeOfType(ToUnderlyingType);
+}
+
+QualType ASTNodeImporter::VisitDecltypeType(DecltypeType *T) {
+ Expr *ToExpr = Importer.Import(T->getUnderlyingExpr());
+ if (!ToExpr)
+ return QualType();
+
+ return Importer.getToContext().getDecltypeType(ToExpr);
+}
+
+QualType ASTNodeImporter::VisitRecordType(RecordType *T) {
+ RecordDecl *ToDecl
+ = dyn_cast_or_null<RecordDecl>(Importer.Import(T->getDecl()));
+ if (!ToDecl)
+ return QualType();
+
+ return Importer.getToContext().getTagDeclType(ToDecl);
+}
+
+QualType ASTNodeImporter::VisitEnumType(EnumType *T) {
+ EnumDecl *ToDecl
+ = dyn_cast_or_null<EnumDecl>(Importer.Import(T->getDecl()));
+ if (!ToDecl)
+ return QualType();
+
+ return Importer.getToContext().getTagDeclType(ToDecl);
+}
+
+QualType ASTNodeImporter::VisitElaboratedType(ElaboratedType *T) {
+ QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType());
+ if (ToUnderlyingType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getElaboratedType(ToUnderlyingType,
+ T->getTagKind());
+}
+
+QualType ASTNodeImporter::VisitQualifiedNameType(QualifiedNameType *T) {
+ NestedNameSpecifier *ToQualifier = Importer.Import(T->getQualifier());
+ if (!ToQualifier)
+ return QualType();
+
+ QualType ToNamedType = Importer.Import(T->getNamedType());
+ if (ToNamedType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getQualifiedNameType(ToQualifier, ToNamedType);
+}
+
+QualType ASTNodeImporter::VisitObjCInterfaceType(ObjCInterfaceType *T) {
+ ObjCInterfaceDecl *Class
+ = dyn_cast_or_null<ObjCInterfaceDecl>(Importer.Import(T->getDecl()));
+ if (!Class)
+ return QualType();
+
+ llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols;
+ for (ObjCInterfaceType::qual_iterator P = T->qual_begin(),
+ PEnd = T->qual_end();
+ P != PEnd; ++P) {
+ ObjCProtocolDecl *Protocol
+ = dyn_cast_or_null<ObjCProtocolDecl>(Importer.Import(*P));
+ if (!Protocol)
+ return QualType();
+ Protocols.push_back(Protocol);
+ }
+
+ return Importer.getToContext().getObjCInterfaceType(Class,
+ Protocols.data(),
+ Protocols.size());
+}
+
+QualType ASTNodeImporter::VisitObjCObjectPointerType(ObjCObjectPointerType *T) {
+ QualType ToPointeeType = Importer.Import(T->getPointeeType());
+ if (ToPointeeType.isNull())
+ return QualType();
+
+ llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols;
+ for (ObjCObjectPointerType::qual_iterator P = T->qual_begin(),
+ PEnd = T->qual_end();
+ P != PEnd; ++P) {
+ ObjCProtocolDecl *Protocol
+ = dyn_cast_or_null<ObjCProtocolDecl>(Importer.Import(*P));
+ if (!Protocol)
+ return QualType();
+ Protocols.push_back(Protocol);
+ }
+
+ return Importer.getToContext().getObjCObjectPointerType(ToPointeeType,
+ Protocols.data(),
+ Protocols.size());
+}
+
+//----------------------------------------------------------------------------
+// Import Declarations
+//----------------------------------------------------------------------------
+bool ASTNodeImporter::ImportDeclParts(NamedDecl *D, DeclContext *&DC,
+ DeclContext *&LexicalDC,
+ DeclarationName &Name,
+ SourceLocation &Loc) {
+ // Import the context of this declaration.
+ DC = Importer.ImportContext(D->getDeclContext());
+ if (!DC)
+ return true;
+
+ LexicalDC = DC;
+ if (D->getDeclContext() != D->getLexicalDeclContext()) {
+ LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
+ if (!LexicalDC)
+ return true;
+ }
+
+ // Import the name of this declaration.
+ Name = Importer.Import(D->getDeclName());
+ if (D->getDeclName() && !Name)
+ return true;
+
+ // Import the location of this declaration.
+ Loc = Importer.Import(D->getLocation());
+ return false;
+}
+
+bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord,
+ RecordDecl *ToRecord) {
+ StructuralEquivalenceContext SEC(Importer.getFromContext(),
+ Importer.getToContext(),
+ Importer.getDiags(),
+ Importer.getNonEquivalentDecls());
+ return SEC.IsStructurallyEquivalent(FromRecord, ToRecord);
+}
+
+bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) {
+ StructuralEquivalenceContext SEC(Importer.getFromContext(),
+ Importer.getToContext(),
+ Importer.getDiags(),
+ Importer.getNonEquivalentDecls());
+ return SEC.IsStructurallyEquivalent(FromEnum, ToEnum);
+}
+
+Decl *ASTNodeImporter::VisitDecl(Decl *D) {
+ Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node)
+ << D->getDeclKindName();
+ return 0;
+}
+
+Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
+ // Import the major distinguishing characteristics of this typedef.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // If this typedef is not in block scope, determine whether we've
+ // seen a typedef with the same name (that we can merge with) or any
+ // other entity by that name (which name lookup could conflict with).
+ if (!DC->isFunctionOrMethod()) {
+ llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ unsigned IDNS = Decl::IDNS_Ordinary;
+ for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+ Lookup.first != Lookup.second;
+ ++Lookup.first) {
+ if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ continue;
+ if (TypedefDecl *FoundTypedef = dyn_cast<TypedefDecl>(*Lookup.first)) {
+ if (Importer.IsStructurallyEquivalent(D->getUnderlyingType(),
+ FoundTypedef->getUnderlyingType()))
+ return Importer.Imported(D, FoundTypedef);
+ }
+
+ ConflictingDecls.push_back(*Lookup.first);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, IDNS,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (!Name)
+ return 0;
+ }
+ }
+
+ // Import the underlying type of this typedef;
+ QualType T = Importer.Import(D->getUnderlyingType());
+ if (T.isNull())
+ return 0;
+
+ // Create the new typedef node.
+ TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+ TypedefDecl *ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC,
+ Loc, Name.getAsIdentifierInfo(),
+ TInfo);
+ ToTypedef->setLexicalDeclContext(LexicalDC);
+ Importer.Imported(D, ToTypedef);
+ LexicalDC->addDecl(ToTypedef);
+
+ return ToTypedef;
+}
+
+Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
+ // Import the major distinguishing characteristics of this enum.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // Figure out what enum name we're looking for.
+ unsigned IDNS = Decl::IDNS_Tag;
+ DeclarationName SearchName = Name;
+ if (!SearchName && D->getTypedefForAnonDecl()) {
+ SearchName = Importer.Import(D->getTypedefForAnonDecl()->getDeclName());
+ IDNS = Decl::IDNS_Ordinary;
+ } else if (Importer.getToContext().getLangOptions().CPlusPlus)
+ IDNS |= Decl::IDNS_Ordinary;
+
+ // We may already have an enum of the same name; try to find and match it.
+ if (!DC->isFunctionOrMethod() && SearchName) {
+ llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+ Lookup.first != Lookup.second;
+ ++Lookup.first) {
+ if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ continue;
+
+ Decl *Found = *Lookup.first;
+ if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Found)) {
+ if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>())
+ Found = Tag->getDecl();
+ }
+
+ if (EnumDecl *FoundEnum = dyn_cast<EnumDecl>(Found)) {
+ if (IsStructuralMatch(D, FoundEnum))
+ return Importer.Imported(D, FoundEnum);
+ }
+
+ ConflictingDecls.push_back(*Lookup.first);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, IDNS,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ }
+ }
+
+ // Create the enum declaration.
+ EnumDecl *D2 = EnumDecl::Create(Importer.getToContext(), DC, Loc,
+ Name.getAsIdentifierInfo(),
+ Importer.Import(D->getTagKeywordLoc()),
+ 0);
+ D2->setLexicalDeclContext(LexicalDC);
+ Importer.Imported(D, D2);
+ LexicalDC->addDecl(D2);
+
+ // Import the integer type.
+ QualType ToIntegerType = Importer.Import(D->getIntegerType());
+ if (ToIntegerType.isNull())
+ return 0;
+ D2->setIntegerType(ToIntegerType);
+
+ // Import the definition
+ if (D->isDefinition()) {
+ QualType T = Importer.Import(Importer.getFromContext().getTypeDeclType(D));
+ if (T.isNull())
+ return 0;
+
+ QualType ToPromotionType = Importer.Import(D->getPromotionType());
+ if (ToPromotionType.isNull())
+ return 0;
+
+ D2->startDefinition();
+ for (DeclContext::decl_iterator FromMem = D->decls_begin(),
+ FromMemEnd = D->decls_end();
+ FromMem != FromMemEnd;
+ ++FromMem)
+ Importer.Import(*FromMem);
+
+ D2->completeDefinition(T, ToPromotionType);
+ }
+
+ return D2;
+}
+
+Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
+ // If this record has a definition in the translation unit we're coming from,
+ // but this particular declaration is not that definition, import the
+ // definition and map to that.
+ TagDecl *Definition = D->getDefinition();
+ if (Definition && Definition != D) {
+ Decl *ImportedDef = Importer.Import(Definition);
+ if (!ImportedDef)
+ return 0;
+
+ return Importer.Imported(D, ImportedDef);
+ }
+
+ // Import the major distinguishing characteristics of this record.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // Figure out what structure name we're looking for.
+ unsigned IDNS = Decl::IDNS_Tag;
+ DeclarationName SearchName = Name;
+ if (!SearchName && D->getTypedefForAnonDecl()) {
+ SearchName = Importer.Import(D->getTypedefForAnonDecl()->getDeclName());
+ IDNS = Decl::IDNS_Ordinary;
+ } else if (Importer.getToContext().getLangOptions().CPlusPlus)
+ IDNS |= Decl::IDNS_Ordinary;
+
+ // We may already have a record of the same name; try to find and match it.
+ RecordDecl *AdoptDecl = 0;
+ if (!DC->isFunctionOrMethod() && SearchName) {
+ llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+ Lookup.first != Lookup.second;
+ ++Lookup.first) {
+ if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ continue;
+
+ Decl *Found = *Lookup.first;
+ if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Found)) {
+ if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>())
+ Found = Tag->getDecl();
+ }
+
+ if (RecordDecl *FoundRecord = dyn_cast<RecordDecl>(Found)) {
+ if (RecordDecl *FoundDef = FoundRecord->getDefinition()) {
+ if (!D->isDefinition() || IsStructuralMatch(D, FoundDef)) {
+ // The record types structurally match, or the "from" translation
+ // unit only had a forward declaration anyway; call it the same
+ // function.
+ // FIXME: For C++, we should also merge methods here.
+ return Importer.Imported(D, FoundDef);
+ }
+ } else {
+ // We have a forward declaration of this type, so adopt that forward
+ // declaration rather than building a new one.
+ AdoptDecl = FoundRecord;
+ continue;
+ }
+ }
+
+ ConflictingDecls.push_back(*Lookup.first);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, IDNS,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ }
+ }
+
+ // Create the record declaration.
+ RecordDecl *D2 = AdoptDecl;
+ if (!D2) {
+ if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D)) {
+ CXXRecordDecl *D2CXX = CXXRecordDecl::Create(Importer.getToContext(),
+ D->getTagKind(),
+ DC, Loc,
+ Name.getAsIdentifierInfo(),
+ Importer.Import(D->getTagKeywordLoc()));
+ D2 = D2CXX;
+
+ if (D->isDefinition()) {
+ // Add base classes.
+ llvm::SmallVector<CXXBaseSpecifier *, 4> Bases;
+ for (CXXRecordDecl::base_class_iterator
+ Base1 = D1CXX->bases_begin(),
+ FromBaseEnd = D1CXX->bases_end();
+ Base1 != FromBaseEnd;
+ ++Base1) {
+ QualType T = Importer.Import(Base1->getType());
+ if (T.isNull())
+ return 0;
+
+ Bases.push_back(
+ new (Importer.getToContext())
+ CXXBaseSpecifier(Importer.Import(Base1->getSourceRange()),
+ Base1->isVirtual(),
+ Base1->isBaseOfClass(),
+ Base1->getAccessSpecifierAsWritten(),
+ T));
+ }
+ if (!Bases.empty())
+ D2CXX->setBases(Bases.data(), Bases.size());
+ }
+ } else {
+ D2 = RecordDecl::Create(Importer.getToContext(), D->getTagKind(),
+ DC, Loc,
+ Name.getAsIdentifierInfo(),
+ Importer.Import(D->getTagKeywordLoc()));
+ }
+ D2->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDecl(D2);
+ }
+
+ Importer.Imported(D, D2);
+
+ if (D->isDefinition()) {
+ D2->startDefinition();
+ for (DeclContext::decl_iterator FromMem = D->decls_begin(),
+ FromMemEnd = D->decls_end();
+ FromMem != FromMemEnd;
+ ++FromMem)
+ Importer.Import(*FromMem);
+
+ D2->completeDefinition();
+ }
+
+ return D2;
+}
+
+Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) {
+ // Import the major distinguishing characteristics of this enumerator.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+
+ // Determine whether there are any other declarations with the same name and
+ // in the same context.
+ if (!LexicalDC->isFunctionOrMethod()) {
+ llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ unsigned IDNS = Decl::IDNS_Ordinary;
+ for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+ Lookup.first != Lookup.second;
+ ++Lookup.first) {
+ if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ continue;
+
+ ConflictingDecls.push_back(*Lookup.first);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, IDNS,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (!Name)
+ return 0;
+ }
+ }
+
+ Expr *Init = Importer.Import(D->getInitExpr());
+ if (D->getInitExpr() && !Init)
+ return 0;
+
+ EnumConstantDecl *ToEnumerator
+ = EnumConstantDecl::Create(Importer.getToContext(), cast<EnumDecl>(DC), Loc,
+ Name.getAsIdentifierInfo(), T,
+ Init, D->getInitVal());
+ ToEnumerator->setLexicalDeclContext(LexicalDC);
+ Importer.Imported(D, ToEnumerator);
+ LexicalDC->addDecl(ToEnumerator);
+ return ToEnumerator;
+}
+
+Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
+ // Import the major distinguishing characteristics of this function.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // Try to find a function in our own ("to") context with the same name, same
+ // type, and in the same context as the function we're importing.
+ if (!LexicalDC->isFunctionOrMethod()) {
+ llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ unsigned IDNS = Decl::IDNS_Ordinary;
+ for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+ Lookup.first != Lookup.second;
+ ++Lookup.first) {
+ if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ continue;
+
+ if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(*Lookup.first)) {
+ if (isExternalLinkage(FoundFunction->getLinkage()) &&
+ isExternalLinkage(D->getLinkage())) {
+ if (Importer.IsStructurallyEquivalent(D->getType(),
+ FoundFunction->getType())) {
+ // FIXME: Actually try to merge the body and other attributes.
+ return Importer.Imported(D, FoundFunction);
+ }
+
+ // FIXME: Check for overloading more carefully, e.g., by boosting
+ // Sema::IsOverload out to the AST library.
+
+ // Function overloading is okay in C++.
+ if (Importer.getToContext().getLangOptions().CPlusPlus)
+ continue;
+
+ // Complain about inconsistent function types.
+ Importer.ToDiag(Loc, diag::err_odr_function_type_inconsistent)
+ << Name << D->getType() << FoundFunction->getType();
+ Importer.ToDiag(FoundFunction->getLocation(),
+ diag::note_odr_value_here)
+ << FoundFunction->getType();
+ }
+ }
+
+ ConflictingDecls.push_back(*Lookup.first);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, IDNS,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (!Name)
+ return 0;
+ }
+ }
+
+ // Import the type.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+
+ // Import the function parameters.
+ llvm::SmallVector<ParmVarDecl *, 8> Parameters;
+ for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
+ P != PEnd; ++P) {
+ ParmVarDecl *ToP = cast_or_null<ParmVarDecl>(Importer.Import(*P));
+ if (!ToP)
+ return 0;
+
+ Parameters.push_back(ToP);
+ }
+
+ // Create the imported function.
+ TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+ FunctionDecl *ToEnumerator
+ = FunctionDecl::Create(Importer.getToContext(), DC, Loc,
+ Name, T, TInfo, D->getStorageClass(),
+ D->isInlineSpecified(),
+ D->hasWrittenPrototype());
+ ToEnumerator->setLexicalDeclContext(LexicalDC);
+ Importer.Imported(D, ToEnumerator);
+ LexicalDC->addDecl(ToEnumerator);
+
+ // Set the parameters.
+ for (unsigned I = 0, N = Parameters.size(); I != N; ++I) {
+ Parameters[I]->setOwningFunction(ToEnumerator);
+ ToEnumerator->addDecl(Parameters[I]);
+ }
+ ToEnumerator->setParams(Parameters.data(), Parameters.size());
+
+ // FIXME: Other bits to merge?
+
+ return ToEnumerator;
+}
+
+Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
+ // Import the major distinguishing characteristics of a variable.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // Import the type.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+
+ TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+ Expr *BitWidth = Importer.Import(D->getBitWidth());
+ if (!BitWidth && D->getBitWidth())
+ return 0;
+
+ FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC,
+ Loc, Name.getAsIdentifierInfo(),
+ T, TInfo, BitWidth, D->isMutable());
+ ToField->setLexicalDeclContext(LexicalDC);
+ Importer.Imported(D, ToField);
+ LexicalDC->addDecl(ToField);
+ return ToField;
+}
+
+Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
+ // Import the major distinguishing characteristics of a variable.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // Try to find a variable in our own ("to") context with the same name and
+ // in the same context as the variable we're importing.
+ if (D->isFileVarDecl()) {
+ VarDecl *MergeWithVar = 0;
+ llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ unsigned IDNS = Decl::IDNS_Ordinary;
+ for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+ Lookup.first != Lookup.second;
+ ++Lookup.first) {
+ if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ continue;
+
+ if (VarDecl *FoundVar = dyn_cast<VarDecl>(*Lookup.first)) {
+ // We have found a variable that we may need to merge with. Check it.
+ if (isExternalLinkage(FoundVar->getLinkage()) &&
+ isExternalLinkage(D->getLinkage())) {
+ if (Importer.IsStructurallyEquivalent(D->getType(),
+ FoundVar->getType())) {
+ MergeWithVar = FoundVar;
+ break;
+ }
+
+ const ArrayType *FoundArray
+ = Importer.getToContext().getAsArrayType(FoundVar->getType());
+ const ArrayType *TArray
+ = Importer.getToContext().getAsArrayType(D->getType());
+ if (FoundArray && TArray) {
+ if (isa<IncompleteArrayType>(FoundArray) &&
+ isa<ConstantArrayType>(TArray)) {
+ // Import the type.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+
+ FoundVar->setType(T);
+ MergeWithVar = FoundVar;
+ break;
+ } else if (isa<IncompleteArrayType>(TArray) &&
+ isa<ConstantArrayType>(FoundArray)) {
+ MergeWithVar = FoundVar;
+ break;
+ }
+ }
+
+ Importer.ToDiag(Loc, diag::err_odr_variable_type_inconsistent)
+ << Name << D->getType() << FoundVar->getType();
+ Importer.ToDiag(FoundVar->getLocation(), diag::note_odr_value_here)
+ << FoundVar->getType();
+ }
+ }
+
+ ConflictingDecls.push_back(*Lookup.first);
+ }
+
+ if (MergeWithVar) {
+ // An equivalent variable with external linkage has been found. Link
+ // the two declarations, then merge them.
+ Importer.Imported(D, MergeWithVar);
+
+ if (VarDecl *DDef = D->getDefinition()) {
+ if (VarDecl *ExistingDef = MergeWithVar->getDefinition()) {
+ Importer.ToDiag(ExistingDef->getLocation(),
+ diag::err_odr_variable_multiple_def)
+ << Name;
+ Importer.FromDiag(DDef->getLocation(), diag::note_odr_defined_here);
+ } else {
+ Expr *Init = Importer.Import(DDef->getInit());
+ MergeWithVar->setInit(Init);
+ }
+ }
+
+ return MergeWithVar;
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, IDNS,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (!Name)
+ return 0;
+ }
+ }
+
+ // Import the type.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+
+ // Create the imported variable.
+ TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+ VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc,
+ Name.getAsIdentifierInfo(), T, TInfo,
+ D->getStorageClass());
+ ToVar->setLexicalDeclContext(LexicalDC);
+ Importer.Imported(D, ToVar);
+ LexicalDC->addDecl(ToVar);
+
+ // Merge the initializer.
+ // FIXME: Can we really import any initializer? Alternatively, we could force
+ // ourselves to import every declaration of a variable and then only use
+ // getInit() here.
+ ToVar->setInit(Importer.Import(const_cast<Expr *>(D->getAnyInitializer())));
+
+ // FIXME: Other bits to merge?
+
+ return ToVar;
+}
+
+Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
+ // Parameters are created in the translation unit's context, then moved
+ // into the function declaration's context afterward.
+ DeclContext *DC = Importer.getToContext().getTranslationUnitDecl();
+
+ // Import the name of this declaration.
+ DeclarationName Name = Importer.Import(D->getDeclName());
+ if (D->getDeclName() && !Name)
+ return 0;
+
+ // Import the location of this declaration.
+ SourceLocation Loc = Importer.Import(D->getLocation());
+
+ // Import the parameter's type.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+
+ // Create the imported parameter.
+ TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+ ParmVarDecl *ToParm = ParmVarDecl::Create(Importer.getToContext(), DC,
+ Loc, Name.getAsIdentifierInfo(),
+ T, TInfo, D->getStorageClass(),
+ /*FIXME: Default argument*/ 0);
+ return Importer.Imported(D, ToParm);
+}
+
+Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ // Import the major distinguishing characteristics of an @interface.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ ObjCInterfaceDecl *MergeWithIface = 0;
+ for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+ Lookup.first != Lookup.second;
+ ++Lookup.first) {
+ if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary))
+ continue;
+
+ if ((MergeWithIface = dyn_cast<ObjCInterfaceDecl>(*Lookup.first)))
+ break;
+ }
+
+ ObjCInterfaceDecl *ToIface = MergeWithIface;
+ if (!ToIface || ToIface->isForwardDecl()) {
+ if (!ToIface) {
+ ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(),
+ DC, Loc,
+ Name.getAsIdentifierInfo(),
+ Importer.Import(D->getClassLoc()),
+ D->isForwardDecl(),
+ D->isImplicitInterfaceDecl());
+ ToIface->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDecl(ToIface);
+ }
+ Importer.Imported(D, ToIface);
+
+ // Import superclass
+ // FIXME: If we're merging, make sure that both decls have the same
+ // superclass.
+ if (D->getSuperClass()) {
+ ObjCInterfaceDecl *Super
+ = cast_or_null<ObjCInterfaceDecl>(Importer.Import(D->getSuperClass()));
+ if (!Super)
+ return 0;
+
+ ToIface->setSuperClass(Super);
+ ToIface->setSuperClassLoc(Importer.Import(D->getSuperClassLoc()));
+ }
+
+ // Import protocols
+ llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols;
+ llvm::SmallVector<SourceLocation, 4> ProtocolLocs;
+ ObjCInterfaceDecl::protocol_loc_iterator
+ FromProtoLoc = D->protocol_loc_begin();
+ for (ObjCInterfaceDecl::protocol_iterator FromProto = D->protocol_begin(),
+ FromProtoEnd = D->protocol_end();
+ FromProto != FromProtoEnd;
+ ++FromProto, ++FromProtoLoc) {
+ ObjCProtocolDecl *ToProto
+ = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto));
+ if (!ToProto)
+ return 0;
+ Protocols.push_back(ToProto);
+ ProtocolLocs.push_back(Importer.Import(*FromProtoLoc));
+ }
+
+ // FIXME: If we're merging, make sure that the protocol list is the same.
+ ToIface->setProtocolList(Protocols.data(), Protocols.size(),
+ ProtocolLocs.data(), Importer.getToContext());
+
+ // FIXME: Import categories
+
+ // Import @end range
+ ToIface->setAtEndRange(Importer.Import(D->getAtEndRange()));
+ } else {
+ Importer.Imported(D, ToIface);
+ }
+
+ // Import all of the members of this class.
+ for (DeclContext::decl_iterator FromMem = D->decls_begin(),
+ FromMemEnd = D->decls_end();
+ FromMem != FromMemEnd;
+ ++FromMem)
+ Importer.Import(*FromMem);
+
+ // If we have an @implementation, import it as well.
+ if (D->getImplementation()) {
+ ObjCImplementationDecl *Impl
+ = cast<ObjCImplementationDecl>(Importer.Import(D->getImplementation()));
+ if (!Impl)
+ return 0;
+
+ ToIface->setImplementation(Impl);
+ }
+
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+// Import Statements
+//----------------------------------------------------------------------------
+
+Stmt *ASTNodeImporter::VisitStmt(Stmt *S) {
+ Importer.FromDiag(S->getLocStart(), diag::err_unsupported_ast_node)
+ << S->getStmtClassName();
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+// Import Expressions
+//----------------------------------------------------------------------------
+Expr *ASTNodeImporter::VisitExpr(Expr *E) {
+ Importer.FromDiag(E->getLocStart(), diag::err_unsupported_ast_node)
+ << E->getStmtClassName();
+ return 0;
+}
+
+Expr *ASTNodeImporter::VisitIntegerLiteral(IntegerLiteral *E) {
+ QualType T = Importer.Import(E->getType());
+ if (T.isNull())
+ return 0;
+
+ return new (Importer.getToContext())
+ IntegerLiteral(E->getValue(), T, Importer.Import(E->getLocation()));
+}
+
+Expr *ASTNodeImporter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ QualType T = Importer.Import(E->getType());
+ if (T.isNull())
+ return 0;
+
+ Expr *SubExpr = Importer.Import(E->getSubExpr());
+ if (!SubExpr)
+ return 0;
+
+ return new (Importer.getToContext()) ImplicitCastExpr(T, E->getCastKind(),
+ SubExpr,
+ E->isLvalueCast());
+}
+
+ASTImporter::ASTImporter(Diagnostic &Diags,
+ ASTContext &ToContext, FileManager &ToFileManager,
+ ASTContext &FromContext, FileManager &FromFileManager)
+ : ToContext(ToContext), FromContext(FromContext),
+ ToFileManager(ToFileManager), FromFileManager(FromFileManager),
+ Diags(Diags) {
+ ImportedDecls[FromContext.getTranslationUnitDecl()]
+ = ToContext.getTranslationUnitDecl();
+}
+
+ASTImporter::~ASTImporter() { }
+
+QualType ASTImporter::Import(QualType FromT) {
+ if (FromT.isNull())
+ return QualType();
+
+ // Check whether we've already imported this type.
+ llvm::DenseMap<Type *, Type *>::iterator Pos
+ = ImportedTypes.find(FromT.getTypePtr());
+ if (Pos != ImportedTypes.end())
+ return ToContext.getQualifiedType(Pos->second, FromT.getQualifiers());
+
+ // Import the type
+ ASTNodeImporter Importer(*this);
+ QualType ToT = Importer.Visit(FromT.getTypePtr());
+ if (ToT.isNull())
+ return ToT;
+
+ // Record the imported type.
+ ImportedTypes[FromT.getTypePtr()] = ToT.getTypePtr();
+
+ return ToContext.getQualifiedType(ToT, FromT.getQualifiers());
+}
+
+TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) {
+ if (!FromTSI)
+ return FromTSI;
+
+ // FIXME: For now we just create a "trivial" type source info based
+ // on the type and a seingle location. Implement a real version of
+ // this.
+ QualType T = Import(FromTSI->getType());
+ if (T.isNull())
+ return 0;
+
+ return ToContext.getTrivialTypeSourceInfo(T,
+ FromTSI->getTypeLoc().getFullSourceRange().getBegin());
+}
+
+Decl *ASTImporter::Import(Decl *FromD) {
+ if (!FromD)
+ return 0;
+
+ // Check whether we've already imported this declaration.
+ llvm::DenseMap<Decl *, Decl *>::iterator Pos = ImportedDecls.find(FromD);
+ if (Pos != ImportedDecls.end())
+ return Pos->second;
+
+ // Import the type
+ ASTNodeImporter Importer(*this);
+ Decl *ToD = Importer.Visit(FromD);
+ if (!ToD)
+ return 0;
+
+ // Record the imported declaration.
+ ImportedDecls[FromD] = ToD;
+
+ if (TagDecl *FromTag = dyn_cast<TagDecl>(FromD)) {
+ // Keep track of anonymous tags that have an associated typedef.
+ if (FromTag->getTypedefForAnonDecl())
+ AnonTagsWithPendingTypedefs.push_back(FromTag);
+ } else if (TypedefDecl *FromTypedef = dyn_cast<TypedefDecl>(FromD)) {
+ // When we've finished transforming a typedef, see whether it was the
+ // typedef for an anonymous tag.
+ for (llvm::SmallVector<TagDecl *, 4>::iterator
+ FromTag = AnonTagsWithPendingTypedefs.begin(),
+ FromTagEnd = AnonTagsWithPendingTypedefs.end();
+ FromTag != FromTagEnd; ++FromTag) {
+ if ((*FromTag)->getTypedefForAnonDecl() == FromTypedef) {
+ if (TagDecl *ToTag = cast_or_null<TagDecl>(Import(*FromTag))) {
+ // We found the typedef for an anonymous tag; link them.
+ ToTag->setTypedefForAnonDecl(cast<TypedefDecl>(ToD));
+ AnonTagsWithPendingTypedefs.erase(FromTag);
+ break;
+ }
+ }
+ }
+ }
+
+ return ToD;
+}
+
+DeclContext *ASTImporter::ImportContext(DeclContext *FromDC) {
+ if (!FromDC)
+ return FromDC;
+
+ return cast_or_null<DeclContext>(Import(cast<Decl>(FromDC)));
+}
+
+Expr *ASTImporter::Import(Expr *FromE) {
+ if (!FromE)
+ return 0;
+
+ return cast_or_null<Expr>(Import(cast<Stmt>(FromE)));
+}
+
+Stmt *ASTImporter::Import(Stmt *FromS) {
+ if (!FromS)
+ return 0;
+
+ // Check whether we've already imported this declaration.
+ llvm::DenseMap<Stmt *, Stmt *>::iterator Pos = ImportedStmts.find(FromS);
+ if (Pos != ImportedStmts.end())
+ return Pos->second;
+
+ // Import the type
+ ASTNodeImporter Importer(*this);
+ Stmt *ToS = Importer.Visit(FromS);
+ if (!ToS)
+ return 0;
+
+ // Record the imported declaration.
+ ImportedStmts[FromS] = ToS;
+ return ToS;
+}
+
+NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) {
+ if (!FromNNS)
+ return 0;
+
+ // FIXME: Implement!
+ return 0;
+}
+
+SourceLocation ASTImporter::Import(SourceLocation FromLoc) {
+ if (FromLoc.isInvalid())
+ return SourceLocation();
+
+ SourceManager &FromSM = FromContext.getSourceManager();
+
+ // For now, map everything down to its spelling location, so that we
+ // don't have to import macro instantiations.
+ // FIXME: Import macro instantiations!
+ FromLoc = FromSM.getSpellingLoc(FromLoc);
+ std::pair<FileID, unsigned> Decomposed = FromSM.getDecomposedLoc(FromLoc);
+ SourceManager &ToSM = ToContext.getSourceManager();
+ return ToSM.getLocForStartOfFile(Import(Decomposed.first))
+ .getFileLocWithOffset(Decomposed.second);
+}
+
+SourceRange ASTImporter::Import(SourceRange FromRange) {
+ return SourceRange(Import(FromRange.getBegin()), Import(FromRange.getEnd()));
+}
+
+FileID ASTImporter::Import(FileID FromID) {
+ llvm::DenseMap<unsigned, FileID>::iterator Pos
+ = ImportedFileIDs.find(FromID.getHashValue());
+ if (Pos != ImportedFileIDs.end())
+ return Pos->second;
+
+ SourceManager &FromSM = FromContext.getSourceManager();
+ SourceManager &ToSM = ToContext.getSourceManager();
+ const SrcMgr::SLocEntry &FromSLoc = FromSM.getSLocEntry(FromID);
+ assert(FromSLoc.isFile() && "Cannot handle macro instantiations yet");
+
+ // Include location of this file.
+ SourceLocation ToIncludeLoc = Import(FromSLoc.getFile().getIncludeLoc());
+
+ // Map the FileID for to the "to" source manager.
+ FileID ToID;
+ const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache();
+ if (Cache->Entry) {
+ // FIXME: We probably want to use getVirtualFile(), so we don't hit the
+ // disk again
+ // FIXME: We definitely want to re-use the existing MemoryBuffer, rather
+ // than mmap the files several times.
+ const FileEntry *Entry = ToFileManager.getFile(Cache->Entry->getName());
+ ToID = ToSM.createFileID(Entry, ToIncludeLoc,
+ FromSLoc.getFile().getFileCharacteristic());
+ } else {
+ // FIXME: We want to re-use the existing MemoryBuffer!
+ const llvm::MemoryBuffer *FromBuf = Cache->getBuffer();
+ llvm::MemoryBuffer *ToBuf
+ = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBufferStart(),
+ FromBuf->getBufferEnd(),
+ FromBuf->getBufferIdentifier());
+ ToID = ToSM.createFileIDForMemBuffer(ToBuf);
+ }
+
+
+ ImportedFileIDs[FromID.getHashValue()] = ToID;
+ return ToID;
+}
+
+DeclarationName ASTImporter::Import(DeclarationName FromName) {
+ if (!FromName)
+ return DeclarationName();
+
+ switch (FromName.getNameKind()) {
+ case DeclarationName::Identifier:
+ return Import(FromName.getAsIdentifierInfo());
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ return Import(FromName.getObjCSelector());
+
+ case DeclarationName::CXXConstructorName: {
+ QualType T = Import(FromName.getCXXNameType());
+ if (T.isNull())
+ return DeclarationName();
+
+ return ToContext.DeclarationNames.getCXXConstructorName(
+ ToContext.getCanonicalType(T));
+ }
+
+ case DeclarationName::CXXDestructorName: {
+ QualType T = Import(FromName.getCXXNameType());
+ if (T.isNull())
+ return DeclarationName();
+
+ return ToContext.DeclarationNames.getCXXDestructorName(
+ ToContext.getCanonicalType(T));
+ }
+
+ case DeclarationName::CXXConversionFunctionName: {
+ QualType T = Import(FromName.getCXXNameType());
+ if (T.isNull())
+ return DeclarationName();
+
+ return ToContext.DeclarationNames.getCXXConversionFunctionName(
+ ToContext.getCanonicalType(T));
+ }
+
+ case DeclarationName::CXXOperatorName:
+ return ToContext.DeclarationNames.getCXXOperatorName(
+ FromName.getCXXOverloadedOperator());
+
+ case DeclarationName::CXXLiteralOperatorName:
+ return ToContext.DeclarationNames.getCXXLiteralOperatorName(
+ Import(FromName.getCXXLiteralIdentifier()));
+
+ case DeclarationName::CXXUsingDirective:
+ // FIXME: STATICS!
+ return DeclarationName::getUsingDirectiveName();
+ }
+
+ // Silence bogus GCC warning
+ return DeclarationName();
+}
+
+IdentifierInfo *ASTImporter::Import(IdentifierInfo *FromId) {
+ if (!FromId)
+ return 0;
+
+ return &ToContext.Idents.get(FromId->getName());
+}
+
+DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name,
+ DeclContext *DC,
+ unsigned IDNS,
+ NamedDecl **Decls,
+ unsigned NumDecls) {
+ return Name;
+}
+
+DiagnosticBuilder ASTImporter::ToDiag(SourceLocation Loc, unsigned DiagID) {
+ return Diags.Report(FullSourceLoc(Loc, ToContext.getSourceManager()),
+ DiagID);
+}
+
+DiagnosticBuilder ASTImporter::FromDiag(SourceLocation Loc, unsigned DiagID) {
+ return Diags.Report(FullSourceLoc(Loc, FromContext.getSourceManager()),
+ DiagID);
+}
+
+Decl *ASTImporter::Imported(Decl *From, Decl *To) {
+ ImportedDecls[From] = To;
+ return To;
+}
+
+bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To) {
+ llvm::DenseMap<Type *, Type *>::iterator Pos
+ = ImportedTypes.find(From.getTypePtr());
+ if (Pos != ImportedTypes.end() && ToContext.hasSameType(Import(From), To))
+ return true;
+
+ StructuralEquivalenceContext SEC(FromContext, ToContext, Diags,
+ NonEquivalentDecls);
+ return SEC.IsStructurallyEquivalent(From, To);
+}
diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
index 02c70b651119..d81979734b3a 100644
--- a/lib/AST/AttrImpl.cpp
+++ b/lib/AST/AttrImpl.cpp
@@ -11,11 +11,61 @@
//
//===----------------------------------------------------------------------===//
-
#include "clang/AST/Attr.h"
#include "clang/AST/ASTContext.h"
using namespace clang;
+void Attr::Destroy(ASTContext &C) {
+ if (Next) {
+ Next->Destroy(C);
+ Next = 0;
+ }
+ this->~Attr();
+ C.Deallocate((void*)this);
+}
+
+AttrWithString::AttrWithString(Attr::Kind AK, ASTContext &C, llvm::StringRef s)
+ : Attr(AK) {
+ assert(!s.empty());
+ StrLen = s.size();
+ Str = new (C) char[StrLen];
+ memcpy(const_cast<char*>(Str), s.data(), StrLen);
+}
+
+void AttrWithString::Destroy(ASTContext &C) {
+ C.Deallocate(const_cast<char*>(Str));
+ Attr::Destroy(C);
+}
+
+void AttrWithString::ReplaceString(ASTContext &C, llvm::StringRef newS) {
+ if (newS.size() > StrLen) {
+ C.Deallocate(const_cast<char*>(Str));
+ Str = new (C) char[newS.size()];
+ }
+ StrLen = newS.size();
+ memcpy(const_cast<char*>(Str), newS.data(), StrLen);
+}
+
+void FormatAttr::setType(ASTContext &C, llvm::StringRef type) {
+ ReplaceString(C, type);
+}
+
+NonNullAttr::NonNullAttr(ASTContext &C, unsigned* arg_nums, unsigned size)
+ : Attr(NonNull), ArgNums(0), Size(0) {
+ if (size == 0)
+ return;
+ assert(arg_nums);
+ ArgNums = new (C) unsigned[size];
+ Size = size;
+ memcpy(ArgNums, arg_nums, sizeof(*ArgNums)*size);
+}
+
+void NonNullAttr::Destroy(ASTContext &C) {
+ if (ArgNums)
+ C.Deallocate(ArgNums);
+ Attr::Destroy(C);
+}
+
#define DEF_SIMPLE_ATTR_CLONE(ATTR) \
Attr *ATTR##Attr::clone(ASTContext &C) const { \
return ::new (C) ATTR##Attr; \
@@ -55,6 +105,7 @@ DEF_SIMPLE_ATTR_CLONE(Hiding)
DEF_SIMPLE_ATTR_CLONE(Override)
DEF_SIMPLE_ATTR_CLONE(DLLImport)
DEF_SIMPLE_ATTR_CLONE(DLLExport)
+DEF_SIMPLE_ATTR_CLONE(X86ForceAlignArgPointer)
Attr* PragmaPackAttr::clone(ASTContext &C) const {
return ::new (C) PragmaPackAttr(Alignment);
@@ -65,15 +116,15 @@ Attr* AlignedAttr::clone(ASTContext &C) const {
}
Attr* AnnotateAttr::clone(ASTContext &C) const {
- return ::new (C) AnnotateAttr(Annotation);
+ return ::new (C) AnnotateAttr(C, getAnnotation());
}
Attr *AsmLabelAttr::clone(ASTContext &C) const {
- return ::new (C) AsmLabelAttr(Label);
+ return ::new (C) AsmLabelAttr(C, getLabel());
}
Attr *AliasAttr::clone(ASTContext &C) const {
- return ::new (C) AliasAttr(Aliasee);
+ return ::new (C) AliasAttr(C, getAliasee());
}
Attr *ConstructorAttr::clone(ASTContext &C) const {
@@ -93,15 +144,15 @@ Attr *GNUInlineAttr::clone(ASTContext &C) const {
}
Attr *SectionAttr::clone(ASTContext &C) const {
- return ::new (C) SectionAttr(Name);
+ return ::new (C) SectionAttr(C, getName());
}
Attr *NonNullAttr::clone(ASTContext &C) const {
- return ::new (C) NonNullAttr(ArgNums, Size);
+ return ::new (C) NonNullAttr(C, ArgNums, Size);
}
Attr *FormatAttr::clone(ASTContext &C) const {
- return ::new (C) FormatAttr(Type, formatIdx, firstArg);
+ return ::new (C) FormatAttr(C, getType(), formatIdx, firstArg);
}
Attr *FormatArgAttr::clone(ASTContext &C) const {
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index dea96e7866ec..e5bd9b7722c5 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -4,6 +4,8 @@ add_clang_library(clangAST
APValue.cpp
ASTConsumer.cpp
ASTContext.cpp
+ ASTImporter.cpp
+ ASTDiagnostic.cpp
AttrImpl.cpp
CXXInheritance.cpp
Decl.cpp
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index 720832869266..99f908caeab6 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -102,7 +102,6 @@ bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const {
bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
void *OpaqueData,
bool AllowShortCircuit) const {
- ASTContext &Context = getASTContext();
llvm::SmallVector<const CXXRecordDecl*, 8> Queue;
const CXXRecordDecl *Record = this;
@@ -118,7 +117,7 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
}
CXXRecordDecl *Base =
- cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition(Context));
+ cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition());
if (!Base) {
if (AllowShortCircuit) return false;
AllMatches = false;
@@ -215,10 +214,13 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
Paths.ScratchPath.Access
= MergeAccess(AccessToHere, BaseSpec->getAccessSpecifier());
}
-
+
+ // Track whether there's a path involving this specific base.
+ bool FoundPathThroughBase = false;
+
if (BaseMatches(BaseSpec, Paths.ScratchPath, UserData)) {
// We've found a path that terminates at this base.
- FoundPath = true;
+ FoundPath = FoundPathThroughBase = true;
if (Paths.isRecordingPaths()) {
// We have a path. Make a copy of it before moving on.
Paths.Paths.push_back(Paths.ScratchPath);
@@ -240,7 +242,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
// There is a path to a base class that meets the criteria. If we're
// not collecting paths or finding ambiguities, we're done.
- FoundPath = true;
+ FoundPath = FoundPathThroughBase = true;
if (!Paths.isFindingAmbiguities())
return FoundPath;
}
@@ -253,7 +255,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
}
// If we set a virtual earlier, and this isn't a path, forget it again.
- if (SetVirtual && !FoundPath) {
+ if (SetVirtual && !FoundPathThroughBase) {
Paths.DetectedVirtual = 0;
}
}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 794b14a1f4a1..5acb82f31a29 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -29,224 +29,81 @@
using namespace clang;
-void Attr::Destroy(ASTContext &C) {
- if (Next) {
- Next->Destroy(C);
- Next = 0;
- }
- this->~Attr();
- C.Deallocate((void*)this);
-}
-
/// \brief Return the TypeLoc wrapper for the type source info.
TypeLoc TypeSourceInfo::getTypeLoc() const {
return TypeLoc(Ty, (void*)(this + 1));
}
//===----------------------------------------------------------------------===//
-// Decl Allocation/Deallocation Method Implementations
+// NamedDecl Implementation
//===----------------------------------------------------------------------===//
+/// \brief Get the most restrictive linkage for the types in the given
+/// template parameter list.
+static Linkage
+getLinkageForTemplateParameterList(const TemplateParameterList *Params) {
+ Linkage L = ExternalLinkage;
+ for (TemplateParameterList::const_iterator P = Params->begin(),
+ PEnd = Params->end();
+ P != PEnd; ++P) {
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P))
+ if (!NTTP->getType()->isDependentType()) {
+ L = minLinkage(L, NTTP->getType()->getLinkage());
+ continue;
+ }
-TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) {
- return new (C) TranslationUnitDecl(C);
-}
-
-NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id) {
- return new (C) NamespaceDecl(DC, L, Id);
-}
-
-void NamespaceDecl::Destroy(ASTContext& C) {
- // NamespaceDecl uses "NextDeclarator" to chain namespace declarations
- // together. They are all top-level Decls.
-
- this->~NamespaceDecl();
- C.Deallocate((void *)this);
-}
-
-
-ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id, QualType T) {
- return new (C) ImplicitParamDecl(ImplicitParam, DC, L, Id, T);
-}
-
-const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
- switch (SC) {
- case VarDecl::None: break;
- case VarDecl::Auto: return "auto"; break;
- case VarDecl::Extern: return "extern"; break;
- case VarDecl::PrivateExtern: return "__private_extern__"; break;
- case VarDecl::Register: return "register"; break;
- case VarDecl::Static: return "static"; break;
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(*P)) {
+ L = minLinkage(L,
+ getLinkageForTemplateParameterList(TTP->getTemplateParameters()));
+ }
}
- assert(0 && "Invalid storage class");
- return 0;
-}
-
-ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- QualType T, TypeSourceInfo *TInfo,
- StorageClass S, Expr *DefArg) {
- return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg);
-}
-
-Expr *ParmVarDecl::getDefaultArg() {
- assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!");
- assert(!hasUninstantiatedDefaultArg() &&
- "Default argument is not yet instantiated!");
-
- Expr *Arg = getInit();
- if (CXXExprWithTemporaries *E = dyn_cast_or_null<CXXExprWithTemporaries>(Arg))
- return E->getSubExpr();
-
- return Arg;
-}
-
-unsigned ParmVarDecl::getNumDefaultArgTemporaries() const {
- if (const CXXExprWithTemporaries *E =
- dyn_cast<CXXExprWithTemporaries>(getInit()))
- return E->getNumTemporaries();
-
- return 0;
+ return L;
}
-CXXTemporary *ParmVarDecl::getDefaultArgTemporary(unsigned i) {
- assert(getNumDefaultArgTemporaries() &&
- "Default arguments does not have any temporaries!");
-
- CXXExprWithTemporaries *E = cast<CXXExprWithTemporaries>(getInit());
- return E->getTemporary(i);
-}
+/// \brief Get the most restrictive linkage for the types and
+/// declarations in the given template argument list.
+static Linkage getLinkageForTemplateArgumentList(const TemplateArgument *Args,
+ unsigned NumArgs) {
+ Linkage L = ExternalLinkage;
-SourceRange ParmVarDecl::getDefaultArgRange() const {
- if (const Expr *E = getInit())
- return E->getSourceRange();
-
- if (hasUninstantiatedDefaultArg())
- return getUninstantiatedDefaultArg()->getSourceRange();
-
- return SourceRange();
-}
-
-void VarDecl::setInit(ASTContext &C, Expr *I) {
- if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) {
- Eval->~EvaluatedStmt();
- C.Deallocate(Eval);
- }
-
- Init = I;
-}
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ switch (Args[I].getKind()) {
+ case TemplateArgument::Null:
+ case TemplateArgument::Integral:
+ case TemplateArgument::Expression:
+ break;
+
+ case TemplateArgument::Type:
+ L = minLinkage(L, Args[I].getAsType()->getLinkage());
+ break;
-bool VarDecl::isExternC() const {
- ASTContext &Context = getASTContext();
- if (!Context.getLangOptions().CPlusPlus)
- return (getDeclContext()->isTranslationUnit() &&
- getStorageClass() != Static) ||
- (getDeclContext()->isFunctionOrMethod() && hasExternalStorage());
+ case TemplateArgument::Declaration:
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(Args[I].getAsDecl()))
+ L = minLinkage(L, ND->getLinkage());
+ if (ValueDecl *VD = dyn_cast<ValueDecl>(Args[I].getAsDecl()))
+ L = minLinkage(L, VD->getType()->getLinkage());
+ break;
- for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit();
- DC = DC->getParent()) {
- if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) {
- if (Linkage->getLanguage() == LinkageSpecDecl::lang_c)
- return getStorageClass() != Static;
+ case TemplateArgument::Template:
+ if (TemplateDecl *Template
+ = Args[I].getAsTemplate().getAsTemplateDecl())
+ L = minLinkage(L, Template->getLinkage());
+ break;
+ case TemplateArgument::Pack:
+ L = minLinkage(L,
+ getLinkageForTemplateArgumentList(Args[I].pack_begin(),
+ Args[I].pack_size()));
break;
}
-
- if (DC->isFunctionOrMethod())
- return false;
}
- return false;
+ return L;
}
-FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
- DeclarationName N, QualType T,
- TypeSourceInfo *TInfo,
- StorageClass S, bool isInline,
- bool hasWrittenPrototype) {
- FunctionDecl *New
- = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, S, isInline);
- New->HasWrittenPrototype = hasWrittenPrototype;
- return New;
-}
-
-BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
- return new (C) BlockDecl(DC, L);
-}
-
-FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, QualType T,
- TypeSourceInfo *TInfo, Expr *BW, bool Mutable) {
- return new (C) FieldDecl(Decl::Field, DC, L, Id, T, TInfo, BW, Mutable);
-}
-
-bool FieldDecl::isAnonymousStructOrUnion() const {
- if (!isImplicit() || getDeclName())
- return false;
-
- if (const RecordType *Record = getType()->getAs<RecordType>())
- return Record->getDecl()->isAnonymousStructOrUnion();
-
- return false;
-}
-
-EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
- SourceLocation L,
- IdentifierInfo *Id, QualType T,
- Expr *E, const llvm::APSInt &V) {
- return new (C) EnumConstantDecl(CD, L, Id, T, E, V);
-}
-
-void EnumConstantDecl::Destroy(ASTContext& C) {
- if (Init) Init->Destroy(C);
- Decl::Destroy(C);
-}
-
-TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- TypeSourceInfo *TInfo) {
- return new (C) TypedefDecl(DC, L, Id, TInfo);
-}
-
-// Anchor TypedefDecl's vtable here.
-TypedefDecl::~TypedefDecl() {}
-
-EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, SourceLocation TKL,
- EnumDecl *PrevDecl) {
- EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL);
- C.getTypeDeclType(Enum, PrevDecl);
- return Enum;
-}
-
-void EnumDecl::Destroy(ASTContext& C) {
- Decl::Destroy(C);
-}
-
-void EnumDecl::completeDefinition(ASTContext &C,
- QualType NewType,
- QualType NewPromotionType) {
- assert(!isDefinition() && "Cannot redefine enums!");
- IntegerType = NewType;
- PromotionType = NewPromotionType;
- TagDecl::completeDefinition();
-}
-
-FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
- StringLiteral *Str) {
- return new (C) FileScopeAsmDecl(DC, L, Str);
-}
-
-//===----------------------------------------------------------------------===//
-// NamedDecl Implementation
-//===----------------------------------------------------------------------===//
-
-static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
+static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
assert(D->getDeclContext()->getLookupContext()->isFileContext() &&
"Not a name having namespace scope");
ASTContext &Context = D->getASTContext();
@@ -260,7 +117,7 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
// Explicitly declared static.
if (Var->getStorageClass() == VarDecl::Static)
- return NamedDecl::InternalLinkage;
+ return InternalLinkage;
// - an object or reference that is explicitly declared const
// and neither explicitly declared extern nor previously
@@ -274,13 +131,16 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
for (const VarDecl *PrevVar = Var->getPreviousDeclaration();
PrevVar && !FoundExtern;
PrevVar = PrevVar->getPreviousDeclaration())
- if (PrevVar->getLinkage() == NamedDecl::ExternalLinkage)
+ if (isExternalLinkage(PrevVar->getLinkage()))
FoundExtern = true;
if (!FoundExtern)
- return NamedDecl::InternalLinkage;
+ return InternalLinkage;
}
} else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
+ // C++ [temp]p4:
+ // A non-member function template can have internal linkage; any
+ // other template name shall have external linkage.
const FunctionDecl *Function = 0;
if (const FunctionTemplateDecl *FunTmpl
= dyn_cast<FunctionTemplateDecl>(D))
@@ -290,11 +150,11 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
// Explicitly declared static.
if (Function->getStorageClass() == FunctionDecl::Static)
- return NamedDecl::InternalLinkage;
+ return InternalLinkage;
} else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
// - a data member of an anonymous union.
if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion())
- return NamedDecl::InternalLinkage;
+ return InternalLinkage;
}
// C++ [basic.link]p4:
@@ -317,7 +177,7 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
// is visible, or if the prior declaration specifies no
// linkage, then the identifier has external linkage.
if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) {
- if (NamedDecl::Linkage L = PrevVar->getLinkage())
+ if (Linkage L = PrevVar->getLinkage())
return L;
}
}
@@ -326,7 +186,10 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
// If the declaration of an identifier for an object has file
// scope and no storage-class specifier, its linkage is
// external.
- return NamedDecl::ExternalLinkage;
+ if (Var->isInAnonymousNamespace())
+ return UniqueExternalLinkage;
+
+ return ExternalLinkage;
}
// - a function, unless it has internal linkage; or
@@ -350,12 +213,26 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
// is visible, or if the prior declaration specifies no
// linkage, then the identifier has external linkage.
if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) {
- if (NamedDecl::Linkage L = PrevFunc->getLinkage())
+ if (Linkage L = PrevFunc->getLinkage())
return L;
}
}
- return NamedDecl::ExternalLinkage;
+ if (Function->isInAnonymousNamespace())
+ return UniqueExternalLinkage;
+
+ if (FunctionTemplateSpecializationInfo *SpecInfo
+ = Function->getTemplateSpecializationInfo()) {
+ Linkage L = SpecInfo->getTemplate()->getLinkage();
+ const TemplateArgumentList &TemplateArgs = *SpecInfo->TemplateArguments;
+ L = minLinkage(L,
+ getLinkageForTemplateArgumentList(
+ TemplateArgs.getFlatArgumentList(),
+ TemplateArgs.flat_size()));
+ return L;
+ }
+
+ return ExternalLinkage;
}
// - a named class (Clause 9), or an unnamed class defined in a
@@ -365,29 +242,50 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
// defined in a typedef declaration in which the enumeration
// has the typedef name for linkage purposes (7.1.3); or
if (const TagDecl *Tag = dyn_cast<TagDecl>(D))
- if (Tag->getDeclName() || Tag->getTypedefForAnonDecl())
- return NamedDecl::ExternalLinkage;
+ if (Tag->getDeclName() || Tag->getTypedefForAnonDecl()) {
+ if (Tag->isInAnonymousNamespace())
+ return UniqueExternalLinkage;
+
+ // If this is a class template specialization, consider the
+ // linkage of the template and template arguments.
+ if (const ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Tag)) {
+ const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+ Linkage L = getLinkageForTemplateArgumentList(
+ TemplateArgs.getFlatArgumentList(),
+ TemplateArgs.flat_size());
+ return minLinkage(L, Spec->getSpecializedTemplate()->getLinkage());
+ }
+
+ return ExternalLinkage;
+ }
// - an enumerator belonging to an enumeration with external linkage;
- if (isa<EnumConstantDecl>(D))
- if (cast<NamedDecl>(D->getDeclContext())->getLinkage()
- == NamedDecl::ExternalLinkage)
- return NamedDecl::ExternalLinkage;
+ if (isa<EnumConstantDecl>(D)) {
+ Linkage L = cast<NamedDecl>(D->getDeclContext())->getLinkage();
+ if (isExternalLinkage(L))
+ return L;
+ }
// - a template, unless it is a function template that has
// internal linkage (Clause 14);
- if (isa<TemplateDecl>(D))
- return NamedDecl::ExternalLinkage;
+ if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
+ if (D->isInAnonymousNamespace())
+ return UniqueExternalLinkage;
+
+ return getLinkageForTemplateParameterList(
+ Template->getTemplateParameters());
+ }
// - a namespace (7.3), unless it is declared within an unnamed
// namespace.
if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace())
- return NamedDecl::ExternalLinkage;
+ return ExternalLinkage;
- return NamedDecl::NoLinkage;
+ return NoLinkage;
}
-NamedDecl::Linkage NamedDecl::getLinkage() const {
+Linkage NamedDecl::getLinkage() const {
// Handle linkage for namespace-scope names.
if (getDeclContext()->getLookupContext()->isFileContext())
if (Linkage L = getLinkageForNamespaceScopeDecl(this))
@@ -403,9 +301,11 @@ NamedDecl::Linkage NamedDecl::getLinkage() const {
if (getDeclContext()->isRecord() &&
(isa<CXXMethodDecl>(this) || isa<VarDecl>(this) ||
(isa<TagDecl>(this) &&
- (getDeclName() || cast<TagDecl>(this)->getTypedefForAnonDecl()))) &&
- cast<RecordDecl>(getDeclContext())->getLinkage() == ExternalLinkage)
- return ExternalLinkage;
+ (getDeclName() || cast<TagDecl>(this)->getTypedefForAnonDecl())))) {
+ Linkage L = cast<RecordDecl>(getDeclContext())->getLinkage();
+ if (isExternalLinkage(L))
+ return L;
+ }
// C++ [basic.link]p6:
// The name of a function declared in block scope and the name of
@@ -424,6 +324,9 @@ NamedDecl::Linkage NamedDecl::getLinkage() const {
if (Linkage L = Function->getPreviousDeclaration()->getLinkage())
return L;
+ if (Function->isInAnonymousNamespace())
+ return UniqueExternalLinkage;
+
return ExternalLinkage;
}
@@ -434,6 +337,9 @@ NamedDecl::Linkage NamedDecl::getLinkage() const {
if (Linkage L = Var->getPreviousDeclaration()->getLinkage())
return L;
+ if (Var->isInAnonymousNamespace())
+ return UniqueExternalLinkage;
+
return ExternalLinkage;
}
}
@@ -441,7 +347,7 @@ NamedDecl::Linkage NamedDecl::getLinkage() const {
// C++ [basic.link]p6:
// Names not covered by these rules have no linkage.
return NoLinkage;
-}
+ }
std::string NamedDecl::getQualifiedNameAsString() const {
return getQualifiedNameAsString(getASTContext().getLangOptions());
@@ -606,6 +512,20 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const {
// VarDecl Implementation
//===----------------------------------------------------------------------===//
+const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
+ switch (SC) {
+ case VarDecl::None: break;
+ case VarDecl::Auto: return "auto"; break;
+ case VarDecl::Extern: return "extern"; break;
+ case VarDecl::PrivateExtern: return "__private_extern__"; break;
+ case VarDecl::Register: return "register"; break;
+ case VarDecl::Static: return "static"; break;
+ }
+
+ assert(0 && "Invalid storage class");
+ return 0;
+}
+
VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
StorageClass S) {
@@ -638,6 +558,127 @@ SourceRange VarDecl::getSourceRange() const {
return SourceRange(Start, getLocation());
}
+bool VarDecl::isExternC() const {
+ ASTContext &Context = getASTContext();
+ if (!Context.getLangOptions().CPlusPlus)
+ return (getDeclContext()->isTranslationUnit() &&
+ getStorageClass() != Static) ||
+ (getDeclContext()->isFunctionOrMethod() && hasExternalStorage());
+
+ for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit();
+ DC = DC->getParent()) {
+ if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) {
+ if (Linkage->getLanguage() == LinkageSpecDecl::lang_c)
+ return getStorageClass() != Static;
+
+ break;
+ }
+
+ if (DC->isFunctionOrMethod())
+ return false;
+ }
+
+ return false;
+}
+
+VarDecl *VarDecl::getCanonicalDecl() {
+ return getFirstDeclaration();
+}
+
+VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition() const {
+ // C++ [basic.def]p2:
+ // A declaration is a definition unless [...] it contains the 'extern'
+ // specifier or a linkage-specification and neither an initializer [...],
+ // it declares a static data member in a class declaration [...].
+ // 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 is
+ // a declaration.
+ if (isStaticDataMember()) {
+ if (isOutOfLine() && (hasInit() ||
+ getTemplateSpecializationKind() != TSK_ExplicitSpecialization))
+ return Definition;
+ else
+ return DeclarationOnly;
+ }
+ // C99 6.7p5:
+ // A definition of an identifier is a declaration for that identifier that
+ // [...] causes storage to be reserved for that object.
+ // Note: that applies for all non-file-scope objects.
+ // C99 6.9.2p1:
+ // If the declaration of an identifier for an object has file scope and an
+ // initializer, the declaration is an external definition for the identifier
+ if (hasInit())
+ return Definition;
+ // AST for 'extern "C" int foo;' is annotated with 'extern'.
+ if (hasExternalStorage())
+ return DeclarationOnly;
+
+ // C99 6.9.2p2:
+ // A declaration of an object that has file scope without an initializer,
+ // and without a storage class specifier or the scs 'static', constitutes
+ // a tentative definition.
+ // No such thing in C++.
+ if (!getASTContext().getLangOptions().CPlusPlus && isFileVarDecl())
+ return TentativeDefinition;
+
+ // What's left is (in C, block-scope) declarations without initializers or
+ // external storage. These are definitions.
+ return Definition;
+}
+
+VarDecl *VarDecl::getActingDefinition() {
+ DefinitionKind Kind = isThisDeclarationADefinition();
+ if (Kind != TentativeDefinition)
+ return 0;
+
+ VarDecl *LastTentative = false;
+ VarDecl *First = getFirstDeclaration();
+ for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
+ I != E; ++I) {
+ Kind = (*I)->isThisDeclarationADefinition();
+ if (Kind == Definition)
+ return 0;
+ else if (Kind == TentativeDefinition)
+ LastTentative = *I;
+ }
+ return LastTentative;
+}
+
+bool VarDecl::isTentativeDefinitionNow() const {
+ DefinitionKind Kind = isThisDeclarationADefinition();
+ if (Kind != TentativeDefinition)
+ return false;
+
+ for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
+ if ((*I)->isThisDeclarationADefinition() == Definition)
+ return false;
+ }
+ return true;
+}
+
+VarDecl *VarDecl::getDefinition() {
+ VarDecl *First = getFirstDeclaration();
+ for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
+ I != E; ++I) {
+ if ((*I)->isThisDeclarationADefinition() == Definition)
+ return *I;
+ }
+ return 0;
+}
+
+const Expr *VarDecl::getAnyInitializer(const VarDecl *&D) const {
+ redecl_iterator I = redecls_begin(), E = redecls_end();
+ while (I != E && !I->getInit())
+ ++I;
+
+ if (I != E) {
+ D = *I;
+ return I->getInit();
+ }
+ return 0;
+}
+
bool VarDecl::isOutOfLine() const {
if (!isStaticDataMember())
return false;
@@ -667,6 +708,15 @@ VarDecl *VarDecl::getOutOfLineDefinition() {
return 0;
}
+void VarDecl::setInit(Expr *I) {
+ if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) {
+ Eval->~EvaluatedStmt();
+ getASTContext().Deallocate(Eval);
+ }
+
+ Init = I;
+}
+
VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
return cast<VarDecl>(MSI->getInstantiatedFrom());
@@ -675,8 +725,7 @@ VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
}
TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const {
- if (MemberSpecializationInfo *MSI
- = getASTContext().getInstantiatedFromStaticDataMember(this))
+ if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
return MSI->getTemplateSpecializationKind();
return TSK_Undeclared;
@@ -697,29 +746,53 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
MSI->setPointOfInstantiation(PointOfInstantiation);
}
-bool VarDecl::isTentativeDefinition(ASTContext &Context) const {
- if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus)
- return false;
+//===----------------------------------------------------------------------===//
+// ParmVarDecl Implementation
+//===----------------------------------------------------------------------===//
- const VarDecl *Def = 0;
- return (!getDefinition(Def) &&
- (getStorageClass() == None || getStorageClass() == Static));
+ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ QualType T, TypeSourceInfo *TInfo,
+ StorageClass S, Expr *DefArg) {
+ return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg);
}
-const Expr *VarDecl::getDefinition(const VarDecl *&Def) const {
- redecl_iterator I = redecls_begin(), E = redecls_end();
- while (I != E && !I->getInit())
- ++I;
+Expr *ParmVarDecl::getDefaultArg() {
+ assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!");
+ assert(!hasUninstantiatedDefaultArg() &&
+ "Default argument is not yet instantiated!");
+
+ Expr *Arg = getInit();
+ if (CXXExprWithTemporaries *E = dyn_cast_or_null<CXXExprWithTemporaries>(Arg))
+ return E->getSubExpr();
+
+ return Arg;
+}
+
+unsigned ParmVarDecl::getNumDefaultArgTemporaries() const {
+ if (const CXXExprWithTemporaries *E =
+ dyn_cast<CXXExprWithTemporaries>(getInit()))
+ return E->getNumTemporaries();
- if (I != E) {
- Def = *I;
- return I->getInit();
- }
return 0;
}
-VarDecl *VarDecl::getCanonicalDecl() {
- return getFirstDeclaration();
+CXXTemporary *ParmVarDecl::getDefaultArgTemporary(unsigned i) {
+ assert(getNumDefaultArgTemporaries() &&
+ "Default arguments does not have any temporaries!");
+
+ CXXExprWithTemporaries *E = cast<CXXExprWithTemporaries>(getInit());
+ return E->getTemporary(i);
+}
+
+SourceRange ParmVarDecl::getDefaultArgRange() const {
+ if (const Expr *E = getInit())
+ return E->getSourceRange();
+
+ if (hasUninstantiatedDefaultArg())
+ return getUninstantiatedDefaultArg()->getSourceRange();
+
+ return SourceRange();
}
//===----------------------------------------------------------------------===//
@@ -826,6 +899,26 @@ bool FunctionDecl::isGlobal() const {
return true;
}
+void
+FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
+ redeclarable_base::setPreviousDeclaration(PrevDecl);
+
+ if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) {
+ FunctionTemplateDecl *PrevFunTmpl
+ = PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0;
+ assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch");
+ FunTmpl->setPreviousDeclaration(PrevFunTmpl);
+ }
+}
+
+const FunctionDecl *FunctionDecl::getCanonicalDecl() const {
+ return getFirstDeclaration();
+}
+
+FunctionDecl *FunctionDecl::getCanonicalDecl() {
+ return getFirstDeclaration();
+}
+
/// \brief Returns a value indicating whether this function
/// corresponds to a builtin function.
///
@@ -882,14 +975,13 @@ unsigned FunctionDecl::getNumParams() const {
}
-void FunctionDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo,
- unsigned NumParams) {
+void FunctionDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) {
assert(ParamInfo == 0 && "Already has param info!");
assert(NumParams == getNumParams() && "Parameter count mismatch!");
// Zero params -> null pointer.
if (NumParams) {
- void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams);
+ void *Mem = getASTContext().Allocate(sizeof(ParmVarDecl*)*NumParams);
ParamInfo = new (Mem) ParmVarDecl*[NumParams];
memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams);
@@ -1014,26 +1106,6 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
return false;
}
-void
-FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
- redeclarable_base::setPreviousDeclaration(PrevDecl);
-
- if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) {
- FunctionTemplateDecl *PrevFunTmpl
- = PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0;
- assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch");
- FunTmpl->setPreviousDeclaration(PrevFunTmpl);
- }
-}
-
-const FunctionDecl *FunctionDecl::getCanonicalDecl() const {
- return getFirstDeclaration();
-}
-
-FunctionDecl *FunctionDecl::getCanonicalDecl() {
- return getFirstDeclaration();
-}
-
/// getOverloadedOperator - Which C++ overloaded operator this
/// function represents, if any.
OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
@@ -1146,8 +1218,7 @@ FunctionDecl::getTemplateSpecializationArgs() const {
}
void
-FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
- FunctionTemplateDecl *Template,
+FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template,
const TemplateArgumentList *TemplateArgs,
void *InsertPos,
TemplateSpecializationKind TSK) {
@@ -1156,7 +1227,7 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
FunctionTemplateSpecializationInfo *Info
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
if (!Info)
- Info = new (Context) FunctionTemplateSpecializationInfo;
+ Info = new (getASTContext()) FunctionTemplateSpecializationInfo;
Info->Function = this;
Info->Template.setPointer(Template);
@@ -1254,6 +1325,26 @@ bool FunctionDecl::isOutOfLine() const {
}
//===----------------------------------------------------------------------===//
+// FieldDecl Implementation
+//===----------------------------------------------------------------------===//
+
+FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, QualType T,
+ TypeSourceInfo *TInfo, Expr *BW, bool Mutable) {
+ return new (C) FieldDecl(Decl::Field, DC, L, Id, T, TInfo, BW, Mutable);
+}
+
+bool FieldDecl::isAnonymousStructOrUnion() const {
+ if (!isImplicit() || getDeclName())
+ return false;
+
+ if (const RecordType *Record = getType()->getAs<RecordType>())
+ return Record->getDecl()->isAnonymousStructOrUnion();
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
// TagDecl Implementation
//===----------------------------------------------------------------------===//
@@ -1271,9 +1362,23 @@ void TagDecl::startDefinition() {
TagT->decl.setPointer(this);
TagT->decl.setInt(1);
}
+
+ if (isa<CXXRecordDecl>(this)) {
+ CXXRecordDecl *D = cast<CXXRecordDecl>(this);
+ struct CXXRecordDecl::DefinitionData *Data =
+ new (getASTContext()) struct CXXRecordDecl::DefinitionData(D);
+ do {
+ D->DefinitionData = Data;
+ D = cast_or_null<CXXRecordDecl>(D->getPreviousDeclaration());
+ } while (D);
+ }
}
void TagDecl::completeDefinition() {
+ assert((!isa<CXXRecordDecl>(this) ||
+ cast<CXXRecordDecl>(this)->hasDefinition()) &&
+ "definition completed but not started");
+
IsDefinition = true;
if (TagType *TagT = const_cast<TagType *>(TypeForDecl->getAs<TagType>())) {
assert(TagT->decl.getPointer() == this &&
@@ -1282,7 +1387,7 @@ void TagDecl::completeDefinition() {
}
}
-TagDecl* TagDecl::getDefinition(ASTContext& C) const {
+TagDecl* TagDecl::getDefinition() const {
if (isDefinition())
return const_cast<TagDecl *>(this);
@@ -1305,6 +1410,30 @@ TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) {
}
//===----------------------------------------------------------------------===//
+// EnumDecl Implementation
+//===----------------------------------------------------------------------===//
+
+EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, SourceLocation TKL,
+ EnumDecl *PrevDecl) {
+ EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL);
+ C.getTypeDeclType(Enum, PrevDecl);
+ return Enum;
+}
+
+void EnumDecl::Destroy(ASTContext& C) {
+ Decl::Destroy(C);
+}
+
+void EnumDecl::completeDefinition(QualType NewType,
+ QualType NewPromotionType) {
+ assert(!isDefinition() && "Cannot redefine enums!");
+ IntegerType = NewType;
+ PromotionType = NewPromotionType;
+ TagDecl::completeDefinition();
+}
+
+//===----------------------------------------------------------------------===//
// RecordDecl Implementation
//===----------------------------------------------------------------------===//
@@ -1341,7 +1470,7 @@ bool RecordDecl::isInjectedClassName() const {
/// completeDefinition - Notes that the definition of this type is now
/// complete.
-void RecordDecl::completeDefinition(ASTContext& C) {
+void RecordDecl::completeDefinition() {
assert(!isDefinition() && "Cannot redefine record!");
TagDecl::completeDefinition();
}
@@ -1364,14 +1493,14 @@ void BlockDecl::Destroy(ASTContext& C) {
Decl::Destroy(C);
}
-void BlockDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo,
+void BlockDecl::setParams(ParmVarDecl **NewParamInfo,
unsigned NParms) {
assert(ParamInfo == 0 && "Already has param info!");
// Zero params -> null pointer.
if (NParms) {
NumParams = NParms;
- void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams);
+ void *Mem = getASTContext().Allocate(sizeof(ParmVarDecl*)*NumParams);
ParamInfo = new (Mem) ParmVarDecl*[NumParams];
memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams);
}
@@ -1380,3 +1509,74 @@ void BlockDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo,
unsigned BlockDecl::getNumParams() const {
return NumParams;
}
+
+
+//===----------------------------------------------------------------------===//
+// Other Decl Allocation/Deallocation Method Implementations
+//===----------------------------------------------------------------------===//
+
+TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) {
+ return new (C) TranslationUnitDecl(C);
+}
+
+NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id) {
+ return new (C) NamespaceDecl(DC, L, Id);
+}
+
+void NamespaceDecl::Destroy(ASTContext& C) {
+ // NamespaceDecl uses "NextDeclarator" to chain namespace declarations
+ // together. They are all top-level Decls.
+
+ this->~NamespaceDecl();
+ C.Deallocate((void *)this);
+}
+
+
+ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id, QualType T) {
+ return new (C) ImplicitParamDecl(ImplicitParam, DC, L, Id, T);
+}
+
+FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ DeclarationName N, QualType T,
+ TypeSourceInfo *TInfo,
+ StorageClass S, bool isInline,
+ bool hasWrittenPrototype) {
+ FunctionDecl *New
+ = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, S, isInline);
+ New->HasWrittenPrototype = hasWrittenPrototype;
+ return New;
+}
+
+BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
+ return new (C) BlockDecl(DC, L);
+}
+
+EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
+ SourceLocation L,
+ IdentifierInfo *Id, QualType T,
+ Expr *E, const llvm::APSInt &V) {
+ return new (C) EnumConstantDecl(CD, L, Id, T, E, V);
+}
+
+void EnumConstantDecl::Destroy(ASTContext& C) {
+ if (Init) Init->Destroy(C);
+ Decl::Destroy(C);
+}
+
+TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ TypeSourceInfo *TInfo) {
+ return new (C) TypedefDecl(DC, L, Id, TInfo);
+}
+
+// Anchor TypedefDecl's vtable here.
+TypedefDecl::~TypedefDecl() {}
+
+FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ StringLiteral *Str) {
+ return new (C) FileScopeAsmDecl(DC, L, Str);
+}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 84aa81ca76db..863a1cbd03c4 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -448,7 +448,10 @@ bool DeclContext::classof(const Decl *D) {
}
DeclContext::~DeclContext() {
- delete static_cast<StoredDeclsMap*>(LookupPtr);
+ // FIXME: Currently ~ASTContext will delete the StoredDeclsMaps because
+ // ~DeclContext() is not guaranteed to be called when ASTContext uses
+ // a BumpPtrAllocator.
+ // delete static_cast<StoredDeclsMap*>(LookupPtr);
}
void DeclContext::DestroyDecls(ASTContext &C) {
@@ -622,7 +625,8 @@ DeclContext::LoadVisibleDeclsFromExternalStorage() const {
// Load the declaration IDs for all of the names visible in this
// context.
assert(!LookupPtr && "Have a lookup map before de-serialization?");
- StoredDeclsMap *Map = new StoredDeclsMap;
+ StoredDeclsMap *Map =
+ (StoredDeclsMap*) getParentASTContext().CreateStoredDeclsMap();
LookupPtr = Map;
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
(*Map)[Decls[I].Name].setFromDeclIDs(Decls[I].Declarations);
@@ -830,8 +834,11 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
if (isa<ClassTemplateSpecializationDecl>(D))
return;
- if (!LookupPtr)
- LookupPtr = new StoredDeclsMap;
+ ASTContext *C = 0;
+ if (!LookupPtr) {
+ C = &getParentASTContext();
+ LookupPtr = (StoredDeclsMap*) C->CreateStoredDeclsMap();
+ }
// Insert this declaration into the map.
StoredDeclsMap &Map = *static_cast<StoredDeclsMap*>(LookupPtr);
@@ -844,7 +851,10 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
// If it is possible that this is a redeclaration, check to see if there is
// already a decl for which declarationReplaces returns true. If there is
// one, just replace it and return.
- if (DeclNameEntries.HandleRedeclaration(getParentASTContext(), D))
+ if (!C)
+ C = &getParentASTContext();
+
+ if (DeclNameEntries.HandleRedeclaration(*C, D))
return;
// Put this declaration into the appropriate slot.
@@ -896,3 +906,18 @@ void StoredDeclsList::materializeDecls(ASTContext &Context) {
}
}
}
+
+//===----------------------------------------------------------------------===//
+// Creation and Destruction of StoredDeclsMaps. //
+//===----------------------------------------------------------------------===//
+
+void *ASTContext::CreateStoredDeclsMap() {
+ StoredDeclsMap *M = new StoredDeclsMap();
+ SDMs.push_back(M);
+ return M;
+}
+
+void ASTContext::ReleaseDeclContextMaps() {
+ for (std::vector<void*>::iterator I = SDMs.begin(), E = SDMs.end(); I!=E; ++I)
+ delete (StoredDeclsMap*) *I;
+}
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index fe6064df325a..b0569d68015f 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -25,18 +25,23 @@ using namespace clang;
// Decl Allocation/Deallocation Method Implementations
//===----------------------------------------------------------------------===//
-CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- CXXRecordDecl *PrevDecl,
- SourceLocation TKL)
- : RecordDecl(K, TK, DC, L, Id, PrevDecl, TKL),
- UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
+CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
+ : UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
Abstract(false), HasTrivialConstructor(true),
HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true),
HasTrivialDestructor(true), ComputedVisibleConversions(false),
Bases(0), NumBases(0), VBases(0), NumVBases(0),
+ Definition(D) {
+}
+
+CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ CXXRecordDecl *PrevDecl,
+ SourceLocation TKL)
+ : RecordDecl(K, TK, DC, L, Id, PrevDecl, TKL),
+ DefinitionData(PrevDecl ? PrevDecl->DefinitionData : 0),
TemplateOrInstantiation() { }
CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
@@ -57,31 +62,35 @@ CXXRecordDecl::~CXXRecordDecl() {
}
void CXXRecordDecl::Destroy(ASTContext &C) {
- C.Deallocate(Bases);
- C.Deallocate(VBases);
+ if (data().Definition == this) {
+ C.Deallocate(data().Bases);
+ C.Deallocate(data().VBases);
+ C.Deallocate(&data());
+ }
this->RecordDecl::Destroy(C);
}
void
-CXXRecordDecl::setBases(ASTContext &C,
- CXXBaseSpecifier const * const *Bases,
+CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
unsigned NumBases) {
+ ASTContext &C = getASTContext();
+
// C++ [dcl.init.aggr]p1:
// An aggregate is an array or a class (clause 9) with [...]
// no base classes [...].
- Aggregate = false;
+ data().Aggregate = false;
- if (this->Bases)
- C.Deallocate(this->Bases);
+ if (data().Bases)
+ C.Deallocate(data().Bases);
int vbaseCount = 0;
llvm::SmallVector<const CXXBaseSpecifier*, 8> UniqueVbases;
bool hasDirectVirtualBase = false;
- this->Bases = new(C) CXXBaseSpecifier [NumBases];
- this->NumBases = NumBases;
+ data().Bases = new(C) CXXBaseSpecifier [NumBases];
+ data().NumBases = NumBases;
for (unsigned i = 0; i < NumBases; ++i) {
- this->Bases[i] = *Bases[i];
+ data().Bases[i] = *Bases[i];
// Keep track of inherited vbases for this base class.
const CXXBaseSpecifier *Base = Bases[i];
QualType BaseType = Base->getType();
@@ -130,13 +139,13 @@ CXXRecordDecl::setBases(ASTContext &C,
}
if (vbaseCount > 0) {
// build AST for inhireted, direct or indirect, virtual bases.
- this->VBases = new (C) CXXBaseSpecifier [vbaseCount];
- this->NumVBases = vbaseCount;
+ data().VBases = new (C) CXXBaseSpecifier [vbaseCount];
+ data().NumVBases = vbaseCount;
for (int i = 0; i < vbaseCount; i++) {
QualType QT = UniqueVbases[i]->getType();
CXXRecordDecl *VBaseClassDecl
= cast<CXXRecordDecl>(QT->getAs<RecordType>()->getDecl());
- this->VBases[i] =
+ data().VBases[i] =
CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true,
VBaseClassDecl->getTagKind() == RecordDecl::TK_class,
UniqueVbases[i]->getAccessSpecifier(), QT);
@@ -239,32 +248,32 @@ CXXRecordDecl::addedConstructor(ASTContext &Context,
CXXConstructorDecl *ConDecl) {
assert(!ConDecl->isImplicit() && "addedConstructor - not for implicit decl");
// Note that we have a user-declared constructor.
- UserDeclaredConstructor = true;
+ data().UserDeclaredConstructor = true;
// C++ [dcl.init.aggr]p1:
// An aggregate is an array or a class (clause 9) with no
// user-declared constructors (12.1) [...].
- Aggregate = false;
+ data().Aggregate = false;
// C++ [class]p4:
// A POD-struct is an aggregate class [...]
- PlainOldData = false;
+ data().PlainOldData = false;
// C++ [class.ctor]p5:
// A constructor is trivial if it is an implicitly-declared default
// constructor.
// FIXME: C++0x: don't do this for "= default" default constructors.
- HasTrivialConstructor = false;
+ data().HasTrivialConstructor = false;
// Note when we have a user-declared copy constructor, which will
// suppress the implicit declaration of a copy constructor.
if (ConDecl->isCopyConstructor()) {
- UserDeclaredCopyConstructor = true;
+ data().UserDeclaredCopyConstructor = true;
// C++ [class.copy]p6:
// A copy constructor is trivial if it is implicitly declared.
// FIXME: C++0x: don't do this for "= default" copy constructors.
- HasTrivialCopyConstructor = false;
+ data().HasTrivialCopyConstructor = false;
}
}
@@ -295,17 +304,17 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
OpDecl->setCopyAssignment(true);
// Suppress the implicit declaration of a copy constructor.
- UserDeclaredCopyAssignment = true;
+ data().UserDeclaredCopyAssignment = true;
// C++ [class.copy]p11:
// A copy assignment operator is trivial if it is implicitly declared.
// FIXME: C++0x: don't do this for "= default" copy operators.
- HasTrivialCopyAssignment = false;
+ data().HasTrivialCopyAssignment = false;
// C++ [class]p4:
// A POD-struct is an aggregate class that [...] has no user-defined copy
// assignment operator [...].
- PlainOldData = false;
+ data().PlainOldData = false;
}
void
@@ -415,42 +424,42 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() {
// If root class, all conversions are visible.
if (bases_begin() == bases_end())
- return &Conversions;
+ return &data().Conversions;
// If visible conversion list is already evaluated, return it.
- if (ComputedVisibleConversions)
- return &VisibleConversions;
+ if (data().ComputedVisibleConversions)
+ return &data().VisibleConversions;
llvm::SmallPtrSet<CanQualType, 8> TopConversionsTypeSet;
collectConversionFunctions(TopConversionsTypeSet);
getNestedVisibleConversionFunctions(this, TopConversionsTypeSet,
TopConversionsTypeSet);
- ComputedVisibleConversions = true;
- return &VisibleConversions;
+ data().ComputedVisibleConversions = true;
+ return &data().VisibleConversions;
}
void CXXRecordDecl::addVisibleConversionFunction(
CXXConversionDecl *ConvDecl) {
assert(!ConvDecl->getDescribedFunctionTemplate() &&
"Conversion function templates should cast to FunctionTemplateDecl.");
- VisibleConversions.addDecl(ConvDecl);
+ data().VisibleConversions.addDecl(ConvDecl);
}
void CXXRecordDecl::addVisibleConversionFunction(
FunctionTemplateDecl *ConvDecl) {
assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
"Function template is not a conversion function template");
- VisibleConversions.addDecl(ConvDecl);
+ data().VisibleConversions.addDecl(ConvDecl);
}
void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) {
assert(!ConvDecl->getDescribedFunctionTemplate() &&
"Conversion function templates should cast to FunctionTemplateDecl.");
- Conversions.addDecl(ConvDecl);
+ data().Conversions.addDecl(ConvDecl);
}
void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) {
assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
"Function template is not a conversion function template");
- Conversions.addDecl(ConvDecl);
+ data().Conversions.addDecl(ConvDecl);
}
@@ -579,7 +588,8 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const {
// then this function is a usual deallocation function.
ASTContext &Context = getASTContext();
if (getNumParams() != 2 ||
- !Context.hasSameType(getParamDecl(1)->getType(), Context.getSizeType()))
+ !Context.hasSameUnqualifiedType(getParamDecl(1)->getType(),
+ Context.getSizeType()))
return false;
// This function is a usual deallocation function if there are no
@@ -604,7 +614,9 @@ static OverriddenMethodsMapTy *OverriddenMethods = 0;
void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
assert(MD->isCanonicalDecl() && "Method is not canonical!");
-
+ assert(!MD->getParent()->isDependentContext() &&
+ "Can't add an overridden method to a class template!");
+
// FIXME: The CXXMethodDecl dtor needs to remove and free the entry.
if (!OverriddenMethods)
@@ -671,42 +683,25 @@ bool CXXMethodDecl::hasInlineBody() const {
CXXBaseOrMemberInitializer::
CXXBaseOrMemberInitializer(ASTContext &Context,
- TypeSourceInfo *TInfo, CXXConstructorDecl *C,
- SourceLocation L,
- Expr **Args, unsigned NumArgs,
- SourceLocation R)
- : BaseOrMember(TInfo), Args(0), NumArgs(0), CtorOrAnonUnion(C),
+ TypeSourceInfo *TInfo,
+ SourceLocation L, Expr *Init, SourceLocation R)
+ : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0),
LParenLoc(L), RParenLoc(R)
{
- if (NumArgs > 0) {
- this->NumArgs = NumArgs;
- this->Args = new (Context) Stmt*[NumArgs];
- for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
- this->Args[Idx] = Args[Idx];
- }
}
CXXBaseOrMemberInitializer::
CXXBaseOrMemberInitializer(ASTContext &Context,
FieldDecl *Member, SourceLocation MemberLoc,
- CXXConstructorDecl *C, SourceLocation L,
- Expr **Args, unsigned NumArgs,
- SourceLocation R)
- : BaseOrMember(Member), MemberLocation(MemberLoc), Args(0), NumArgs(0),
- CtorOrAnonUnion(C), LParenLoc(L), RParenLoc(R)
+ SourceLocation L, Expr *Init, SourceLocation R)
+ : BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init),
+ AnonUnionMember(0), LParenLoc(L), RParenLoc(R)
{
- if (NumArgs > 0) {
- this->NumArgs = NumArgs;
- this->Args = new (Context) Stmt*[NumArgs];
- for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
- this->Args[Idx] = Args[Idx];
- }
}
void CXXBaseOrMemberInitializer::Destroy(ASTContext &Context) {
- for (unsigned I = 0; I != NumArgs; ++I)
- Args[I]->Destroy(Context);
- Context.Deallocate(Args);
+ if (Init)
+ Init->Destroy(Context);
this->~CXXBaseOrMemberInitializer();
}
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index ffda505aaab1..131e098d0467 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -111,8 +111,9 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
// Look through categories.
for (ObjCCategoryDecl *Category = OID->getCategoryList();
Category; Category = Category->getNextClassCategory()) {
- if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PropertyId))
- return P;
+ if (!Category->IsClassExtension())
+ if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PropertyId))
+ return P;
}
// Look through protocols.
for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(),
@@ -124,10 +125,11 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
return OID->getSuperClass()->FindPropertyDeclaration(PropertyId);
} else if (const ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(this)) {
// Look through protocols.
- for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(),
- E = OCD->protocol_end(); I != E; ++I) {
- if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
- return P;
+ if (!OCD->IsClassExtension())
+ for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(),
+ E = OCD->protocol_end(); I != E; ++I) {
+ if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
+ return P;
}
}
return 0;
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 32ac53d85be8..a625865ecdb3 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/PrettyPrinter.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -403,32 +404,51 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
CXXBaseOrMemberInitializer * BMInitializer = (*B);
if (B != CDecl->init_begin())
Out << ", ";
- bool hasArguments = (BMInitializer->arg_begin() !=
- BMInitializer->arg_end());
if (BMInitializer->isMemberInitializer()) {
FieldDecl *FD = BMInitializer->getMember();
Out << FD->getNameAsString();
+ } else {
+ Out << QualType(BMInitializer->getBaseClass(), 0).getAsString();
}
- else // FIXME. skip dependent types for now.
- if (const RecordType *RT =
- BMInitializer->getBaseClass()->getAs<RecordType>()) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(RT->getDecl());
- Out << BaseDecl->getNameAsString();
- }
- if (hasArguments) {
- Out << "(";
- for (CXXBaseOrMemberInitializer::const_arg_iterator BE =
- BMInitializer->const_arg_begin(),
- EE = BMInitializer->const_arg_end(); BE != EE; ++BE) {
- if (BE != BMInitializer->const_arg_begin())
- Out<< ", ";
- const Expr *Exp = (*BE);
- Exp->printPretty(Out, Context, 0, Policy, Indentation);
+
+ Out << "(";
+ if (!BMInitializer->getInit()) {
+ // Nothing to print
+ } else {
+ Expr *Init = BMInitializer->getInit();
+ if (CXXExprWithTemporaries *Tmp
+ = dyn_cast<CXXExprWithTemporaries>(Init))
+ Init = Tmp->getSubExpr();
+
+ Init = Init->IgnoreParens();
+
+ Expr *SimpleInit = 0;
+ Expr **Args = 0;
+ unsigned NumArgs = 0;
+ if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
+ Args = ParenList->getExprs();
+ NumArgs = ParenList->getNumExprs();
+ } else if (CXXConstructExpr *Construct
+ = dyn_cast<CXXConstructExpr>(Init)) {
+ Args = Construct->getArgs();
+ NumArgs = Construct->getNumArgs();
+ } else
+ SimpleInit = Init;
+
+ if (SimpleInit)
+ SimpleInit->printPretty(Out, Context, 0, Policy, Indentation);
+ else {
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ if (isa<CXXDefaultArgExpr>(Args[I]))
+ break;
+
+ if (I)
+ Out << ", ";
+ Args[I]->printPretty(Out, Context, 0, Policy, Indentation);
+ }
}
- Out << ")";
- } else
- Out << "()";
+ }
+ Out << ")";
}
}
}
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 75b3975322b2..d80db45f4557 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -213,7 +213,8 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) {
TemplateArgs.push_back(TemplateArgument(ParamType));
} else if (NonTypeTemplateParmDecl *NTTP =
dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
- Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(),
+ Expr *E = new (Context) DeclRefExpr(NTTP,
+ NTTP->getType().getNonReferenceType(),
NTTP->getLocation());
TemplateArgs.push_back(TemplateArgument(E));
} else {
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index ff810735bc81..19b58bcbaf03 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -66,27 +66,33 @@ public:
}
};
-bool operator<(DeclarationName LHS, DeclarationName RHS) {
+static int compareInt(unsigned A, unsigned B) {
+ return (A < B ? -1 : (A > B ? 1 : 0));
+}
+
+int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) {
if (LHS.getNameKind() != RHS.getNameKind())
- return LHS.getNameKind() < RHS.getNameKind();
+ return (LHS.getNameKind() < RHS.getNameKind() ? -1 : 1);
switch (LHS.getNameKind()) {
- case DeclarationName::Identifier:
- return LHS.getAsIdentifierInfo()->getName() <
- RHS.getAsIdentifierInfo()->getName();
+ case DeclarationName::Identifier: {
+ IdentifierInfo *LII = LHS.getAsIdentifierInfo();
+ IdentifierInfo *RII = RHS.getAsIdentifierInfo();
+ if (!LII) return RII ? -1 : 0;
+ if (!RII) return 1;
+
+ return LII->getName().compare(RII->getName());
+ }
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector: {
Selector LHSSelector = LHS.getObjCSelector();
Selector RHSSelector = RHS.getObjCSelector();
- for (unsigned I = 0,
- N = std::min(LHSSelector.getNumArgs(), RHSSelector.getNumArgs());
- I != N; ++I) {
+ unsigned LN = LHSSelector.getNumArgs(), RN = RHSSelector.getNumArgs();
+ for (unsigned I = 0, N = std::min(LN, RN); I != N; ++I) {
IdentifierInfo *LHSId = LHSSelector.getIdentifierInfoForSlot(I);
IdentifierInfo *RHSId = RHSSelector.getIdentifierInfoForSlot(I);
- if (!LHSId || !RHSId)
- return LHSId && !RHSId;
switch (LHSId->getName().compare(RHSId->getName())) {
case -1: return true;
@@ -94,27 +100,32 @@ bool operator<(DeclarationName LHS, DeclarationName RHS) {
default: break;
}
}
-
- return LHSSelector.getNumArgs() < RHSSelector.getNumArgs();
+
+ return compareInt(LN, RN);
}
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
- return QualTypeOrdering()(LHS.getCXXNameType(), RHS.getCXXNameType());
+ if (QualTypeOrdering()(LHS.getCXXNameType(), RHS.getCXXNameType()))
+ return -1;
+ if (QualTypeOrdering()(RHS.getCXXNameType(), LHS.getCXXNameType()))
+ return 1;
+ return 0;
case DeclarationName::CXXOperatorName:
- return LHS.getCXXOverloadedOperator() < RHS.getCXXOverloadedOperator();
+ return compareInt(LHS.getCXXOverloadedOperator(),
+ RHS.getCXXOverloadedOperator());
case DeclarationName::CXXLiteralOperatorName:
- return LHS.getCXXLiteralIdentifier()->getName() <
- RHS.getCXXLiteralIdentifier()->getName();
+ return LHS.getCXXLiteralIdentifier()->getName().compare(
+ RHS.getCXXLiteralIdentifier()->getName());
case DeclarationName::CXXUsingDirective:
- return false;
+ return 0;
}
- return false;
+ return 0;
}
} // end namespace clang
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index fa44b510e99a..4cb0aa4560de 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -99,8 +99,7 @@ void DeclRefExpr::computeDependence() {
else if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
if (Var->getType()->isIntegralType() &&
Var->getType().getCVRQualifiers() == Qualifiers::Const) {
- const VarDecl *Def = 0;
- if (const Expr *Init = Var->getDefinition(Def))
+ if (const Expr *Init = Var->getAnyInitializer())
if (Init->isValueDependent())
ValueDependent = true;
}
@@ -164,17 +163,18 @@ SourceRange DeclRefExpr::getSourceRange() const {
// FIXME: Maybe this should use DeclPrinter with a special "print predefined
// expr" policy instead.
-std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentType IT,
- const Decl *CurrentDecl) {
+std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
+ ASTContext &Context = CurrentDecl->getASTContext();
+
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
- if (IT != PrettyFunction)
+ if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual)
return FD->getNameAsString();
llvm::SmallString<256> Name;
llvm::raw_svector_ostream Out(Name);
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
- if (MD->isVirtual())
+ if (MD->isVirtual() && IT != PrettyFunctionNoVirtual)
Out << "virtual ";
if (MD->isStatic())
Out << "static ";
@@ -827,9 +827,17 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
case BinaryOperatorClass: {
const BinaryOperator *BO = cast<BinaryOperator>(this);
// Consider comma to have side effects if the LHS or RHS does.
- if (BO->getOpcode() == BinaryOperator::Comma)
+ if (BO->getOpcode() == BinaryOperator::Comma) {
+ // ((foo = <blah>), 0) is an idiom for hiding the result (and
+ // lvalue-ness) of an assignment written in a macro.
+ if (IntegerLiteral *IE =
+ dyn_cast<IntegerLiteral>(BO->getRHS()->IgnoreParens()))
+ if (IE->getValue() == 0)
+ return false;
+
return (BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) ||
BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx));
+ }
if (BO->isAssignmentOp())
return false;
@@ -1068,9 +1076,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
if (isa<FieldDecl>(Member)) {
if (m->isArrow())
return LV_Valid;
- Expr *BaseExp = m->getBase();
- return (BaseExp->getStmtClass() == ObjCPropertyRefExprClass) ?
- LV_SubObjCPropertySetting : BaseExp->isLvalue(Ctx);
+ return m->getBase()->isLvalue(Ctx);
}
// -- If it refers to a static member function [...], then
@@ -1093,8 +1099,11 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
if (m->isArrow())
return LV_Valid;
Expr *BaseExp = m->getBase();
- return (BaseExp->getStmtClass() == ObjCPropertyRefExprClass) ?
- LV_SubObjCPropertySetting : BaseExp->isLvalue(Ctx);
+ if (BaseExp->getStmtClass() == ObjCPropertyRefExprClass)
+ return LV_SubObjCPropertySetting;
+ return
+ (BaseExp->getStmtClass() == ObjCImplicitSetterGetterRefExprClass) ?
+ LV_SubObjCPropertyGetterSetting : BaseExp->isLvalue(Ctx);
}
case UnaryOperatorClass:
if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref)
@@ -1205,6 +1214,9 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
case CXXBindTemporaryExprClass:
return cast<CXXBindTemporaryExpr>(this)->getSubExpr()->
isLvalueInternal(Ctx);
+ case CXXBindReferenceExprClass:
+ // Something that's bound to a reference is always an lvalue.
+ return LV_Valid;
case ConditionalOperatorClass: {
// Complicated handling is only for C++.
if (!Ctx.getLangOptions().CPlusPlus)
@@ -1281,7 +1293,9 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const {
}
return MLV_InvalidExpression;
case LV_MemberFunction: return MLV_MemberFunction;
- case LV_SubObjCPropertySetting: return MLV_SubObjCPropertySetting;
+ case LV_SubObjCPropertySetting: return MLV_SubObjCPropertySetting;
+ case LV_SubObjCPropertyGetterSetting:
+ return MLV_SubObjCPropertyGetterSetting;
}
// The following is illegal:
@@ -1594,6 +1608,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::DependentScopeDeclRefExprClass:
case Expr::CXXConstructExprClass:
case Expr::CXXBindTemporaryExprClass:
+ case Expr::CXXBindReferenceExprClass:
case Expr::CXXExprWithTemporariesClass:
case Expr::CXXTemporaryObjectExprClass:
case Expr::CXXUnresolvedConstructExprClass:
@@ -1613,7 +1628,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::BlockExprClass:
case Expr::BlockDeclRefExprClass:
case Expr::NoStmtClass:
- case Expr::ExprClass:
return ICEDiag(2, E->getLocStart());
case Expr::GNUNullExprClass:
@@ -1650,30 +1664,22 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
if (Quals.hasVolatile() || !Quals.hasConst())
return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
- // Look for the definition of this variable, which will actually have
- // an initializer.
- const VarDecl *Def = 0;
- const Expr *Init = Dcl->getDefinition(Def);
+ // Look for a declaration of this variable that has an initializer.
+ const VarDecl *ID = 0;
+ const Expr *Init = Dcl->getAnyInitializer(ID);
if (Init) {
- if (Def->isInitKnownICE()) {
+ if (ID->isInitKnownICE()) {
// We have already checked whether this subexpression is an
// integral constant expression.
- if (Def->isInitICE())
+ if (ID->isInitICE())
return NoDiag();
else
return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
}
- // C++ [class.static.data]p4:
- // If a static data member is of const integral or const
- // enumeration type, its declaration in the class definition can
- // specify a constant-initializer which shall be an integral
- // constant expression (5.19). In that case, the member can appear
- // in integral constant expressions.
- if (Def->isOutOfLine()) {
- Dcl->setInitKnownICE(false);
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
- }
+ // It's an ICE whether or not the definition we found is
+ // out-of-line. See DR 721 and the discussion in Clang PR
+ // 6206 for details.
if (Dcl->isCheckingICE()) {
return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
@@ -1810,9 +1816,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
}
}
}
- case Expr::CastExprClass:
case Expr::ImplicitCastExprClass:
- case Expr::ExplicitCastExprClass:
case Expr::CStyleCastExprClass:
case Expr::CXXFunctionalCastExprClass:
case Expr::CXXNamedCastExprClass:
@@ -1954,6 +1958,13 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx,
FieldDecl *Expr::getBitField() {
Expr *E = this->IgnoreParens();
+ while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ if (ICE->isLvalueCast() && ICE->getCastKind() == CastExpr::CK_NoOp)
+ E = ICE->getSubExpr()->IgnoreParens();
+ else
+ break;
+ }
+
if (MemberExpr *MemRef = dyn_cast<MemberExpr>(E))
if (FieldDecl *Field = dyn_cast<FieldDecl>(MemRef->getMemberDecl()))
if (Field->isBitField())
@@ -1966,6 +1977,25 @@ FieldDecl *Expr::getBitField() {
return 0;
}
+bool Expr::refersToVectorElement() const {
+ const Expr *E = this->IgnoreParens();
+
+ while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ if (ICE->isLvalueCast() && ICE->getCastKind() == CastExpr::CK_NoOp)
+ E = ICE->getSubExpr()->IgnoreParens();
+ else
+ break;
+ }
+
+ if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E))
+ return ASE->getBase()->getType()->isVectorType();
+
+ if (isa<ExtVectorElementExpr>(E))
+ return true;
+
+ return false;
+}
+
/// isArrow - Return true if the base expression is a pointer to vector,
/// return false if the base expression is a vector.
bool ExtVectorElementExpr::isArrow() const {
@@ -2030,14 +2060,15 @@ void ExtVectorElementExpr::getEncodedElementAccess(
}
// constructor for instance messages.
-ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo,
- QualType retType, ObjCMethodDecl *mproto,
- SourceLocation LBrac, SourceLocation RBrac,
- Expr **ArgExprs, unsigned nargs)
+ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, Expr *receiver,
+ Selector selInfo,
+ QualType retType, ObjCMethodDecl *mproto,
+ SourceLocation LBrac, SourceLocation RBrac,
+ Expr **ArgExprs, unsigned nargs)
: Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo),
MethodProto(mproto) {
NumArgs = nargs;
- SubExprs = new Stmt*[NumArgs+1];
+ SubExprs = new (C) Stmt*[NumArgs+1];
SubExprs[RECEIVER] = receiver;
if (NumArgs) {
for (unsigned i = 0; i != NumArgs; ++i)
@@ -2049,14 +2080,15 @@ ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo,
// constructor for class messages.
// FIXME: clsName should be typed to ObjCInterfaceType
-ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo,
- QualType retType, ObjCMethodDecl *mproto,
- SourceLocation LBrac, SourceLocation RBrac,
- Expr **ArgExprs, unsigned nargs)
+ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName,
+ Selector selInfo, QualType retType,
+ ObjCMethodDecl *mproto,
+ SourceLocation LBrac, SourceLocation RBrac,
+ Expr **ArgExprs, unsigned nargs)
: Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo),
MethodProto(mproto) {
NumArgs = nargs;
- SubExprs = new Stmt*[NumArgs+1];
+ SubExprs = new (C) Stmt*[NumArgs+1];
SubExprs[RECEIVER] = (Expr*) ((uintptr_t) clsName | IsClsMethDeclUnknown);
if (NumArgs) {
for (unsigned i = 0; i != NumArgs; ++i)
@@ -2067,14 +2099,15 @@ ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo,
}
// constructor for class messages.
-ObjCMessageExpr::ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo,
- QualType retType, ObjCMethodDecl *mproto,
- SourceLocation LBrac, SourceLocation RBrac,
- Expr **ArgExprs, unsigned nargs)
+ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, ObjCInterfaceDecl *cls,
+ Selector selInfo, QualType retType,
+ ObjCMethodDecl *mproto, SourceLocation LBrac,
+ SourceLocation RBrac, Expr **ArgExprs,
+ unsigned nargs)
: Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo),
MethodProto(mproto) {
NumArgs = nargs;
- SubExprs = new Stmt*[NumArgs+1];
+ SubExprs = new (C) Stmt*[NumArgs+1];
SubExprs[RECEIVER] = (Expr*) ((uintptr_t) cls | IsClsMethDeclKnown);
if (NumArgs) {
for (unsigned i = 0; i != NumArgs; ++i)
@@ -2109,6 +2142,13 @@ void ObjCMessageExpr::setClassInfo(const ObjCMessageExpr::ClassInfo &CI) {
SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.first | IsClsMethDeclKnown);
}
+void ObjCMessageExpr::DoDestroy(ASTContext &C) {
+ DestroyChildren(C);
+ if (SubExprs)
+ C.Deallocate(SubExprs);
+ this->~ObjCMessageExpr();
+ C.Deallocate((void*) this);
+}
bool ChooseExpr::isConditionTrue(ASTContext &C) const {
return getCond()->EvaluateAsInt(C) != 0;
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index a6574efda8ee..f4b8333dd3ae 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -73,7 +73,7 @@ Stmt::child_iterator CXXZeroInitValueExpr::child_end() {
}
// CXXNewExpr
-CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew,
+CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
Expr **placementArgs, unsigned numPlaceArgs,
bool parenTypeId, Expr *arraySize,
CXXConstructorDecl *constructor, bool initializer,
@@ -87,7 +87,7 @@ CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew,
OperatorDelete(operatorDelete), Constructor(constructor),
StartLoc(startLoc), EndLoc(endLoc) {
unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs;
- SubExprs = new Stmt*[TotalSize];
+ SubExprs = new (C) Stmt*[TotalSize];
unsigned i = 0;
if (Array)
SubExprs[i++] = arraySize;
@@ -98,6 +98,14 @@ CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew,
assert(i == TotalSize);
}
+void CXXNewExpr::DoDestroy(ASTContext &C) {
+ DestroyChildren(C);
+ if (SubExprs)
+ C.Deallocate(SubExprs);
+ this->~CXXNewExpr();
+ C.Deallocate((void*)this);
+}
+
Stmt::child_iterator CXXNewExpr::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator CXXNewExpr::child_end() {
return &SubExprs[0] + Array + getNumPlacementArgs() + getNumConstructorArgs();
@@ -116,6 +124,7 @@ Stmt::child_iterator CXXPseudoDestructorExpr::child_end() {
// UnresolvedLookupExpr
UnresolvedLookupExpr *
UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent,
+ CXXRecordDecl *NamingClass,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange, DeclarationName Name,
SourceLocation NameLoc, bool ADL,
@@ -125,7 +134,8 @@ UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent,
ExplicitTemplateArgumentList::sizeFor(Args));
UnresolvedLookupExpr *ULE
= new (Mem) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy,
- Dependent, Qualifier, QualifierRange,
+ Dependent, NamingClass,
+ Qualifier, QualifierRange,
Name, NameLoc, ADL,
/*Overload*/ true,
/*ExplicitTemplateArgs*/ true);
@@ -135,10 +145,9 @@ UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent,
return ULE;
}
-bool UnresolvedLookupExpr::
- ComputeDependence(UnresolvedSetImpl::const_iterator Begin,
- UnresolvedSetImpl::const_iterator End,
- const TemplateArgumentListInfo *Args) {
+bool OverloadExpr::ComputeDependence(UnresolvedSetIterator Begin,
+ UnresolvedSetIterator End,
+ const TemplateArgumentListInfo *Args) {
for (UnresolvedSetImpl::const_iterator I = Begin; I != End; ++I)
if ((*I)->getDeclContext()->isDependentContext())
return true;
@@ -393,6 +402,19 @@ void CXXBindTemporaryExpr::DoDestroy(ASTContext &C) {
C.Deallocate(this);
}
+CXXBindReferenceExpr *CXXBindReferenceExpr::Create(ASTContext &C, Expr *SubExpr,
+ bool ExtendsLifetime,
+ bool RequiresTemporaryCopy) {
+ return new (C) CXXBindReferenceExpr(SubExpr,
+ ExtendsLifetime,
+ RequiresTemporaryCopy);
+}
+
+void CXXBindReferenceExpr::DoDestroy(ASTContext &C) {
+ this->~CXXBindReferenceExpr();
+ C.Deallocate(this);
+}
+
CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
CXXConstructorDecl *Cons,
QualType writtenTy,
@@ -409,22 +431,26 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool Elidable,
Expr **Args, unsigned NumArgs,
- bool ZeroInitialization) {
+ bool ZeroInitialization,
+ bool BaseInitialization) {
return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D,
- Elidable, Args, NumArgs, ZeroInitialization);
+ Elidable, Args, NumArgs, ZeroInitialization,
+ BaseInitialization);
}
CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool elidable,
Expr **args, unsigned numargs,
- bool ZeroInitialization)
+ bool ZeroInitialization,
+ bool BaseInitialization)
: Expr(SC, T,
T->isDependentType(),
(T->isDependentType() ||
CallExpr::hasAnyValueDependentArguments(args, numargs))),
Constructor(D), Loc(Loc), Elidable(elidable),
- ZeroInitialization(ZeroInitialization), Args(0), NumArgs(numargs)
+ ZeroInitialization(ZeroInitialization),
+ BaseInitialization(BaseInitialization), Args(0), NumArgs(numargs)
{
if (NumArgs) {
Args = new (C) Stmt*[NumArgs];
@@ -491,6 +517,15 @@ Stmt::child_iterator CXXBindTemporaryExpr::child_end() {
return &SubExpr + 1;
}
+// CXXBindReferenceExpr
+Stmt::child_iterator CXXBindReferenceExpr::child_begin() {
+ return &SubExpr;
+}
+
+Stmt::child_iterator CXXBindReferenceExpr::child_end() {
+ return &SubExpr + 1;
+}
+
// CXXConstructExpr
Stmt::child_iterator CXXConstructExpr::child_begin() {
return &Args[0];
@@ -618,15 +653,13 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent,
DeclarationName MemberName,
SourceLocation MemberLoc,
const TemplateArgumentListInfo *TemplateArgs)
- : Expr(UnresolvedMemberExprClass, T, Dependent, Dependent),
- Base(Base), BaseType(BaseType), IsArrow(IsArrow),
- HasUnresolvedUsing(HasUnresolvedUsing),
- HasExplicitTemplateArgs(TemplateArgs != 0),
- OperatorLoc(OperatorLoc),
- Qualifier(Qualifier), QualifierRange(QualifierRange),
- MemberName(MemberName), MemberLoc(MemberLoc) {
+ : OverloadExpr(UnresolvedMemberExprClass, T, Dependent,
+ Qualifier, QualifierRange, MemberName, MemberLoc,
+ TemplateArgs != 0),
+ IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing),
+ Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc) {
if (TemplateArgs)
- getExplicitTemplateArgs()->initializeFrom(*TemplateArgs);
+ getExplicitTemplateArgs().initializeFrom(*TemplateArgs);
}
UnresolvedMemberExpr *
@@ -651,6 +684,35 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent,
Member, MemberLoc, TemplateArgs);
}
+CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const {
+ // Unlike for UnresolvedLookupExpr, it is very easy to re-derive this.
+
+ // If there was a nested name specifier, it names the naming class.
+ // It can't be dependent: after all, we were actually able to do the
+ // lookup.
+ const RecordType *RT;
+ if (getQualifier()) {
+ Type *T = getQualifier()->getAsType();
+ assert(T && "qualifier in member expression does not name type");
+ RT = T->getAs<RecordType>();
+ assert(RT && "qualifier in member expression does not name record");
+
+ // Otherwise the naming class must have been the base class.
+ } else {
+ QualType BaseType = getBaseType().getNonReferenceType();
+ if (isArrow()) {
+ const PointerType *PT = BaseType->getAs<PointerType>();
+ assert(PT && "base of arrow member access is not pointer");
+ BaseType = PT->getPointeeType();
+ }
+
+ RT = BaseType->getAs<RecordType>();
+ assert(RT && "base of member expression does not name record");
+ }
+
+ return cast<CXXRecordDecl>(RT->getDecl());
+}
+
Stmt::child_iterator UnresolvedMemberExpr::child_begin() {
return child_iterator(&Base);
}
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 086249c811f9..1a44cd02d9c1 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -263,8 +263,7 @@ APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) {
if (!VD->getType()->isReferenceType())
return APValue(E);
// FIXME: Check whether VD might be overridden!
- const VarDecl *Def = 0;
- if (const Expr *Init = VD->getDefinition(Def))
+ if (const Expr *Init = VD->getAnyInitializer())
return Visit(const_cast<Expr *>(Init));
}
@@ -813,7 +812,7 @@ public:
return false;
}
- bool VisitCallExpr(const CallExpr *E);
+ bool VisitCallExpr(CallExpr *E);
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitUnaryOperator(const UnaryOperator *E);
bool VisitConditionalOperator(const ConditionalOperator *E);
@@ -849,8 +848,8 @@ public:
bool VisitUnaryImag(const UnaryOperator *E);
private:
- unsigned GetAlignOfExpr(const Expr *E);
- unsigned GetAlignOfType(QualType T);
+ CharUnits GetAlignOfExpr(const Expr *E);
+ CharUnits GetAlignOfType(QualType T);
// FIXME: Missing: array subscript of vector, member of vector
};
} // end anonymous namespace
@@ -879,9 +878,12 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
// In C, they can also be folded, although they are not ICEs.
if (Info.Ctx.getCanonicalType(E->getType()).getCVRQualifiers()
== Qualifiers::Const) {
+
+ if (isa<ParmVarDecl>(D))
+ return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- const VarDecl *Def = 0;
- if (const Expr *Init = VD->getDefinition(Def)) {
+ if (const Expr *Init = VD->getAnyInitializer()) {
if (APValue *V = VD->getEvaluatedValue()) {
if (V->isInt())
return Success(V->getInt(), E);
@@ -965,7 +967,7 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) {
return -1;
}
-bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
+bool IntExprEvaluator::VisitCallExpr(CallExpr *E) {
switch (E->isBuiltinCall(Info.Ctx)) {
default:
return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
@@ -1020,6 +1022,9 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
Operand = Info.Ctx.Target.getEHDataRegisterNumber(Operand);
return Success(Operand, E);
}
+
+ case Builtin::BI__builtin_expect:
+ return Visit(E->getArg(0));
}
}
@@ -1288,7 +1293,7 @@ bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) {
return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr());
}
-unsigned IntExprEvaluator::GetAlignOfType(QualType T) {
+CharUnits IntExprEvaluator::GetAlignOfType(QualType T) {
// C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
// the result is the size of the referenced type."
// C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
@@ -1300,20 +1305,22 @@ unsigned IntExprEvaluator::GetAlignOfType(QualType T) {
unsigned CharSize = Info.Ctx.Target.getCharWidth();
// __alignof is defined to return the preferred alignment.
- return Info.Ctx.getPreferredTypeAlign(T.getTypePtr()) / CharSize;
+ return CharUnits::fromQuantity(
+ Info.Ctx.getPreferredTypeAlign(T.getTypePtr()) / CharSize);
}
-unsigned IntExprEvaluator::GetAlignOfExpr(const Expr *E) {
+CharUnits IntExprEvaluator::GetAlignOfExpr(const Expr *E) {
E = E->IgnoreParens();
// alignof decl is always accepted, even if it doesn't make sense: we default
// to 1 in those cases.
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- return Info.Ctx.getDeclAlignInBytes(DRE->getDecl(), /*RefAsPointee*/true);
+ return Info.Ctx.getDeclAlign(DRE->getDecl(),
+ /*RefAsPointee*/true);
if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
- return Info.Ctx.getDeclAlignInBytes(ME->getMemberDecl(),
- /*RefAsPointee*/true);
+ return Info.Ctx.getDeclAlign(ME->getMemberDecl(),
+ /*RefAsPointee*/true);
return GetAlignOfType(E->getType());
}
@@ -1325,9 +1332,9 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
// Handle alignof separately.
if (!E->isSizeOf()) {
if (E->isArgumentType())
- return Success(GetAlignOfType(E->getArgumentType()), E);
+ return Success(GetAlignOfType(E->getArgumentType()).getQuantity(), E);
else
- return Success(GetAlignOfExpr(E->getArgumentExpr()), E);
+ return Success(GetAlignOfExpr(E->getArgumentExpr()).getQuantity(), E);
}
QualType SrcTy = E->getTypeOfArgument();
diff --git a/lib/AST/Makefile b/lib/AST/Makefile
index f7d4e9f62d5f..8afc629d6b3b 100644
--- a/lib/AST/Makefile
+++ b/lib/AST/Makefile
@@ -14,7 +14,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangAST
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 0aa01801959c..50acd15fde05 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -119,11 +119,10 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD,
return;
}
}
- if (i->isVirtual()) {
- SelectPrimaryVBase(Base, FirstPrimary);
- if (PrimaryBase.getBase())
- return;
- }
+ assert(i->isVirtual());
+ SelectPrimaryVBase(Base, FirstPrimary);
+ if (PrimaryBase.getBase())
+ return;
}
}
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 104e3361892f..8347249a466b 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -35,6 +35,7 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
// Intialize the table on the first use.
Initialized = true;
+#define ABSTRACT_EXPR(CLASS, PARENT)
#define STMT(CLASS, PARENT) \
StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS; \
StmtClassInfo[(unsigned)Stmt::CLASS##Class].Size = sizeof(CLASS);
@@ -132,9 +133,8 @@ Expr *AsmStmt::getOutputExpr(unsigned i) {
/// getOutputConstraint - Return the constraint string for the specified
/// output operand. All output constraints are known to be non-empty (either
/// '=' or '+').
-std::string AsmStmt::getOutputConstraint(unsigned i) const {
- return std::string(Constraints[i]->getStrData(),
- Constraints[i]->getByteLength());
+llvm::StringRef AsmStmt::getOutputConstraint(unsigned i) const {
+ return getOutputConstraintLiteral(i)->getString();
}
/// getNumPlusOperands - Return the number of output operands that have a "+"
@@ -147,40 +147,52 @@ unsigned AsmStmt::getNumPlusOperands() const {
return Res;
}
-
-
Expr *AsmStmt::getInputExpr(unsigned i) {
return cast<Expr>(Exprs[i + NumOutputs]);
}
/// getInputConstraint - Return the specified input constraint. Unlike output
/// constraints, these can be empty.
-std::string AsmStmt::getInputConstraint(unsigned i) const {
- return std::string(Constraints[i + NumOutputs]->getStrData(),
- Constraints[i + NumOutputs]->getByteLength());
+llvm::StringRef AsmStmt::getInputConstraint(unsigned i) const {
+ return getInputConstraintLiteral(i)->getString();
}
-void AsmStmt::setOutputsAndInputs(unsigned NumOutputs,
- unsigned NumInputs,
- const std::string *Names,
- StringLiteral **Constraints,
- Stmt **Exprs) {
+void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C,
+ IdentifierInfo **Names,
+ StringLiteral **Constraints,
+ Stmt **Exprs,
+ unsigned NumOutputs,
+ unsigned NumInputs,
+ StringLiteral **Clobbers,
+ unsigned NumClobbers) {
this->NumOutputs = NumOutputs;
this->NumInputs = NumInputs;
- this->Names.clear();
- this->Names.insert(this->Names.end(), Names, Names + NumOutputs + NumInputs);
- this->Constraints.clear();
- this->Constraints.insert(this->Constraints.end(),
- Constraints, Constraints + NumOutputs + NumInputs);
- this->Exprs.clear();
- this->Exprs.insert(this->Exprs.end(), Exprs, Exprs + NumOutputs + NumInputs);
+ this->NumClobbers = NumClobbers;
+
+ unsigned NumExprs = NumOutputs + NumInputs;
+
+ C.Deallocate(this->Names);
+ this->Names = new (C) IdentifierInfo*[NumExprs];
+ std::copy(Names, Names + NumExprs, this->Names);
+
+ C.Deallocate(this->Exprs);
+ this->Exprs = new (C) Stmt*[NumExprs];
+ std::copy(Exprs, Exprs + NumExprs, this->Exprs);
+
+ C.Deallocate(this->Constraints);
+ this->Constraints = new (C) StringLiteral*[NumExprs];
+ std::copy(Constraints, Constraints + NumExprs, this->Constraints);
+
+ C.Deallocate(this->Clobbers);
+ this->Clobbers = new (C) StringLiteral*[NumClobbers];
+ std::copy(Clobbers, Clobbers + NumClobbers, this->Clobbers);
}
/// getNamedOperand - Given a symbolic operand reference like %[foo],
/// translate this into a numeric value needed to reference the same operand.
/// This returns -1 if the operand name is invalid.
-int AsmStmt::getNamedOperand(const std::string &SymbolicName) const {
+int AsmStmt::getNamedOperand(llvm::StringRef SymbolicName) const {
unsigned NumPlusOperands = 0;
// Check if this is an output operand.
@@ -197,11 +209,6 @@ int AsmStmt::getNamedOperand(const std::string &SymbolicName) const {
return -1;
}
-void AsmStmt::setClobbers(StringLiteral **Clobbers, unsigned NumClobbers) {
- this->Clobbers.clear();
- this->Clobbers.insert(this->Clobbers.end(), Clobbers, Clobbers + NumClobbers);
-}
-
/// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing
/// it into pieces. If the asm string is erroneous, emit errors and return
/// true, otherwise return false.
@@ -313,7 +320,7 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
if (NameEnd == CurPtr)
return diag::err_asm_empty_symbolic_operand_name;
- std::string SymbolicName(CurPtr, NameEnd);
+ llvm::StringRef SymbolicName(CurPtr, NameEnd - CurPtr);
int N = getNamedOperand(SymbolicName);
if (N == -1) {
@@ -332,26 +339,39 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
}
}
+QualType CXXCatchStmt::getCaughtType() const {
+ if (ExceptionDecl)
+ return ExceptionDecl->getType();
+ return QualType();
+}
+
//===----------------------------------------------------------------------===//
// Constructors
//===----------------------------------------------------------------------===//
-AsmStmt::AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile,
- bool msasm, unsigned numoutputs, unsigned numinputs,
- std::string *names, StringLiteral **constraints,
+AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
+ bool isvolatile, bool msasm,
+ unsigned numoutputs, unsigned numinputs,
+ IdentifierInfo **names, StringLiteral **constraints,
Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
StringLiteral **clobbers, SourceLocation rparenloc)
: Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr)
, IsSimple(issimple), IsVolatile(isvolatile), MSAsm(msasm)
- , NumOutputs(numoutputs), NumInputs(numinputs) {
- for (unsigned i = 0, e = numinputs + numoutputs; i != e; i++) {
- Names.push_back(names[i]);
- Exprs.push_back(exprs[i]);
- Constraints.push_back(constraints[i]);
- }
+ , NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) {
- for (unsigned i = 0; i != numclobbers; i++)
- Clobbers.push_back(clobbers[i]);
+ unsigned NumExprs = NumOutputs +NumInputs;
+
+ Names = new (C) IdentifierInfo*[NumExprs];
+ std::copy(names, names + NumExprs, Names);
+
+ Exprs = new (C) Stmt*[NumExprs];
+ std::copy(exprs, exprs + NumExprs, Exprs);
+
+ Constraints = new (C) StringLiteral*[NumExprs];
+ std::copy(constraints, constraints + NumExprs, Constraints);
+
+ Clobbers = new (C) StringLiteral*[NumClobbers];
+ std::copy(clobbers, clobbers + NumClobbers, Clobbers);
}
ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect,
@@ -387,6 +407,24 @@ ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc,
RParenLoc = rparenloc;
}
+CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc,
+ Stmt *tryBlock, Stmt **handlers,
+ unsigned numHandlers) {
+ std::size_t Size = sizeof(CXXTryStmt);
+ Size += ((numHandlers + 1) * sizeof(Stmt));
+
+ void *Mem = C.Allocate(Size, llvm::alignof<CXXTryStmt>());
+ return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers, numHandlers);
+}
+
+CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
+ Stmt **handlers, unsigned numHandlers)
+ : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(numHandlers) {
+ Stmt **Stmts = reinterpret_cast<Stmt **>(this + 1);
+ Stmts[0] = tryBlock;
+ std::copy(handlers, handlers + NumHandlers, Stmts + 1);
+}
+
//===----------------------------------------------------------------------===//
// AST Destruction.
//===----------------------------------------------------------------------===//
@@ -453,6 +491,18 @@ void WhileStmt::DoDestroy(ASTContext &C) {
BranchDestroy(C, this, SubExprs, END_EXPR);
}
+void AsmStmt::DoDestroy(ASTContext &C) {
+ DestroyChildren(C);
+
+ C.Deallocate(Names);
+ C.Deallocate(Constraints);
+ C.Deallocate(Exprs);
+ C.Deallocate(Clobbers);
+
+ this->~AsmStmt();
+ C.Deallocate((void *)this);
+}
+
//===----------------------------------------------------------------------===//
// Child Iterators for iterating over subexpressions/substatements
//===----------------------------------------------------------------------===//
@@ -566,10 +616,10 @@ Stmt::child_iterator ReturnStmt::child_end() {
// AsmStmt
Stmt::child_iterator AsmStmt::child_begin() {
- return Exprs.empty() ? 0 : &Exprs[0];
+ return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0];
}
Stmt::child_iterator AsmStmt::child_end() {
- return Exprs.empty() ? 0 : &Exprs[0] + Exprs.size();
+ return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0] + NumOutputs + NumInputs;
}
// ObjCAtCatchStmt
@@ -615,19 +665,11 @@ Stmt::child_iterator CXXCatchStmt::child_end() {
return &HandlerBlock + 1;
}
-QualType CXXCatchStmt::getCaughtType() const {
- if (ExceptionDecl)
- return ExceptionDecl->getType();
- return QualType();
-}
-
// CXXTryStmt
-Stmt::child_iterator CXXTryStmt::child_begin() { return &Stmts[0]; }
-Stmt::child_iterator CXXTryStmt::child_end() { return &Stmts[0]+Stmts.size(); }
+Stmt::child_iterator CXXTryStmt::child_begin() {
+ return reinterpret_cast<Stmt **>(this + 1);
+}
-CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
- Stmt **handlers, unsigned numHandlers)
- : Stmt(CXXTryStmtClass), TryLoc(tryLoc) {
- Stmts.push_back(tryBlock);
- Stmts.insert(Stmts.end(), handlers, handlers + numHandlers);
+Stmt::child_iterator CXXTryStmt::child_end() {
+ return reinterpret_cast<Stmt **>(this + 1) + NumHandlers + 1;
}
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index ae76526b7939..ba6218be1426 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -472,6 +472,8 @@ void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) {
DumpExpr(Node);
+ CXXConstructorDecl *Ctor = Node->getConstructor();
+ DumpType(Ctor->getType());
if (Node->isElidable())
OS << " elidable";
}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index bbb904de79b3..3ae306d3c7ac 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1038,6 +1038,10 @@ void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
PrintExpr(Node->getSubExpr());
}
+void StmtPrinter::VisitCXXBindReferenceExpr(CXXBindReferenceExpr *Node) {
+ PrintExpr(Node->getSubExpr());
+}
+
void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) {
OS << Node->getType().getAsString();
OS << "(";
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index b74e1ef0bab4..3a19ec212c14 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -465,6 +465,10 @@ void StmtProfiler::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *S) {
const_cast<CXXDestructorDecl *>(S->getTemporary()->getDestructor()));
}
+void StmtProfiler::VisitCXXBindReferenceExpr(CXXBindReferenceExpr *S) {
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitCXXConstructExpr(CXXConstructExpr *S) {
VisitExpr(S);
VisitDecl(S->getConstructor());
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index edfb580cc35f..76cc38292064 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -339,21 +339,18 @@ const RecordType *Type::getAsUnionType() const {
return 0;
}
-ObjCInterfaceType::ObjCInterfaceType(ASTContext &Ctx, QualType Canonical,
+ObjCInterfaceType::ObjCInterfaceType(QualType Canonical,
ObjCInterfaceDecl *D,
ObjCProtocolDecl **Protos, unsigned NumP) :
Type(ObjCInterface, Canonical, /*Dependent=*/false),
- Decl(D), Protocols(0), NumProtocols(NumP)
+ Decl(D), NumProtocols(NumP)
{
- if (NumProtocols) {
- Protocols = new (Ctx) ObjCProtocolDecl*[NumProtocols];
- memcpy(Protocols, Protos, NumProtocols * sizeof(*Protocols));
- }
+ if (NumProtocols)
+ memcpy(reinterpret_cast<ObjCProtocolDecl**>(this + 1), Protos,
+ NumProtocols * sizeof(*Protos));
}
void ObjCInterfaceType::Destroy(ASTContext& C) {
- if (Protocols)
- C.Deallocate(Protocols);
this->~ObjCInterfaceType();
C.Deallocate(this);
}
@@ -372,22 +369,18 @@ bool Type::isObjCQualifiedInterfaceType() const {
return getAsObjCQualifiedInterfaceType() != 0;
}
-ObjCObjectPointerType::ObjCObjectPointerType(ASTContext &Ctx,
- QualType Canonical, QualType T,
+ObjCObjectPointerType::ObjCObjectPointerType(QualType Canonical, QualType T,
ObjCProtocolDecl **Protos,
unsigned NumP) :
Type(ObjCObjectPointer, Canonical, /*Dependent=*/false),
- PointeeType(T), Protocols(NULL), NumProtocols(NumP)
+ PointeeType(T), NumProtocols(NumP)
{
- if (NumProtocols) {
- Protocols = new (Ctx) ObjCProtocolDecl*[NumProtocols];
- memcpy(Protocols, Protos, NumProtocols * sizeof(*Protocols));
- }
+ if (NumProtocols)
+ memcpy(reinterpret_cast<ObjCProtocolDecl **>(this + 1), Protos,
+ NumProtocols * sizeof(*Protos));
}
void ObjCObjectPointerType::Destroy(ASTContext& C) {
- if (Protocols)
- C.Deallocate(Protocols);
this->~ObjCObjectPointerType();
C.Deallocate(this);
}
@@ -720,6 +713,19 @@ bool Type::isPromotableIntegerType() const {
default:
return false;
}
+
+ // Enumerated types are promotable to their compatible integer types
+ // (C99 6.3.1.1) a.k.a. its underlying type (C++ [conv.prom]p2).
+ if (const EnumType *ET = getAs<EnumType>()){
+ if (this->isDependentType() || ET->getDecl()->getPromotionType().isNull())
+ return false;
+
+ const BuiltinType *BT
+ = ET->getDecl()->getPromotionType()->getAs<BuiltinType>();
+ return BT->getKind() == BuiltinType::Int
+ || BT->getKind() == BuiltinType::UInt;
+ }
+
return false;
}
@@ -797,12 +803,24 @@ const char *BuiltinType::getName(const LangOptions &LO) const {
}
}
+llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) {
+ switch (CC) {
+ case CC_Default: llvm_unreachable("no name for default cc");
+ default: return "";
+
+ case CC_C: return "cdecl";
+ case CC_X86StdCall: return "stdcall";
+ case CC_X86FastCall: return "fastcall";
+ }
+}
+
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
arg_type_iterator ArgTys,
unsigned NumArgs, bool isVariadic,
unsigned TypeQuals, bool hasExceptionSpec,
bool anyExceptionSpec, unsigned NumExceptions,
- exception_iterator Exs, bool NoReturn) {
+ exception_iterator Exs, bool NoReturn,
+ CallingConv CallConv) {
ID.AddPointer(Result.getAsOpaquePtr());
for (unsigned i = 0; i != NumArgs; ++i)
ID.AddPointer(ArgTys[i].getAsOpaquePtr());
@@ -815,16 +833,19 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
ID.AddPointer(Exs[i].getAsOpaquePtr());
}
ID.AddInteger(NoReturn);
+ ID.AddInteger(CallConv);
}
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(),
getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(),
- getNumExceptions(), exception_begin(), getNoReturnAttr());
+ getNumExceptions(), exception_begin(), getNoReturnAttr(),
+ getCallConv());
}
void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID,
- QualType OIT, ObjCProtocolDecl **protocols,
+ QualType OIT,
+ ObjCProtocolDecl * const *protocols,
unsigned NumProtocols) {
ID.AddPointer(OIT.getAsOpaquePtr());
for (unsigned i = 0; i != NumProtocols; i++)
@@ -832,10 +853,7 @@ void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID,
}
void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID) {
- if (getNumProtocols())
- Profile(ID, getPointeeType(), &Protocols[0], getNumProtocols());
- else
- Profile(ID, getPointeeType(), 0, 0);
+ Profile(ID, getPointeeType(), qual_begin(), getNumProtocols());
}
/// LookThroughTypedefs - Return the ultimate type this typedef corresponds to
@@ -894,8 +912,9 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID,
E->Profile(ID, Context, true);
}
-TagType::TagType(TypeClass TC, TagDecl *D, QualType can)
- : Type(TC, can, D->isDependentType()), decl(D, 0) {}
+TagType::TagType(TypeClass TC, const TagDecl *D, QualType can)
+ : Type(TC, can, D->isDependentType()),
+ decl(const_cast<TagDecl*>(D), 0) {}
bool RecordType::classof(const TagType *TT) {
return isa<RecordDecl>(TT->getDecl());
@@ -1023,7 +1042,7 @@ QualType QualifierCollector::apply(const Type *T) const {
void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID,
const ObjCInterfaceDecl *Decl,
- ObjCProtocolDecl **protocols,
+ ObjCProtocolDecl * const *protocols,
unsigned NumProtocols) {
ID.AddPointer(Decl);
for (unsigned i = 0; i != NumProtocols; i++)
@@ -1031,8 +1050,81 @@ void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID,
}
void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID) {
- if (getNumProtocols())
- Profile(ID, getDecl(), &Protocols[0], getNumProtocols());
- else
- Profile(ID, getDecl(), 0, 0);
+ Profile(ID, getDecl(), qual_begin(), getNumProtocols());
+}
+
+Linkage Type::getLinkage() const {
+ // C++ [basic.link]p8:
+ // Names not covered by these rules have no linkage.
+ if (this != CanonicalType.getTypePtr())
+ return CanonicalType->getLinkage();
+
+ return NoLinkage;
+}
+
+Linkage BuiltinType::getLinkage() const {
+ // C++ [basic.link]p8:
+ // A type is said to have linkage if and only if:
+ // - it is a fundamental type (3.9.1); or
+ return ExternalLinkage;
+}
+
+Linkage TagType::getLinkage() const {
+ // C++ [basic.link]p8:
+ // - it is a class or enumeration type that is named (or has a name for
+ // linkage purposes (7.1.3)) and the name has linkage; or
+ // - it is a specialization of a class template (14); or
+ return getDecl()->getLinkage();
+}
+
+// C++ [basic.link]p8:
+// - it is a compound type (3.9.2) other than a class or enumeration,
+// compounded exclusively from types that have linkage; or
+Linkage ComplexType::getLinkage() const {
+ return ElementType->getLinkage();
+}
+
+Linkage PointerType::getLinkage() const {
+ return PointeeType->getLinkage();
+}
+
+Linkage BlockPointerType::getLinkage() const {
+ return PointeeType->getLinkage();
+}
+
+Linkage ReferenceType::getLinkage() const {
+ return PointeeType->getLinkage();
+}
+
+Linkage MemberPointerType::getLinkage() const {
+ return minLinkage(Class->getLinkage(), PointeeType->getLinkage());
+}
+
+Linkage ArrayType::getLinkage() const {
+ return ElementType->getLinkage();
+}
+
+Linkage VectorType::getLinkage() const {
+ return ElementType->getLinkage();
+}
+
+Linkage FunctionNoProtoType::getLinkage() const {
+ return getResultType()->getLinkage();
+}
+
+Linkage FunctionProtoType::getLinkage() const {
+ Linkage L = getResultType()->getLinkage();
+ for (arg_type_iterator A = arg_type_begin(), AEnd = arg_type_end();
+ A != AEnd; ++A)
+ L = minLinkage(L, (*A)->getLinkage());
+
+ return L;
+}
+
+Linkage ObjCInterfaceType::getLinkage() const {
+ return ExternalLinkage;
+}
+
+Linkage ObjCObjectPointerType::getLinkage() const {
+ return ExternalLinkage;
}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 00b74bc21a14..5b621cf7280d 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -225,15 +225,24 @@ void TypePrinter::PrintDependentSizedExtVector(
}
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.
- Print(T->getElementType(), S);
- std::string V = "__attribute__((__vector_size__(";
- V += llvm::utostr_32(T->getNumElements()); // convert back to bytes.
- std::string ET;
- Print(T->getElementType(), ET);
- V += " * sizeof(" + ET + ")))) ";
- S = V + S;
+ if (T->isAltiVec()) {
+ if (T->isPixel())
+ S = "__vector __pixel " + S;
+ else {
+ Print(T->getElementType(), S);
+ S = "__vector " + S;
+ }
+ } else {
+ // FIXME: We prefer to print the size directly here, but have no way
+ // to get the size of the type.
+ Print(T->getElementType(), S);
+ std::string V = "__attribute__((__vector_size__(";
+ V += llvm::utostr_32(T->getNumElements()); // convert back to bytes.
+ std::string ET;
+ Print(T->getElementType(), ET);
+ V += " * sizeof(" + ET + ")))) ";
+ S = V + S;
+ }
}
void TypePrinter::PrintExtVector(const ExtVectorType *T, std::string &S) {
@@ -271,6 +280,19 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
S += ")";
+ switch(T->getCallConv()) {
+ case CC_Default:
+ default: break;
+ case CC_C:
+ S += " __attribute__((cdecl))";
+ break;
+ case CC_X86StdCall:
+ S += " __attribute__((stdcall))";
+ break;
+ case CC_X86FastCall:
+ S += " __attribute__((fastcall))";
+ break;
+ }
if (T->getNoReturnAttr())
S += " __attribute__((noreturn))";
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index ad9f6dd19413..ccd5088f2ec7 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -12,10 +12,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
-#include "clang/Analysis/PathSensitive/MemRegion.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -87,12 +86,6 @@ AnalysisContext *AnalysisContextManager::getContext(const Decl *D) {
return AC;
}
-const BlockDecl *BlockInvocationContext::getBlockDecl() const {
- return Data.is<const BlockDataRegion*>() ?
- Data.get<const BlockDataRegion*>()->getDecl()
- : Data.get<const BlockDecl*>();
-}
-
//===----------------------------------------------------------------------===//
// FoldingSet profiling.
//===----------------------------------------------------------------------===//
@@ -117,11 +110,7 @@ void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) {
}
void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) {
- if (const BlockDataRegion *BR = getBlockRegion())
- Profile(ID, getAnalysisContext(), getParent(), BR);
- else
- Profile(ID, getAnalysisContext(), getParent(),
- Data.get<const BlockDecl*>());
+ Profile(ID, getAnalysisContext(), getParent(), BD);
}
//===----------------------------------------------------------------------===//
@@ -170,15 +159,6 @@ LocationContextManager::getScope(AnalysisContext *ctx,
return getLocationContext<ScopeContext, Stmt>(ctx, parent, s);
}
-const BlockInvocationContext *
-LocationContextManager::getBlockInvocation(AnalysisContext *ctx,
- const LocationContext *parent,
- const BlockDataRegion *BR) {
- return getLocationContext<BlockInvocationContext, BlockDataRegion>(ctx,
- parent,
- BR);
-}
-
//===----------------------------------------------------------------------===//
// LocationContext methods.
//===----------------------------------------------------------------------===//
@@ -214,6 +194,7 @@ namespace {
class FindBlockDeclRefExprsVals : public StmtVisitor<FindBlockDeclRefExprsVals>{
BumpVector<const VarDecl*> &BEVals;
BumpVectorContext &BC;
+ llvm::DenseMap<const VarDecl*, unsigned> Visited;
public:
FindBlockDeclRefExprsVals(BumpVector<const VarDecl*> &bevals,
BumpVectorContext &bc)
@@ -224,10 +205,27 @@ public:
if (Stmt *child = *I)
Visit(child);
}
+
+ void VisitDeclRefExpr(const DeclRefExpr *DR) {
+ // Non-local variables are also directly modified.
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
+ if (!VD->hasLocalStorage()) {
+ unsigned &flag = Visited[VD];
+ if (!flag) {
+ flag = 1;
+ BEVals.push_back(VD, BC);
+ }
+ }
+ }
void VisitBlockDeclRefExpr(BlockDeclRefExpr *DR) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
- BEVals.push_back(VD, BC);
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ unsigned &flag = Visited[VD];
+ if (!flag) {
+ flag = 1;
+ BEVals.push_back(VD, BC);
+ }
+ }
}
};
} // end anonymous namespace
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index 521f1be6ec8b..4f8259e44939 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -2,67 +2,10 @@ set(LLVM_NO_RTTI 1)
add_clang_library(clangAnalysis
AnalysisContext.cpp
- ArrayBoundChecker.cpp
- AttrNonNullChecker.cpp
- BasicConstraintManager.cpp
- BasicObjCFoundationChecks.cpp
- BasicStore.cpp
- BasicValueFactory.cpp
- BugReporter.cpp
- BugReporterVisitors.cpp
- BuiltinFunctionChecker.cpp
CFG.cpp
- CFRefCount.cpp
- CallAndMessageChecker.cpp
- CallInliner.cpp
- CastToStructChecker.cpp
- CheckDeadStores.cpp
- CheckObjCDealloc.cpp
- CheckObjCInstMethSignature.cpp
- CheckObjCUnusedIVars.cpp
- CheckSecuritySyntaxOnly.cpp
- CheckSizeofPointer.cpp
- Checker.cpp
- DereferenceChecker.cpp
- DivZeroChecker.cpp
- Environment.cpp
- ExplodedGraph.cpp
- FixedAddressChecker.cpp
- GRBlockCounter.cpp
- GRCoreEngine.cpp
- GRExprEngine.cpp
- GRExprEngineExperimentalChecks.cpp
- GRState.cpp
LiveVariables.cpp
- MallocChecker.cpp
- ManagerRegistry.cpp
- MemRegion.cpp
- NoReturnFunctionChecker.cpp
- NSAutoreleasePoolChecker.cpp
- NSErrorChecker.cpp
- OSAtomicChecker.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
- SimpleSValuator.cpp
- Store.cpp
- SymbolManager.cpp
- UndefBranchChecker.cpp
- UndefResultChecker.cpp
- UndefinedArraySubscriptChecker.cpp
- UndefinedAssignmentChecker.cpp
+ PrintfFormatString.cpp
UninitializedValues.cpp
- VLASizeChecker.cpp
- ValueManager.cpp
)
add_dependencies(clangAnalysis ClangDiagnosticAnalysis)
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index 0b2620e609c2..94ed75286dee 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -19,7 +19,7 @@
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
#include "clang/Analysis/Support/SaveAndRestore.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/lib/Analysis/Makefile b/lib/Analysis/Makefile
index c597254fd2d7..d6411122e322 100644
--- a/lib/Analysis/Makefile
+++ b/lib/Analysis/Makefile
@@ -14,7 +14,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangAnalysis
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
new file mode 100644
index 000000000000..55abd1077150
--- /dev/null
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -0,0 +1,436 @@
+//= PrintfFormatStrings.cpp - Analysis of printf format strings --*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Handling of format string in printf and friends. The structure of format
+// strings for fprintf() are described in C99 7.19.6.1.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/PrintfFormatString.h"
+#include "clang/AST/ASTContext.h"
+
+using clang::analyze_printf::FormatSpecifier;
+using clang::analyze_printf::OptionalAmount;
+using clang::analyze_printf::ArgTypeResult;
+using clang::analyze_printf::FormatStringHandler;
+using namespace clang;
+
+namespace {
+class FormatSpecifierResult {
+ FormatSpecifier FS;
+ const char *Start;
+ bool Stop;
+public:
+ FormatSpecifierResult(bool stop = false)
+ : Start(0), Stop(stop) {}
+ FormatSpecifierResult(const char *start,
+ const FormatSpecifier &fs)
+ : FS(fs), Start(start), Stop(false) {}
+
+
+ const char *getStart() const { return Start; }
+ bool shouldStop() const { return Stop; }
+ bool hasValue() const { return Start != 0; }
+ const FormatSpecifier &getValue() const {
+ assert(hasValue());
+ return FS;
+ }
+ const FormatSpecifier &getValue() { return FS; }
+};
+} // end anonymous namespace
+
+template <typename T>
+class UpdateOnReturn {
+ T &ValueToUpdate;
+ const T &ValueToCopy;
+public:
+ UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
+ : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
+
+ ~UpdateOnReturn() {
+ ValueToUpdate = ValueToCopy;
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// Methods for parsing format strings.
+//===----------------------------------------------------------------------===//
+
+static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
+ const char *I = Beg;
+ UpdateOnReturn <const char*> UpdateBeg(Beg, I);
+
+ bool foundDigits = false;
+ unsigned accumulator = 0;
+
+ for ( ; I != E; ++I) {
+ char c = *I;
+ if (c >= '0' && c <= '9') {
+ foundDigits = true;
+ accumulator += (accumulator * 10) + (c - '0');
+ continue;
+ }
+
+ if (foundDigits)
+ return OptionalAmount(accumulator, Beg);
+
+ if (c == '*') {
+ ++I;
+ return OptionalAmount(OptionalAmount::Arg, Beg);
+ }
+
+ break;
+ }
+
+ return OptionalAmount();
+}
+
+static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
+ const char *&Beg,
+ const char *E) {
+
+ using namespace clang::analyze_printf;
+
+ const char *I = Beg;
+ const char *Start = 0;
+ UpdateOnReturn <const char*> UpdateBeg(Beg, I);
+
+ // Look for a '%' character that indicates the start of a format specifier.
+ for ( ; I != E ; ++I) {
+ char c = *I;
+ if (c == '\0') {
+ // Detect spurious null characters, which are likely errors.
+ H.HandleNullChar(I);
+ return true;
+ }
+ if (c == '%') {
+ Start = I++; // Record the start of the format specifier.
+ break;
+ }
+ }
+
+ // No format specifier found?
+ if (!Start)
+ return false;
+
+ if (I == E) {
+ // No more characters left?
+ H.HandleIncompleteFormatSpecifier(Start, E - Start);
+ return true;
+ }
+
+ FormatSpecifier FS;
+
+ // Look for flags (if any).
+ bool hasMore = true;
+ for ( ; I != E; ++I) {
+ switch (*I) {
+ default: hasMore = false; break;
+ case '-': FS.setIsLeftJustified(); break;
+ case '+': FS.setHasPlusPrefix(); break;
+ case ' ': FS.setHasSpacePrefix(); break;
+ case '#': FS.setHasAlternativeForm(); break;
+ case '0': FS.setHasLeadingZeros(); break;
+ }
+ if (!hasMore)
+ break;
+ }
+
+ if (I == E) {
+ // No more characters left?
+ H.HandleIncompleteFormatSpecifier(Start, E - Start);
+ return true;
+ }
+
+ // Look for the field width (if any).
+ FS.setFieldWidth(ParseAmount(I, E));
+
+ if (I == E) {
+ // No more characters left?
+ H.HandleIncompleteFormatSpecifier(Start, E - Start);
+ return true;
+ }
+
+ // Look for the precision (if any).
+ if (*I == '.') {
+ ++I;
+ if (I == E) {
+ H.HandleIncompleteFormatSpecifier(Start, E - Start);
+ return true;
+ }
+
+ FS.setPrecision(ParseAmount(I, E));
+
+ if (I == E) {
+ // No more characters left?
+ H.HandleIncompleteFormatSpecifier(Start, E - Start);
+ return true;
+ }
+ }
+
+ // Look for the length modifier.
+ LengthModifier lm = None;
+ switch (*I) {
+ default:
+ break;
+ case 'h':
+ ++I;
+ lm = (I != E && *I == 'h') ? ++I, AsChar : AsShort;
+ break;
+ case 'l':
+ ++I;
+ lm = (I != E && *I == 'l') ? ++I, AsLongLong : AsLong;
+ break;
+ case 'j': lm = AsIntMax; ++I; break;
+ case 'z': lm = AsSizeT; ++I; break;
+ case 't': lm = AsPtrDiff; ++I; break;
+ case 'L': lm = AsLongDouble; ++I; break;
+ case 'q': lm = AsLongLong; ++I; break;
+ }
+ FS.setLengthModifier(lm);
+
+ if (I == E) {
+ // No more characters left?
+ H.HandleIncompleteFormatSpecifier(Start, E - Start);
+ return true;
+ }
+
+ if (*I == '\0') {
+ // Detect spurious null characters, which are likely errors.
+ H.HandleNullChar(I);
+ return true;
+ }
+
+ // Finally, look for the conversion specifier.
+ const char *conversionPosition = I++;
+ ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
+ switch (*conversionPosition) {
+ default:
+ break;
+ // C99: 7.19.6.1 (section 8).
+ case 'd': k = ConversionSpecifier::dArg; break;
+ case 'i': k = ConversionSpecifier::iArg; break;
+ case 'o': k = ConversionSpecifier::oArg; break;
+ case 'u': k = ConversionSpecifier::uArg; break;
+ case 'x': k = ConversionSpecifier::xArg; break;
+ case 'X': k = ConversionSpecifier::XArg; break;
+ case 'f': k = ConversionSpecifier::fArg; break;
+ case 'F': k = ConversionSpecifier::FArg; break;
+ case 'e': k = ConversionSpecifier::eArg; break;
+ case 'E': k = ConversionSpecifier::EArg; break;
+ case 'g': k = ConversionSpecifier::gArg; break;
+ case 'G': k = ConversionSpecifier::GArg; break;
+ case 'a': k = ConversionSpecifier::aArg; break;
+ case 'A': k = ConversionSpecifier::AArg; break;
+ case 'c': k = ConversionSpecifier::IntAsCharArg; break;
+ case 's': k = ConversionSpecifier::CStrArg; break;
+ case 'p': k = ConversionSpecifier::VoidPtrArg; break;
+ case 'n': k = ConversionSpecifier::OutIntPtrArg; break;
+ case '%': k = ConversionSpecifier::PercentArg; break;
+ // Objective-C.
+ case '@': k = ConversionSpecifier::ObjCObjArg; break;
+ // Glibc specific.
+ case 'm': k = ConversionSpecifier::PrintErrno; break;
+ }
+ FS.setConversionSpecifier(ConversionSpecifier(conversionPosition, k));
+
+ if (k == ConversionSpecifier::InvalidSpecifier) {
+ H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg);
+ return false; // Keep processing format specifiers.
+ }
+ return FormatSpecifierResult(Start, FS);
+}
+
+bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H,
+ const char *I, const char *E) {
+ // Keep looking for a format specifier until we have exhausted the string.
+ while (I != E) {
+ const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E);
+ // Did a fail-stop error of any kind occur when parsing the specifier?
+ // If so, don't do any more processing.
+ if (FSR.shouldStop())
+ return true;;
+ // Did we exhaust the string or encounter an error that
+ // we can recover from?
+ if (!FSR.hasValue())
+ continue;
+ // We have a format specifier. Pass it to the callback.
+ if (!H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(),
+ I - FSR.getStart()))
+ return true;
+ }
+ assert(I == E && "Format string not exhausted");
+ return false;
+}
+
+FormatStringHandler::~FormatStringHandler() {}
+
+//===----------------------------------------------------------------------===//
+// Methods on ArgTypeResult.
+//===----------------------------------------------------------------------===//
+
+bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
+ assert(isValid());
+
+ if (K == UnknownTy)
+ return true;
+
+ if (K == SpecificTy) {
+ argTy = C.getCanonicalType(argTy).getUnqualifiedType();
+
+ if (T == argTy)
+ return true;
+
+ if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
+ switch (BT->getKind()) {
+ default:
+ break;
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ return T == C.UnsignedCharTy;
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ return T == C.SignedCharTy;
+ case BuiltinType::Short:
+ return T == C.UnsignedShortTy;
+ case BuiltinType::UShort:
+ return T == C.ShortTy;
+ case BuiltinType::Int:
+ return T == C.UnsignedIntTy;
+ case BuiltinType::UInt:
+ return T == C.IntTy;
+ case BuiltinType::Long:
+ return T == C.UnsignedLongTy;
+ case BuiltinType::ULong:
+ return T == C.LongTy;
+ case BuiltinType::LongLong:
+ return T == C.UnsignedLongLongTy;
+ case BuiltinType::ULongLong:
+ return T == C.LongLongTy;
+ }
+
+ return false;
+ }
+
+ if (K == CStrTy) {
+ const PointerType *PT = argTy->getAs<PointerType>();
+ if (!PT)
+ return false;
+
+ QualType pointeeTy = PT->getPointeeType();
+
+ if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
+ switch (BT->getKind()) {
+ case BuiltinType::Void:
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+ }
+
+ if (K == WCStrTy) {
+ const PointerType *PT = argTy->getAs<PointerType>();
+ if (!PT)
+ return false;
+
+ QualType pointeeTy = PT->getPointeeType();
+ return pointeeTy == C.WCharTy;
+ }
+
+ return false;
+}
+
+QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
+ assert(isValid());
+ if (K == SpecificTy)
+ return T;
+ if (K == CStrTy)
+ return C.getPointerType(C.CharTy);
+ if (K == WCStrTy)
+ return C.getPointerType(C.WCharTy);
+ if (K == ObjCPointerTy)
+ return C.ObjCBuiltinIdTy;
+
+ return QualType();
+}
+
+//===----------------------------------------------------------------------===//
+// Methods on OptionalAmount.
+//===----------------------------------------------------------------------===//
+
+ArgTypeResult OptionalAmount::getArgType(ASTContext &Ctx) const {
+ return Ctx.IntTy;
+}
+
+//===----------------------------------------------------------------------===//
+// Methods on FormatSpecifier.
+//===----------------------------------------------------------------------===//
+
+ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const {
+ if (!CS.consumesDataArgument())
+ return ArgTypeResult::Invalid();
+
+ if (CS.isIntArg())
+ switch (LM) {
+ case AsLongDouble:
+ return ArgTypeResult::Invalid();
+ case None: return Ctx.IntTy;
+ case AsChar: return Ctx.SignedCharTy;
+ case AsShort: return Ctx.ShortTy;
+ case AsLong: return Ctx.LongTy;
+ case AsLongLong: return Ctx.LongLongTy;
+ case AsIntMax:
+ // FIXME: Return unknown for now.
+ return ArgTypeResult();
+ case AsSizeT: return Ctx.getSizeType();
+ case AsPtrDiff: return Ctx.getPointerDiffType();
+ }
+
+ if (CS.isUIntArg())
+ switch (LM) {
+ case AsLongDouble:
+ return ArgTypeResult::Invalid();
+ case None: return Ctx.UnsignedIntTy;
+ case AsChar: return Ctx.UnsignedCharTy;
+ case AsShort: return Ctx.UnsignedShortTy;
+ case AsLong: return Ctx.UnsignedLongTy;
+ case AsLongLong: return Ctx.UnsignedLongLongTy;
+ case AsIntMax:
+ // FIXME: Return unknown for now.
+ return ArgTypeResult();
+ case AsSizeT:
+ // FIXME: How to get the corresponding unsigned
+ // version of size_t?
+ return ArgTypeResult();
+ case AsPtrDiff:
+ // FIXME: How to get the corresponding unsigned
+ // version of ptrdiff_t?
+ return ArgTypeResult();
+ }
+
+ if (CS.isDoubleArg()) {
+ if (LM == AsLongDouble)
+ return Ctx.LongDoubleTy;
+ return Ctx.DoubleTy;
+ }
+
+ if (CS.getKind() == ConversionSpecifier::CStrArg)
+ return ArgTypeResult(LM == AsWideChar ? ArgTypeResult::WCStrTy
+ : ArgTypeResult::CStrTy);
+
+ // FIXME: Handle other cases.
+ return ArgTypeResult();
+}
+
diff --git a/lib/Analysis/ReturnStackAddressChecker.cpp b/lib/Analysis/ReturnStackAddressChecker.cpp
deleted file mode 100644
index 4d7e8ade98f7..000000000000
--- a/lib/Analysis/ReturnStackAddressChecker.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-//== 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 "clang/Basic/SourceManager.h"
-#include "llvm/ADT/SmallString.h"
-
-using namespace clang;
-
-namespace {
-class 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.GenerateSink();
-
- 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;
-
- // Get the base region, stripping away fields and elements.
- R = R->getBaseRegion();
-
- // 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 if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
- const BlockDecl *BD = BR->getCodeRegion()->getDecl();
- SourceLocation L = BD->getLocStart();
- range = BD->getSourceRange();
- os << "Address of stack-allocated block declared on line "
- << C.getSourceManager().getInstantiationLineNumber(L)
- << " returned to caller";
- }
- else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- os << "Address of stack memory associated with local variable '"
- << VR->getString() << "' returned";
- range = VR->getDecl()->getSourceRange();
- }
- else {
- assert(false && "Invalid region in ReturnStackAddressChecker.");
- return;
- }
-
- RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
- report->addRange(RetE->getSourceRange());
- if (range.isValid())
- report->addRange(range);
-
- C.EmitReport(report);
-}
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index 6fa4b539dc40..bdc0e7c621f7 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -13,7 +13,6 @@
#include "clang/Analysis/Analyses/UninitializedValues.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
-#include "clang/Analysis/LocalCheckers.h"
#include "clang/Analysis/AnalysisDiagnostic.h"
#include "clang/AST/ASTContext.h"
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index abbf6f9b6e41..094f7760a8ec 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -21,8 +21,10 @@
#include "clang/Analysis/AnalysisDiagnostic.h"
#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
@@ -385,6 +387,123 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const {
return Result;
}
+static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
+ unsigned &Value) {
+ if (Memory + sizeof(unsigned) > MemoryEnd)
+ return true;
+
+ memmove(&Value, Memory, sizeof(unsigned));
+ Memory += sizeof(unsigned);
+ return false;
+}
+
+static bool ReadSourceLocation(FileManager &FM, SourceManager &SM,
+ const char *&Memory, const char *MemoryEnd,
+ SourceLocation &Location) {
+ // Read the filename.
+ unsigned FileNameLen = 0;
+ if (ReadUnsigned(Memory, MemoryEnd, FileNameLen) ||
+ Memory + FileNameLen > MemoryEnd)
+ return true;
+
+ llvm::StringRef FileName(Memory, FileNameLen);
+ Memory += FileNameLen;
+
+ // Read the line, column.
+ unsigned Line = 0, Column = 0;
+ if (ReadUnsigned(Memory, MemoryEnd, Line) ||
+ ReadUnsigned(Memory, MemoryEnd, Column))
+ return true;
+
+ if (FileName.empty()) {
+ Location = SourceLocation();
+ return false;
+ }
+
+ const FileEntry *File = FM.getFile(FileName);
+ if (!File)
+ return true;
+
+ // Make sure that this file has an entry in the source manager.
+ if (!SM.hasFileInfo(File))
+ SM.createFileID(File, SourceLocation(), SrcMgr::C_User);
+
+ Location = SM.getLocation(File, Line, Column);
+ return false;
+}
+
+DiagnosticBuilder Diagnostic::Deserialize(FileManager &FM, SourceManager &SM,
+ const char *&Memory,
+ const char *MemoryEnd) {
+ if (Memory == MemoryEnd)
+ return DiagnosticBuilder(0);
+
+ // Read the severity level.
+ unsigned Level = 0;
+ if (ReadUnsigned(Memory, MemoryEnd, Level) || Level > Fatal)
+ return DiagnosticBuilder(0);
+
+ // Read the source location.
+ SourceLocation Location;
+ if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Location))
+ return DiagnosticBuilder(0);
+
+ // Read the diagnostic text.
+ if (Memory == MemoryEnd)
+ return DiagnosticBuilder(0);
+
+ unsigned MessageLen = 0;
+ if (ReadUnsigned(Memory, MemoryEnd, MessageLen) ||
+ Memory + MessageLen > MemoryEnd)
+ return DiagnosticBuilder(0);
+
+ llvm::StringRef Message(Memory, MessageLen);
+ Memory += MessageLen;
+
+ // At this point, we have enough information to form a diagnostic. Do so.
+ unsigned DiagID = getCustomDiagID((enum Level)Level, Message);
+ DiagnosticBuilder DB = Report(FullSourceLoc(Location, SM), DiagID);
+ if (Memory == MemoryEnd)
+ return DB;
+
+ // Read the source ranges.
+ unsigned NumSourceRanges = 0;
+ if (ReadUnsigned(Memory, MemoryEnd, NumSourceRanges))
+ return DB;
+ for (unsigned I = 0; I != NumSourceRanges; ++I) {
+ SourceLocation Begin, End;
+ if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Begin) ||
+ ReadSourceLocation(FM, SM, Memory, MemoryEnd, End))
+ return DB;
+
+ DB << SourceRange(Begin, End);
+ }
+
+ // Read the fix-it hints.
+ unsigned NumFixIts = 0;
+ if (ReadUnsigned(Memory, MemoryEnd, NumFixIts))
+ return DB;
+ for (unsigned I = 0; I != NumFixIts; ++I) {
+ SourceLocation RemoveBegin, RemoveEnd, InsertionLoc;
+ unsigned InsertLen = 0;
+ if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveBegin) ||
+ ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveEnd) ||
+ ReadSourceLocation(FM, SM, Memory, MemoryEnd, InsertionLoc) ||
+ ReadUnsigned(Memory, MemoryEnd, InsertLen) ||
+ Memory + InsertLen > MemoryEnd)
+ return DB;
+
+ CodeModificationHint Hint;
+ Hint.RemoveRange = SourceRange(RemoveBegin, RemoveEnd);
+ Hint.InsertionLoc = InsertionLoc;
+ Hint.CodeToInsert.assign(Memory, Memory + InsertLen);
+ Memory += InsertLen;
+ DB << Hint;
+ }
+
+ return DB;
+}
+
struct WarningOption {
const char *Name;
const short *Members;
@@ -510,7 +629,7 @@ bool Diagnostic::ProcessDiag() {
// it.
if (SuppressSystemWarnings && !ShouldEmitInSystemHeader &&
Info.getLocation().isValid() &&
- Info.getLocation().getSpellingLoc().isInSystemHeader() &&
+ Info.getLocation().getInstantiationLoc().isInSystemHeader() &&
(DiagLevel != Diagnostic::Note || LastDiagLevel == Diagnostic::Ignored)) {
LastDiagLevel = Diagnostic::Ignored;
return false;
@@ -917,6 +1036,104 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
}
}
+static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) {
+ OS.write((const char *)&Value, sizeof(unsigned));
+}
+
+static void WriteString(llvm::raw_ostream &OS, llvm::StringRef String) {
+ WriteUnsigned(OS, String.size());
+ OS.write(String.data(), String.size());
+}
+
+static void WriteSourceLocation(llvm::raw_ostream &OS,
+ SourceManager *SM,
+ SourceLocation Location) {
+ if (!SM || Location.isInvalid()) {
+ // If we don't have a source manager or this location is invalid,
+ // just write an invalid location.
+ WriteUnsigned(OS, 0);
+ WriteUnsigned(OS, 0);
+ WriteUnsigned(OS, 0);
+ return;
+ }
+
+ Location = SM->getInstantiationLoc(Location);
+ std::pair<FileID, unsigned> Decomposed = SM->getDecomposedLoc(Location);
+
+ WriteString(OS, SM->getFileEntryForID(Decomposed.first)->getName());
+ WriteUnsigned(OS, SM->getLineNumber(Decomposed.first, Decomposed.second));
+ WriteUnsigned(OS, SM->getColumnNumber(Decomposed.first, Decomposed.second));
+}
+
+void DiagnosticInfo::Serialize(Diagnostic::Level DiagLevel,
+ llvm::raw_ostream &OS) const {
+ SourceManager *SM = 0;
+ if (getLocation().isValid())
+ SM = &const_cast<SourceManager &>(getLocation().getManager());
+
+ // Write the diagnostic level and location.
+ WriteUnsigned(OS, (unsigned)DiagLevel);
+ WriteSourceLocation(OS, SM, getLocation());
+
+ // Write the diagnostic message.
+ llvm::SmallString<64> Message;
+ FormatDiagnostic(Message);
+ WriteString(OS, Message);
+
+ // Count the number of ranges that don't point into macros, since
+ // only simple file ranges serialize well.
+ unsigned NumNonMacroRanges = 0;
+ for (unsigned I = 0, N = getNumRanges(); I != N; ++I) {
+ SourceRange R = getRange(I);
+ if (R.getBegin().isMacroID() || R.getEnd().isMacroID())
+ continue;
+
+ ++NumNonMacroRanges;
+ }
+
+ // Write the ranges.
+ WriteUnsigned(OS, NumNonMacroRanges);
+ if (NumNonMacroRanges) {
+ for (unsigned I = 0, N = getNumRanges(); I != N; ++I) {
+ SourceRange R = getRange(I);
+ if (R.getBegin().isMacroID() || R.getEnd().isMacroID())
+ continue;
+
+ WriteSourceLocation(OS, SM, R.getBegin());
+ WriteSourceLocation(OS, SM, R.getEnd());
+ }
+ }
+
+ // Determine if all of the fix-its involve rewrites with simple file
+ // locations (not in macro instantiations). If so, we can write
+ // fix-it information.
+ unsigned NumFixIts = getNumCodeModificationHints();
+ for (unsigned I = 0; I != NumFixIts; ++I) {
+ const CodeModificationHint &Hint = getCodeModificationHint(I);
+ if (Hint.RemoveRange.isValid() &&
+ (Hint.RemoveRange.getBegin().isMacroID() ||
+ Hint.RemoveRange.getEnd().isMacroID())) {
+ NumFixIts = 0;
+ break;
+ }
+
+ if (Hint.InsertionLoc.isValid() && Hint.InsertionLoc.isMacroID()) {
+ NumFixIts = 0;
+ break;
+ }
+ }
+
+ // Write the fix-its.
+ WriteUnsigned(OS, NumFixIts);
+ for (unsigned I = 0; I != NumFixIts; ++I) {
+ const CodeModificationHint &Hint = getCodeModificationHint(I);
+ WriteSourceLocation(OS, SM, Hint.RemoveRange.getBegin());
+ WriteSourceLocation(OS, SM, Hint.RemoveRange.getEnd());
+ WriteSourceLocation(OS, SM, Hint.InsertionLoc);
+ WriteString(OS, Hint.CodeToInsert);
+ }
+}
+
/// IncludeInDiagnosticCounts - This method (whose default implementation
/// returns true) indicates whether the diagnostics handled by this
/// DiagnosticClient should be included in the number of diagnostics
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 401e6cba0692..16a61b7156fa 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -68,7 +68,8 @@ namespace {
KEYCXX0X = 8,
KEYGNU = 16,
KEYMS = 32,
- BOOLSUPPORT = 64
+ BOOLSUPPORT = 64,
+ KEYALTIVEC = 128
};
}
@@ -91,6 +92,7 @@ static void AddKeyword(const char *Keyword, unsigned KWLen,
else if (LangOpts.GNUMode && (Flags & KEYGNU)) AddResult = 1;
else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1;
else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2;
+ else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2;
// Don't add this keyword if disabled in this language.
if (AddResult == 0) return;
diff --git a/lib/Basic/Makefile b/lib/Basic/Makefile
index f7335789384f..58ac7eb86e75 100644
--- a/lib/Basic/Makefile
+++ b/lib/Basic/Makefile
@@ -14,7 +14,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangBasic
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
ifdef CLANG_VENDOR
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 354bf7befbb3..b91671ad17b1 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -560,10 +560,14 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
SourceLocation SourceManager::
getInstantiationLocSlowCase(SourceLocation Loc) const {
do {
- std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc);
- Loc = getSLocEntry(LocInfo.first).getInstantiation()
+ // Note: If Loc indicates an offset into a token that came from a macro
+ // expansion (e.g. the 5th character of the token) we do not want to add
+ // this offset when going to the instantiation location. The instatiation
+ // location is the macro invocation, which the offset has nothing to do
+ // with. This is unlike when we get the spelling loc, because the offset
+ // directly correspond to the token whose spelling we're inspecting.
+ Loc = getSLocEntry(getFileID(Loc)).getInstantiation()
.getInstantiationLocStart();
- Loc = Loc.getFileLocWithOffset(LocInfo.second);
} while (!Loc.isFileID());
return Loc;
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index 493beeea6dc5..136089fe90c2 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -150,39 +150,41 @@ void TargetInfo::setForcedLangOptions(LangOptions &Opts) {
//===----------------------------------------------------------------------===//
-static void removeGCCRegisterPrefix(const char *&Name) {
+static llvm::StringRef removeGCCRegisterPrefix(llvm::StringRef Name) {
if (Name[0] == '%' || Name[0] == '#')
- Name++;
+ Name = Name.substr(1);
+
+ return Name;
}
/// isValidGCCRegisterName - Returns whether the passed in string
/// is a valid register name according to GCC. This is used by Sema for
/// inline asm statements.
-bool TargetInfo::isValidGCCRegisterName(const char *Name) const {
+bool TargetInfo::isValidGCCRegisterName(llvm::StringRef Name) const {
+ if (Name.empty())
+ return false;
+
const char * const *Names;
unsigned NumNames;
// Get rid of any register prefix.
- removeGCCRegisterPrefix(Name);
+ Name = removeGCCRegisterPrefix(Name);
-
- if (strcmp(Name, "memory") == 0 ||
- strcmp(Name, "cc") == 0)
+ if (Name == "memory" || Name == "cc")
return true;
getGCCRegNames(Names, NumNames);
// If we have a number it maps to an entry in the register name array.
if (isdigit(Name[0])) {
- char *End;
- int n = (int)strtol(Name, &End, 0);
- if (*End == 0)
+ int n;
+ if (!Name.getAsInteger(0, n))
return n >= 0 && (unsigned)n < NumNames;
}
// Check register names.
for (unsigned i = 0; i < NumNames; i++) {
- if (strcmp(Name, Names[i]) == 0)
+ if (Name == Names[i])
return true;
}
@@ -195,7 +197,7 @@ bool TargetInfo::isValidGCCRegisterName(const char *Name) const {
for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) {
if (!Aliases[i].Aliases[j])
break;
- if (strcmp(Aliases[i].Aliases[j], Name) == 0)
+ if (Aliases[i].Aliases[j] == Name)
return true;
}
}
@@ -203,10 +205,12 @@ bool TargetInfo::isValidGCCRegisterName(const char *Name) const {
return false;
}
-const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const {
+llvm::StringRef
+TargetInfo::getNormalizedGCCRegisterName(llvm::StringRef Name) const {
assert(isValidGCCRegisterName(Name) && "Invalid register passed in");
- removeGCCRegisterPrefix(Name);
+ // Get rid of any register prefix.
+ Name = removeGCCRegisterPrefix(Name);
const char * const *Names;
unsigned NumNames;
@@ -215,9 +219,8 @@ const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const {
// First, check if we have a number.
if (isdigit(Name[0])) {
- char *End;
- int n = (int)strtol(Name, &End, 0);
- if (*End == 0) {
+ int n;
+ if (!Name.getAsInteger(0, n)) {
assert(n >= 0 && (unsigned)n < NumNames &&
"Out of bounds register number!");
return Names[n];
@@ -233,7 +236,7 @@ const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const {
for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) {
if (!Aliases[i].Aliases[j])
break;
- if (strcmp(Aliases[i].Aliases[j], Name) == 0)
+ if (Aliases[i].Aliases[j] == Name)
return Aliases[i].Register;
}
}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index ea076ae0bbfc..c1cd96e361ed 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -74,7 +74,8 @@ public:
} // end anonymous namespace
-static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts) {
+static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
+ const llvm::Triple &Triple) {
Builder.defineMacro("__APPLE_CC__", "5621");
Builder.defineMacro("__APPLE__");
Builder.defineMacro("__MACH__");
@@ -96,51 +97,45 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts) {
if (Opts.POSIXThreads)
Builder.defineMacro("_REENTRANT");
-}
-
-static void getDarwinOSXDefines(MacroBuilder &Builder,
- const llvm::Triple &Triple) {
- if (Triple.getOS() != llvm::Triple::Darwin)
- return;
-
- // Figure out which "darwin number" the target triple is. "darwin9" -> 10.5.
- unsigned Maj, Min, Rev;
- Triple.getDarwinNumber(Maj, Min, Rev);
-
- char MacOSXStr[] = "1000";
- if (Maj >= 4 && Maj <= 13) { // 10.0-10.9
- // darwin7 -> 1030, darwin8 -> 1040, darwin9 -> 1050, etc.
- MacOSXStr[2] = '0' + Maj-4;
- }
-
- // Handle minor version: 10.4.9 -> darwin8.9 -> "1049"
- // Cap 10.4.11 -> darwin8.11 -> "1049"
- MacOSXStr[3] = std::min(Min, 9U)+'0';
- Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__",
- MacOSXStr);
-}
-
-static void getDarwinIPhoneOSDefines(MacroBuilder &Builder,
- const llvm::Triple &Triple) {
- if (Triple.getOS() != llvm::Triple::Darwin)
- return;
- // Figure out which "darwin number" the target triple is. "darwin9" -> 10.5.
+ // Get the OS version number from the triple.
unsigned Maj, Min, Rev;
- Triple.getDarwinNumber(Maj, Min, Rev);
- // When targetting iPhone OS, interpret the minor version and
- // revision as the iPhone OS version
- char iPhoneOSStr[] = "10000";
- if (Min >= 2 && Min <= 9) { // iPhone OS 2.0-9.0
- // darwin9.2.0 -> 20000, darwin9.3.0 -> 30000, etc.
- iPhoneOSStr[0] = '0' + Min;
+ // If no version was given, default to to 10.4.0, for simplifying tests.
+ if (Triple.getOSName() == "darwin") {
+ Min = Rev = 0;
+ Maj = 8;
+ } else
+ Triple.getDarwinNumber(Maj, Min, Rev);
+
+ // Set the appropriate OS version define.
+ if (Triple.getEnvironmentName() == "iphoneos") {
+ assert(Maj < 10 && Min < 99 && Rev < 99 && "Invalid version!");
+ char Str[6];
+ Str[0] = '0' + Maj;
+ Str[1] = '0' + (Min / 10);
+ Str[2] = '0' + (Min % 10);
+ Str[3] = '0' + (Rev / 10);
+ Str[4] = '0' + (Rev % 10);
+ Str[5] = '\0';
+ Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", Str);
+ } else {
+ // For historical reasons that make little sense, the version passed here is
+ // the "darwin" version, which drops the 10 and offsets by 4.
+ Rev = Min;
+ Min = Maj - 4;
+ Maj = 10;
+
+ assert(Triple.getEnvironmentName().empty() && "Invalid environment!");
+ assert(Maj < 99 && Min < 10 && Rev < 10 && "Invalid version!");
+ char Str[5];
+ Str[0] = '0' + (Maj / 10);
+ Str[1] = '0' + (Maj % 10);
+ Str[2] = '0' + Min;
+ Str[3] = '0' + Rev;
+ Str[4] = '\0';
+ Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str);
}
-
- // Handle minor version: 2.2 -> darwin9.2.2 -> 20200
- iPhoneOSStr[2] = std::min(Rev, 9U)+'0';
- Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__",
- iPhoneOSStr);
}
namespace {
@@ -149,8 +144,7 @@ class DarwinTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
MacroBuilder &Builder) const {
- getDarwinDefines(Builder, Opts);
- getDarwinOSXDefines(Builder, Triple);
+ getDarwinDefines(Builder, Opts, Triple);
}
public:
@@ -159,11 +153,7 @@ public:
this->TLSSupported = false;
}
- virtual const char *getUnicodeStringSection() const {
- return "__TEXT,__ustring";
- }
-
- virtual std::string isValidSectionSpecifier(const llvm::StringRef &SR) const {
+ virtual std::string isValidSectionSpecifier(llvm::StringRef SR) const {
// Let MCSectionMachO validate this.
llvm::StringRef Segment, Section;
unsigned TAA, StubSize;
@@ -201,16 +191,10 @@ protected:
// FreeBSD defines; list based off of gcc output
// FIXME: Move version number handling to llvm::Triple.
- const char *FreeBSD = strstr(Triple.getTriple().c_str(),
- "-freebsd");
- FreeBSD += strlen("-freebsd");
- char release[] = "X";
- release[0] = FreeBSD[0];
- char version[] = "X00001";
- version[0] = FreeBSD[0];
-
- Builder.defineMacro("__FreeBSD__", release);
- Builder.defineMacro("__FreeBSD_cc_version", version);
+ llvm::StringRef Release = Triple.getOSName().substr(strlen("freebsd"), 1);
+
+ Builder.defineMacro("__FreeBSD__", Release);
+ Builder.defineMacro("__FreeBSD_cc_version", Release + "00001");
Builder.defineMacro("__KPRINTF_ATTRIBUTE__");
DefineStd(Builder, "unix", Opts);
Builder.defineMacro("__ELF__");
@@ -643,9 +627,13 @@ class X86TargetInfo : public TargetInfo {
enum X86SSEEnum {
NoMMXSSE, MMX, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42
} SSELevel;
+ enum AMD3DNowEnum {
+ NoAMD3DNow, AMD3DNow, AMD3DNowAthlon
+ } AMD3DNowLevel;
+
public:
X86TargetInfo(const std::string& triple)
- : TargetInfo(triple), SSELevel(NoMMXSSE) {
+ : TargetInfo(triple), SSELevel(NoMMXSSE), AMD3DNowLevel(NoAMD3DNow) {
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended;
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
@@ -810,6 +798,14 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
.Case("mmx", MMX)
.Default(NoMMXSSE);
SSELevel = std::max(SSELevel, Level);
+
+ AMD3DNowEnum ThreeDNowLevel =
+ llvm::StringSwitch<AMD3DNowEnum>(Features[i].substr(1))
+ .Case("3dnowa", AMD3DNowAthlon)
+ .Case("3dnow", AMD3DNow)
+ .Default(NoAMD3DNow);
+
+ AMD3DNowLevel = std::max(AMD3DNowLevel, ThreeDNowLevel);
}
}
@@ -864,6 +860,16 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case NoMMXSSE:
break;
}
+
+ // Each case falls through to the previous one here.
+ switch (AMD3DNowLevel) {
+ case AMD3DNowAthlon:
+ Builder.defineMacro("__3dNOW_A__");
+ case AMD3DNow:
+ Builder.defineMacro("__3dNOW__");
+ case NoAMD3DNow:
+ break;
+ }
}
@@ -1224,7 +1230,7 @@ public:
// FIXME: We need support for -meabi... we could just mangle it into the
// name.
if (Name == "apcs-gnu") {
- DoubleAlign = LongLongAlign = 32;
+ DoubleAlign = LongLongAlign = LongDoubleAlign = 32;
SizeType = UnsignedLong;
if (IsThumb) {
@@ -1379,9 +1385,6 @@ public:
// when Neon instructions are actually available.
if (FPU == NeonFPU && !SoftFloat && IsThumb2)
Builder.defineMacro("__ARM_NEON__");
-
- if (getTriple().getOS() == llvm::Triple::Darwin)
- Builder.defineMacro("__USING_SJLJ_EXCEPTIONS__");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
@@ -1461,8 +1464,7 @@ class DarwinARMTargetInfo :
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
MacroBuilder &Builder) const {
- getDarwinDefines(Builder, Opts);
- getDarwinIPhoneOSDefines(Builder, Triple);
+ getDarwinDefines(Builder, Opts, Triple);
}
public:
@@ -1617,23 +1619,25 @@ namespace {
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
Builder.defineMacro("__pic16");
+ Builder.defineMacro("__PIC16");
Builder.defineMacro("rom", "__attribute__((address_space(1)))");
Builder.defineMacro("ram", "__attribute__((address_space(0)))");
- Builder.defineMacro("_section(SectName)",
+ Builder.defineMacro("__section(SectName)",
"__attribute__((section(SectName)))");
Builder.defineMacro("near",
"__attribute__((section(\"Address=NEAR\")))");
- Builder.defineMacro("_address(Addr)",
+ Builder.defineMacro("__address(Addr)",
"__attribute__((section(\"Address=\"#Addr)))");
- Builder.defineMacro("_CONFIG(conf)", "asm(\"CONFIG \"#conf)");
- Builder.defineMacro("_interrupt",
+ Builder.defineMacro("__config(conf)", "asm(\"CONFIG \"#conf)");
+ Builder.defineMacro("__idlocs(value)", "asm(\"__IDLOCS \"#value)");
+ Builder.defineMacro("interrupt",
"__attribute__((section(\"interrupt=0x4\"))) \
__attribute__((used))");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {}
virtual const char *getVAListDeclaration() const {
- return "";
+ return "typedef char* __builtin_va_list;";
}
virtual const char *getClobbers() const {
return "";
@@ -1656,13 +1660,10 @@ namespace {
public:
MSP430TargetInfo(const std::string& triple) : TargetInfo(triple) {
TLSSupported = false;
- IntWidth = 16;
- LongWidth = 32;
- LongLongWidth = 64;
- PointerWidth = 16;
- IntAlign = 8;
- LongAlign = LongLongAlign = 8;
- PointerAlign = 8;
+ IntWidth = 16; IntAlign = 16;
+ LongWidth = 32; LongLongWidth = 64;
+ LongAlign = LongLongAlign = 16;
+ PointerWidth = 16; PointerAlign = 16;
SizeType = UnsignedInt;
IntMaxType = SignedLong;
UIntMaxType = UnsignedLong;
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index b1b250f82933..98cf42b8c3d9 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -21,67 +21,55 @@ using namespace std;
namespace clang {
llvm::StringRef getClangRepositoryPath() {
- static const char *Path = 0;
- if (Path)
- return Path;
-
- static char URL[] = "$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $";
- char *End = strstr(URL, "/lib/Basic");
+ static const char URL[] = "$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $";
+ const char *URLEnd = URL + strlen(URL);
+
+ const char *End = strstr(URL, "/lib/Basic");
if (End)
- *End = 0;
-
+ URLEnd = End;
+
End = strstr(URL, "/clang/tools/clang");
if (End)
- *End = 0;
-
- char *Begin = strstr(URL, "cfe/");
- if (Begin) {
- Path = Begin + 4;
- return Path;
- }
-
- Path = URL;
- return Path;
-}
+ URLEnd = End;
+
+ const char *Begin = strstr(URL, "cfe/");
+ if (Begin)
+ return llvm::StringRef(Begin + 4, URLEnd - Begin - 4);
+ return llvm::StringRef(URL, URLEnd - URL);
+}
-llvm::StringRef getClangRevision() {
+std::string getClangRevision() {
#ifndef SVN_REVISION
// Subversion was not available at build time?
- return llvm::StringRef();
+ return "";
#else
- static std::string revision;
- if (revision.empty()) {
- llvm::raw_string_ostream OS(revision);
- OS << strtol(SVN_REVISION, 0, 10);
- }
+ std::string revision;
+ llvm::raw_string_ostream OS(revision);
+ OS << strtol(SVN_REVISION, 0, 10);
return revision;
#endif
}
-llvm::StringRef getClangFullRepositoryVersion() {
- static std::string buf;
- if (buf.empty()) {
- llvm::raw_string_ostream OS(buf);
- OS << getClangRepositoryPath();
- llvm::StringRef Revision = getClangRevision();
- if (!Revision.empty())
- OS << ' ' << Revision;
- }
+std::string getClangFullRepositoryVersion() {
+ std::string buf;
+ llvm::raw_string_ostream OS(buf);
+ OS << getClangRepositoryPath();
+ const std::string &Revision = getClangRevision();
+ if (!Revision.empty())
+ OS << ' ' << Revision;
return buf;
}
-const char *getClangFullVersion() {
- static std::string buf;
- if (buf.empty()) {
- llvm::raw_string_ostream OS(buf);
+std::string getClangFullVersion() {
+ std::string buf;
+ llvm::raw_string_ostream OS(buf);
#ifdef CLANG_VENDOR
- OS << CLANG_VENDOR;
+ OS << CLANG_VENDOR;
#endif
- OS << "clang version " CLANG_VERSION_STRING " ("
- << getClangFullRepositoryVersion() << ')';
- }
- return buf.c_str();
+ OS << "clang version " CLANG_VERSION_STRING " ("
+ << getClangFullRepositoryVersion() << ')';
+ return buf;
}
-
+
} // end namespace clang
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 2bfaa445e568..bc2cd460d92b 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -10,3 +10,4 @@ add_subdirectory(Rewrite)
add_subdirectory(Driver)
add_subdirectory(Frontend)
add_subdirectory(Index)
+add_subdirectory(Checker)
diff --git a/lib/Checker/AdjustedReturnValueChecker.cpp b/lib/Checker/AdjustedReturnValueChecker.cpp
new file mode 100644
index 000000000000..e95a86b838b6
--- /dev/null
+++ b/lib/Checker/AdjustedReturnValueChecker.cpp
@@ -0,0 +1,98 @@
+//== AdjustedReturnValueChecker.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 AdjustedReturnValueChecker, a simple check to see if the
+// return value of a function call is different than the one the caller thinks
+// it is.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallString.h"
+
+using namespace clang;
+
+namespace {
+class AdjustedReturnValueChecker :
+ public CheckerVisitor<AdjustedReturnValueChecker> {
+public:
+ AdjustedReturnValueChecker() {}
+
+ void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+
+ static void *getTag() {
+ static int x = 0; return &x;
+ }
+};
+}
+
+void clang::RegisterAdjustedReturnValueChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new AdjustedReturnValueChecker());
+}
+
+void AdjustedReturnValueChecker::PostVisitCallExpr(CheckerContext &C,
+ const CallExpr *CE) {
+
+ // Get the result type of the call.
+ QualType expectedResultTy = CE->getType();
+
+ // Fetch the signature of the called function.
+ const GRState *state = C.getState();
+
+ SVal V = state->getSVal(CE);
+
+ if (V.isUnknown())
+ return;
+
+ // Casting to void? Discard the value.
+ if (expectedResultTy->isVoidType()) {
+ C.GenerateNode(state->BindExpr(CE, UnknownVal()));
+ return;
+ }
+
+ const MemRegion *callee = state->getSVal(CE->getCallee()).getAsRegion();
+ if (!callee)
+ return;
+
+ QualType actualResultTy;
+
+ if (const FunctionTextRegion *FT = dyn_cast<FunctionTextRegion>(callee)) {
+ const FunctionDecl *FD = FT->getDecl();
+ actualResultTy = FD->getResultType();
+ }
+ else if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(callee)) {
+ const BlockTextRegion *BR = BD->getCodeRegion();
+ const BlockPointerType *BT =
+ BR->getLocationType(C.getASTContext())->getAs<BlockPointerType>();
+ const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>();
+ actualResultTy = FT->getResultType();
+ }
+
+ // Can this happen?
+ if (actualResultTy.isNull())
+ return;
+
+ // For now, ignore references.
+ if (actualResultTy->getAs<ReferenceType>())
+ return;
+
+
+ // Are they the same?
+ if (expectedResultTy != actualResultTy) {
+ // FIXME: Do more checking and actual emit an error. At least performing
+ // the cast avoids some assertion failures elsewhere.
+ SValuator &SVator = C.getSValuator();
+ V = SVator.EvalCast(V, expectedResultTy, actualResultTy);
+ C.GenerateNode(state->BindExpr(CE, V));
+ }
+}
diff --git a/lib/Analysis/ArrayBoundChecker.cpp b/lib/Checker/ArrayBoundChecker.cpp
index 49c86068265b..74fb06f45564 100644
--- a/lib/Analysis/ArrayBoundChecker.cpp
+++ b/lib/Checker/ArrayBoundChecker.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
using namespace clang;
diff --git a/lib/Analysis/AttrNonNullChecker.cpp b/lib/Checker/AttrNonNullChecker.cpp
index aa21700c2483..83dc13e92b63 100644
--- a/lib/Analysis/AttrNonNullChecker.cpp
+++ b/lib/Checker/AttrNonNullChecker.cpp
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Checker/BasicConstraintManager.cpp
index 6dfc470530a4..e89546ecb018 100644
--- a/lib/Analysis/BasicConstraintManager.cpp
+++ b/lib/Checker/BasicConstraintManager.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "SimpleConstraintManager.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/GRStateTrait.h"
-#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Checker/BasicObjCFoundationChecks.cpp
index 67483d979291..d6c09a2e04a6 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/lib/Checker/BasicObjCFoundationChecks.cpp
@@ -15,15 +15,15 @@
#include "BasicObjCFoundationChecks.h"
-#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
-#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/MemRegion.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Checker/PathSensitive/ExplodedGraph.h"
+#include "clang/Checker/PathSensitive/GRSimpleAPICheck.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/MemRegion.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
@@ -163,61 +163,22 @@ bool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N,
// FIXME: This is going to be really slow doing these checks with
// lexical comparisons.
- std::string name = S.getAsString();
- assert (!name.empty());
- const char* cstr = &name[0];
- unsigned len = name.size();
-
- switch (len) {
- default:
- break;
- case 8:
- if (!strcmp(cstr, "compare:"))
- return CheckNilArg(N, 0);
-
- break;
-
- case 15:
- // FIXME: Checking for initWithFormat: will not work in most cases
- // yet because [NSString alloc] returns id, not NSString*. We will
- // need support for tracking expected-type information in the analyzer
- // to find these errors.
- if (!strcmp(cstr, "initWithFormat:"))
- return CheckNilArg(N, 0);
-
- break;
-
- case 16:
- if (!strcmp(cstr, "compare:options:"))
- return CheckNilArg(N, 0);
-
- break;
-
- case 22:
- if (!strcmp(cstr, "compare:options:range:"))
- return CheckNilArg(N, 0);
-
- break;
-
- case 23:
-
- if (!strcmp(cstr, "caseInsensitiveCompare:"))
- return CheckNilArg(N, 0);
-
- break;
-
- case 29:
- if (!strcmp(cstr, "compare:options:range:locale:"))
- return CheckNilArg(N, 0);
-
- break;
-
- case 37:
- if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:"))
- return CheckNilArg(N, 0);
-
- break;
- }
+ std::string NameStr = S.getAsString();
+ llvm::StringRef Name(NameStr);
+ assert(!Name.empty());
+
+ // FIXME: Checking for initWithFormat: will not work in most cases
+ // yet because [NSString alloc] returns id, not NSString*. We will
+ // need support for tracking expected-type information in the analyzer
+ // to find these errors.
+ if (Name == "caseInsensitiveCompare:" ||
+ Name == "compare:" ||
+ Name == "compare:options:" ||
+ Name == "compare:options:range:" ||
+ Name == "compare:options:range:locale:" ||
+ Name == "componentsSeparatedByCharactersInSet:" ||
+ Name == "initWithFormat:")
+ return CheckNilArg(N, 0);
return false;
}
diff --git a/lib/Analysis/BasicObjCFoundationChecks.h b/lib/Checker/BasicObjCFoundationChecks.h
index 679c6dc1df2d..679c6dc1df2d 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.h
+++ b/lib/Checker/BasicObjCFoundationChecks.h
diff --git a/lib/Analysis/BasicStore.cpp b/lib/Checker/BasicStore.cpp
index 224281b17770..6ef29429f681 100644
--- a/lib/Analysis/BasicStore.cpp
+++ b/lib/Checker/BasicStore.cpp
@@ -13,8 +13,8 @@
#include "clang/AST/ExprObjC.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Checker/PathSensitive/GRState.h"
#include "llvm/ADT/ImmutableMap.h"
using namespace clang;
@@ -40,25 +40,19 @@ public:
~BasicStoreManager() {}
- SubRegionMap *getSubRegionMap(const GRState *state) {
+ SubRegionMap *getSubRegionMap(Store store) {
return new BasicStoreSubRegionMap();
}
- SValuator::CastResult Retrieve(const GRState *state, Loc loc,
- QualType T = QualType());
+ SVal Retrieve(Store store, Loc loc, QualType T = QualType());
- const GRState *InvalidateRegion(const GRState *state, const MemRegion *R,
- const Expr *E, unsigned Count,
- InvalidatedSymbols *IS);
-
- const GRState *Bind(const GRState *state, Loc L, SVal V) {
- return state->makeWithStore(BindInternal(state->getStore(), L, V));
- }
+ Store InvalidateRegion(Store store, const MemRegion *R, const Expr *E,
+ unsigned Count, InvalidatedSymbols *IS);
Store scanForIvars(Stmt *B, const Decl* SelfDecl,
const MemRegion *SelfRegion, Store St);
- Store BindInternal(Store St, Loc loc, SVal V);
+ Store Bind(Store St, Loc loc, SVal V);
Store Remove(Store St, Loc loc);
Store getInitialStore(const LocationContext *InitLoc);
@@ -67,38 +61,28 @@ public:
return ValMgr.makeLoc(MRMgr.getVarRegion(VD, LC));
}
- const GRState *BindCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr*,
- const LocationContext*,
- SVal val) {
- return state;
+ Store BindCompoundLiteral(Store store, const CompoundLiteralExpr*,
+ const LocationContext*, SVal val) {
+ return store;
}
- SVal getLValueVar(const VarDecl *VD, const LocationContext *LC);
- SVal getLValueString(const StringLiteral *S);
- SVal getLValueIvar(const ObjCIvarDecl* D, SVal Base);
- SVal getLValueField(const FieldDecl *D, SVal Base);
- SVal getLValueElement(QualType elementType, SVal Offset, SVal Base);
-
/// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit
/// conversions between arrays and pointers.
SVal ArrayToPointer(Loc Array) { return Array; }
/// RemoveDeadBindings - Scans a BasicStore of 'state' for dead values.
/// It updatees the GRState object in place with the values removed.
- void RemoveDeadBindings(GRState &state, Stmt* Loc, SymbolReaper& SymReaper,
+ Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
void iterBindings(Store store, BindingsHandler& f);
- const GRState *BindDecl(const GRState *state, const VarRegion *VR,
- SVal InitVal) {
- return state->makeWithStore(BindDeclInternal(state->getStore(), VR,
- &InitVal));
+ Store BindDecl(Store store, const VarRegion *VR, SVal InitVal) {
+ return BindDeclInternal(store, VR, &InitVal);
}
- const GRState *BindDeclWithNoInit(const GRState *state, const VarRegion *VR) {
- return state->makeWithStore(BindDeclInternal(state->getStore(), VR, 0));
+ Store BindDeclWithNoInit(Store store, const VarRegion *VR) {
+ return BindDeclInternal(store, VR, 0);
}
Store BindDeclInternal(Store store, const VarRegion *VR, SVal *InitVal);
@@ -121,114 +105,6 @@ StoreManager* clang::CreateBasicStoreManager(GRStateManager& StMgr) {
return new BasicStoreManager(StMgr);
}
-SVal BasicStoreManager::getLValueVar(const VarDecl* VD,
- const LocationContext *LC) {
- return ValMgr.makeLoc(MRMgr.getVarRegion(VD, LC));
-}
-
-SVal BasicStoreManager::getLValueString(const StringLiteral* S) {
- return ValMgr.makeLoc(MRMgr.getStringRegion(S));
-}
-
-SVal BasicStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) {
-
- if (Base.isUnknownOrUndef())
- return Base;
-
- Loc BaseL = cast<Loc>(Base);
-
- if (isa<loc::MemRegionVal>(BaseL)) {
- const MemRegion *BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
- return ValMgr.makeLoc(MRMgr.getObjCIvarRegion(D, BaseR));
- }
-
- return UnknownVal();
-}
-
-SVal BasicStoreManager::getLValueField(const FieldDecl* D, SVal Base) {
-
- if (Base.isUnknownOrUndef())
- return Base;
-
- Loc BaseL = cast<Loc>(Base);
- const MemRegion* BaseR = 0;
-
- switch(BaseL.getSubKind()) {
- case loc::GotoLabelKind:
- return UndefinedVal();
-
- case loc::MemRegionKind:
- BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
- break;
-
- case loc::ConcreteIntKind:
- // While these seem funny, this can happen through casts.
- // FIXME: What we should return is the field offset. For example,
- // add the field offset to the integer value. That way funny things
- // like this work properly: &(((struct foo *) 0xa)->f)
- return Base;
-
- default:
- assert ("Unhandled Base.");
- return Base;
- }
-
- return ValMgr.makeLoc(MRMgr.getFieldRegion(D, BaseR));
-}
-
-SVal BasicStoreManager::getLValueElement(QualType elementType,
- SVal Offset, SVal Base) {
-
- if (Base.isUnknownOrUndef())
- return Base;
-
- Loc BaseL = cast<Loc>(Base);
- const MemRegion* BaseR = 0;
-
- switch(BaseL.getSubKind()) {
- case loc::GotoLabelKind:
- // Technically we can get here if people do funny things with casts.
- return UndefinedVal();
-
- case loc::MemRegionKind: {
- const MemRegion *R = cast<loc::MemRegionVal>(BaseL).getRegion();
-
- if (isa<ElementRegion>(R)) {
- // int x;
- // char* y = (char*) &x;
- // 'y' => ElementRegion(0, VarRegion('x'))
- // y[0] = 'a';
- return Base;
- }
-
- if (isa<TypedRegion>(R) || isa<SymbolicRegion>(R)) {
- BaseR = R;
- break;
- }
-
- break;
- }
-
- case loc::ConcreteIntKind:
- // While these seem funny, this can happen through casts.
- // FIXME: What we should return is the field offset. For example,
- // add the field offset to the integer value. That way funny things
- // like this work properly: &(((struct foo *) 0xa)->f)
- return Base;
-
- default:
- assert ("Unhandled Base.");
- return Base;
- }
-
- if (BaseR) {
- return ValMgr.makeLoc(MRMgr.getElementRegion(elementType, UnknownVal(),
- BaseR, getContext()));
- }
- else
- return UnknownVal();
-}
-
static bool isHigherOrderRawPtr(QualType T, ASTContext &C) {
bool foundPointer = false;
while (1) {
@@ -250,11 +126,9 @@ static bool isHigherOrderRawPtr(QualType T, ASTContext &C) {
}
}
-SValuator::CastResult BasicStoreManager::Retrieve(const GRState *state,
- Loc loc, QualType T) {
-
+SVal BasicStoreManager::Retrieve(Store store, Loc loc, QualType T) {
if (isa<UnknownVal>(loc))
- return SValuator::CastResult(state, UnknownVal());
+ return UnknownVal();
assert(!isa<UndefinedVal>(loc));
@@ -264,33 +138,32 @@ SValuator::CastResult BasicStoreManager::Retrieve(const GRState *state,
const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion();
if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
- return SValuator::CastResult(state, UnknownVal());
+ return UnknownVal();
- BindingsTy B = GetBindings(state->getStore());
+ BindingsTy B = GetBindings(store);
BindingsTy::data_type *Val = B.lookup(R);
if (!Val)
break;
- return SValuator::CastResult(state,
- CastRetrievedVal(*Val, cast<TypedRegion>(R), T));
+ return CastRetrievedVal(*Val, cast<TypedRegion>(R), T);
}
case loc::ConcreteIntKind:
// Some clients may call GetSVal with such an option simply because
// they are doing a quick scan through their Locs (potentially to
// invalidate their bindings). Just return Undefined.
- return SValuator::CastResult(state, UndefinedVal());
+ return UndefinedVal();
default:
assert (false && "Invalid Loc.");
break;
}
- return SValuator::CastResult(state, UnknownVal());
+ return UnknownVal();
}
-Store BasicStoreManager::BindInternal(Store store, Loc loc, SVal V) {
+Store BasicStoreManager::Bind(Store store, Loc loc, SVal V) {
if (isa<loc::ConcreteInt>(loc))
return store;
@@ -352,12 +225,10 @@ Store BasicStoreManager::Remove(Store store, Loc loc) {
}
}
-void
-BasicStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
- SymbolReaper& SymReaper,
+Store BasicStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
+ SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
{
- Store store = state.getStore();
BindingsTy B = GetBindings(store);
typedef SVal::symbol_iterator symbol_iterator;
@@ -398,7 +269,7 @@ BasicStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
break;
Marked.insert(MR);
- SVal X = Retrieve(&state, loc::MemRegionVal(MR)).getSVal();
+ SVal X = Retrieve(store, loc::MemRegionVal(MR));
// FIXME: We need to handle symbols nested in region definitions.
for (symbol_iterator SI=X.symbol_begin(),SE=X.symbol_end();SI!=SE;++SI)
@@ -431,8 +302,7 @@ BasicStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
}
}
- // Write the store back.
- state.setStore(store);
+ return store;
}
Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl,
@@ -452,7 +322,7 @@ Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl,
const MemRegion *IVR = MRMgr.getObjCIvarRegion(IV->getDecl(),
SelfRegion);
SVal X = ValMgr.getRegionValueSymbolVal(IVR);
- St = BindInternal(St, ValMgr.makeLoc(IVR), X);
+ St = Bind(St, ValMgr.makeLoc(IVR), X);
}
}
}
@@ -485,8 +355,7 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) {
const MemRegion *SelfRegion =
ValMgr.getRegionValueSymbolVal(VR).getAsRegion();
assert(SelfRegion);
- St = BindInternal(St, ValMgr.makeLoc(VR),
- loc::MemRegionVal(SelfRegion));
+ St = Bind(St, ValMgr.makeLoc(VR), loc::MemRegionVal(SelfRegion));
// Scan the method for ivar references. While this requires an
// entire AST scan, the cost should not be high in practice.
St = scanForIvars(MD->getBody(), PD, SelfRegion, St);
@@ -505,7 +374,7 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) {
if (R->hasGlobalsOrParametersStorage())
X = ValMgr.getRegionValueSymbolVal(R);
- St = BindInternal(St, ValMgr.makeLoc(R), X);
+ St = Bind(St, ValMgr.makeLoc(R), X);
}
}
return St;
@@ -543,16 +412,16 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR,
if (!InitVal) {
QualType T = VD->getType();
if (Loc::IsLocType(T))
- store = BindInternal(store, loc::MemRegionVal(VR),
+ store = Bind(store, loc::MemRegionVal(VR),
loc::ConcreteInt(BasicVals.getValue(0, T)));
else if (T->isIntegerType())
- store = BindInternal(store, loc::MemRegionVal(VR),
+ store = Bind(store, loc::MemRegionVal(VR),
nonloc::ConcreteInt(BasicVals.getValue(0, T)));
else {
// assert(0 && "ignore other types of variables");
}
} else {
- store = BindInternal(store, loc::MemRegionVal(VR), *InitVal);
+ store = Bind(store, loc::MemRegionVal(VR), *InitVal);
}
}
} else {
@@ -560,7 +429,7 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR,
QualType T = VD->getType();
if (ValMgr.getSymbolManager().canSymbolicate(T)) {
SVal V = InitVal ? *InitVal : UndefinedVal();
- store = BindInternal(store, loc::MemRegionVal(VR), V);
+ store = Bind(store, loc::MemRegionVal(VR), V);
}
}
@@ -600,18 +469,18 @@ StoreManager::BindingsHandler::~BindingsHandler() {}
// Binding invalidation.
//===----------------------------------------------------------------------===//
-const GRState *BasicStoreManager::InvalidateRegion(const GRState *state,
- const MemRegion *R,
- const Expr *E,
- unsigned Count,
- InvalidatedSymbols *IS) {
+Store BasicStoreManager::InvalidateRegion(Store store,
+ const MemRegion *R,
+ const Expr *E,
+ unsigned Count,
+ InvalidatedSymbols *IS) {
R = R->StripCasts();
if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
- return state;
+ return store;
if (IS) {
- BindingsTy B = GetBindings(state->getStore());
+ BindingsTy B = GetBindings(store);
if (BindingsTy::data_type *Val = B.lookup(R)) {
if (SymbolRef Sym = Val->getAsSymbol())
IS->insert(Sym);
@@ -620,6 +489,6 @@ const GRState *BasicStoreManager::InvalidateRegion(const GRState *state,
QualType T = cast<TypedRegion>(R)->getValueType(R->getContext());
SVal V = ValMgr.getConjuredSymbolVal(R, E, T, Count);
- return Bind(state, loc::MemRegionVal(R), V);
+ return Bind(store, loc::MemRegionVal(R), V);
}
diff --git a/lib/Analysis/BasicValueFactory.cpp b/lib/Checker/BasicValueFactory.cpp
index b33c277f86f9..246beead1208 100644
--- a/lib/Analysis/BasicValueFactory.cpp
+++ b/lib/Checker/BasicValueFactory.cpp
@@ -13,7 +13,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/BasicValueFactory.h"
+#include "clang/Checker/PathSensitive/BasicValueFactory.h"
using namespace clang;
@@ -24,9 +24,8 @@ void CompoundValData::Profile(llvm::FoldingSetNodeID& ID, QualType T,
}
void LazyCompoundValData::Profile(llvm::FoldingSetNodeID& ID,
- const GRState *state,
- const TypedRegion *region) {
- ID.AddPointer(state);
+ const void *store,const TypedRegion *region) {
+ ID.AddPointer(store);
ID.AddPointer(region);
}
@@ -124,10 +123,10 @@ BasicValueFactory::getCompoundValData(QualType T,
}
const LazyCompoundValData*
-BasicValueFactory::getLazyCompoundValData(const GRState *state,
+BasicValueFactory::getLazyCompoundValData(const void *store,
const TypedRegion *region) {
llvm::FoldingSetNodeID ID;
- LazyCompoundValData::Profile(ID, state, region);
+ LazyCompoundValData::Profile(ID, store, region);
void* InsertPos;
LazyCompoundValData *D =
@@ -135,7 +134,7 @@ BasicValueFactory::getLazyCompoundValData(const GRState *state,
if (!D) {
D = (LazyCompoundValData*) BPAlloc.Allocate<LazyCompoundValData>();
- new (D) LazyCompoundValData(state, region);
+ new (D) LazyCompoundValData(store, region);
LazyCompoundValDataSet.InsertNode(D, InsertPos);
}
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Checker/BugReporter.cpp
index 2a9531df60f1..0cf593b26009 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Checker/BugReporter.cpp
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/AST/ASTContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/AST/Expr.h"
@@ -21,7 +21,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Analysis/ProgramPoint.h"
-#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
diff --git a/lib/Analysis/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp
index 87de30ae7aec..6cf41b14dc5a 100644
--- a/lib/Analysis/BugReporterVisitors.cpp
+++ b/lib/Checker/BugReporterVisitors.cpp
@@ -14,9 +14,9 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/PathSensitive/GRState.h"
using namespace clang;
@@ -323,7 +323,7 @@ void clang::bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC,
if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)
|| V.isUndef()) {
- registerFindLastStore(BRC, R, V);
+ ::registerFindLastStore(BRC, R, V);
}
}
}
@@ -347,3 +347,21 @@ void clang::bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC,
}
}
}
+
+void clang::bugreporter::registerFindLastStore(BugReporterContext& BRC,
+ const void *data,
+ const ExplodedNode* N) {
+
+ const MemRegion *R = static_cast<const MemRegion*>(data);
+
+ if (!R)
+ return;
+
+ const GRState *state = N->getState();
+ SVal V = state->getSVal(R);
+
+ if (V.isUnknown())
+ return;
+
+ BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
+}
diff --git a/lib/Analysis/BuiltinFunctionChecker.cpp b/lib/Checker/BuiltinFunctionChecker.cpp
index a89ad2164b30..8711492049c5 100644
--- a/lib/Analysis/BuiltinFunctionChecker.cpp
+++ b/lib/Checker/BuiltinFunctionChecker.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/Checker.h"
#include "clang/Basic/Builtins.h"
#include "llvm/ADT/StringSwitch.h"
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp
index 5a15fbfb1f05..324916a6f6eb 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Checker/CFRefCount.cpp
@@ -14,15 +14,16 @@
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
-#include "clang/Analysis/PathSensitive/GRStateTrait.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Analysis/LocalCheckers.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/SymbolManager.h"
-#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngineBuilders.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/SymbolManager.h"
+#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/DomainSpecific/CocoaConventions.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/ADT/DenseMap.h"
@@ -34,129 +35,8 @@
#include <stdarg.h>
using namespace clang;
-
-//===----------------------------------------------------------------------===//
-// Utility functions.
-//===----------------------------------------------------------------------===//
-
-// The "fundamental rule" for naming conventions of methods:
-// (url broken into two lines)
-// http://developer.apple.com/documentation/Cocoa/Conceptual/
-// MemoryMgmt/Tasks/MemoryManagementRules.html
-//
-// "You take ownership of an object if you create it using a method whose name
-// begins with "alloc" or "new" or contains "copy" (for example, alloc,
-// newObject, or mutableCopy), or if you send it a retain message. You are
-// responsible for relinquishing ownership of objects you own using release
-// or autorelease. Any other time you receive an object, you must
-// not release it."
-//
-
-using llvm::StrInStrNoCase;
using llvm::StringRef;
-
-enum NamingConvention { NoConvention, CreateRule, InitRule };
-
-static inline bool isWordEnd(char ch, char prev, char next) {
- return ch == '\0'
- || (islower(prev) && isupper(ch)) // xxxC
- || (isupper(prev) && isupper(ch) && islower(next)) // XXCreate
- || !isalpha(ch);
-}
-
-static inline const char* parseWord(const char* s) {
- char ch = *s, prev = '\0';
- assert(ch != '\0');
- char next = *(s+1);
- while (!isWordEnd(ch, prev, next)) {
- prev = ch;
- ch = next;
- next = *((++s)+1);
- }
- return s;
-}
-
-static NamingConvention deriveNamingConvention(Selector S) {
- IdentifierInfo *II = S.getIdentifierInfoForSlot(0);
-
- if (!II)
- return NoConvention;
-
- const char *s = II->getNameStart();
-
- // A method/function name may contain a prefix. We don't know it is there,
- // however, until we encounter the first '_'.
- bool InPossiblePrefix = true;
- bool AtBeginning = true;
- NamingConvention C = NoConvention;
-
- while (*s != '\0') {
- // Skip '_'.
- if (*s == '_') {
- if (InPossiblePrefix) {
- // If we already have a convention, return it. Otherwise, skip
- // the prefix as if it wasn't there.
- if (C != NoConvention)
- break;
-
- InPossiblePrefix = false;
- AtBeginning = true;
- assert(C == NoConvention);
- }
- ++s;
- continue;
- }
-
- // Skip numbers, ':', etc.
- if (!isalpha(*s)) {
- ++s;
- continue;
- }
-
- const char *wordEnd = parseWord(s);
- assert(wordEnd > s);
- unsigned len = wordEnd - s;
-
- switch (len) {
- default:
- break;
- case 3:
- // Methods starting with 'new' follow the create rule.
- if (AtBeginning && StringRef(s, len).equals_lower("new"))
- C = CreateRule;
- break;
- case 4:
- // Methods starting with 'alloc' or contain 'copy' follow the
- // create rule
- if (C == NoConvention && StringRef(s, len).equals_lower("copy"))
- C = CreateRule;
- else // Methods starting with 'init' follow the init rule.
- if (AtBeginning && StringRef(s, len).equals_lower("init"))
- C = InitRule;
- break;
- case 5:
- if (AtBeginning && StringRef(s, len).equals_lower("alloc"))
- C = CreateRule;
- break;
- }
-
- // If we aren't in the prefix and have a derived convention then just
- // return it now.
- if (!InPossiblePrefix && C != NoConvention)
- return C;
-
- AtBeginning = false;
- s = wordEnd;
- }
-
- // We will get here if there wasn't more than one word
- // after the prefix.
- return C;
-}
-
-static bool followsFundamentalRule(Selector S) {
- return deriveNamingConvention(S) == CreateRule;
-}
+using llvm::StrInStrNoCase;
static const ObjCMethodDecl*
ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) {
@@ -194,34 +74,6 @@ public:
} // end anonymous namespace
//===----------------------------------------------------------------------===//
-// Type querying functions.
-//===----------------------------------------------------------------------===//
-
-static bool isRefType(QualType RetTy, const char* prefix,
- ASTContext* Ctx = 0, const char* name = 0) {
-
- // Recursively walk the typedef stack, allowing typedefs of reference types.
- while (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
- llvm::StringRef TDName = TD->getDecl()->getIdentifier()->getName();
- if (TDName.startswith(prefix) && TDName.endswith("Ref"))
- return true;
-
- RetTy = TD->getDecl()->getUnderlyingType();
- }
-
- if (!Ctx || !name)
- return false;
-
- // Is the type void*?
- const PointerType* PT = RetTy->getAs<PointerType>();
- if (!(PT->getPointeeType().getUnqualifiedType() == Ctx->VoidTy))
- return false;
-
- // Does the name start with the prefix?
- return llvm::StringRef(name).startswith(prefix);
-}
-
-//===----------------------------------------------------------------------===//
// Primitives used for constructing summaries for function/method calls.
//===----------------------------------------------------------------------===//
@@ -853,7 +705,7 @@ public:
RetainSummary* getCFSummaryCreateRule(FunctionDecl* FD);
RetainSummary* getCFSummaryGetRule(FunctionDecl* FD);
- RetainSummary* getCFCreateGetRuleSummary(FunctionDecl* FD, const char* FName);
+ RetainSummary* getCFCreateGetRuleSummary(FunctionDecl* FD, StringRef FName);
RetainSummary* getPersistentSummary(ArgEffects AE, RetEffect RetEff,
ArgEffect ReceiverEff = DoNothing,
@@ -880,10 +732,6 @@ public:
void InitializeClassMethodSummaries();
void InitializeMethodSummaries();
-
- bool isTrackedObjCObjectType(QualType T);
- bool isTrackedCFObjectType(QualType T);
-
private:
void addClsMethSummary(IdentifierInfo* ClsII, Selector S,
@@ -1072,62 +920,15 @@ RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff,
}
//===----------------------------------------------------------------------===//
-// Predicates.
-//===----------------------------------------------------------------------===//
-
-bool RetainSummaryManager::isTrackedObjCObjectType(QualType Ty) {
- if (!Ty->isObjCObjectPointerType())
- return false;
-
- const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>();
-
- // Can be true for objects with the 'NSObject' attribute.
- if (!PT)
- return true;
-
- // We assume that id<..>, id, and "Class" all represent tracked objects.
- if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
- PT->isObjCClassType())
- return true;
-
- // Does the interface subclass NSObject?
- // FIXME: We can memoize here if this gets too expensive.
- const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
-
- // Assume that anything declared with a forward declaration and no
- // @interface subclasses NSObject.
- if (ID->isForwardDecl())
- return true;
-
- IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
-
- for ( ; ID ; ID = ID->getSuperClass())
- if (ID->getIdentifier() == NSObjectII)
- return true;
-
- return false;
-}
-
-bool RetainSummaryManager::isTrackedCFObjectType(QualType T) {
- return isRefType(T, "CF") || // Core Foundation.
- isRefType(T, "CG") || // Core Graphics.
- isRefType(T, "DADisk") || // Disk Arbitration API.
- isRefType(T, "DADissenter") ||
- isRefType(T, "DASessionRef");
-}
-
-//===----------------------------------------------------------------------===//
// Summary creation for functions (largely uses of Core Foundation).
//===----------------------------------------------------------------------===//
-static bool isRetain(FunctionDecl* FD, const char* FName) {
- const char* loc = strstr(FName, "Retain");
- return loc && loc[sizeof("Retain")-1] == '\0';
+static bool isRetain(FunctionDecl* FD, StringRef FName) {
+ return FName.endswith("Retain");
}
-static bool isRelease(FunctionDecl* FD, const char* FName) {
- const char* loc = strstr(FName, "Release");
- return loc && loc[sizeof("Release")-1] == '\0';
+static bool isRelease(FunctionDecl* FD, StringRef FName) {
+ return FName.endswith("Release");
}
RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
@@ -1152,12 +953,12 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
const IdentifierInfo *II = FD->getIdentifier();
if (!II)
break;
-
- const char* FName = II->getNameStart();
+
+ StringRef FName = II->getName();
// Strip away preceding '_'. Doing this here will effect all the checks
// down below.
- while (*FName == '_') ++FName;
+ FName = FName.substr(FName.find_first_not_of('_'));
// Inspect the result type.
QualType RetTy = FT->getResultType();
@@ -1165,133 +966,63 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
// FIXME: This should all be refactored into a chain of "summary lookup"
// filters.
assert(ScratchArgs.isEmpty());
-
- switch (strlen(FName)) {
- default: break;
- case 14:
- if (!memcmp(FName, "pthread_create", 14)) {
- // Part of: <rdar://problem/7299394>. This will be addressed
- // better with IPA.
- S = getPersistentStopSummary();
- }
- break;
-
- case 17:
- // Handle: id NSMakeCollectable(CFTypeRef)
- if (!memcmp(FName, "NSMakeCollectable", 17)) {
- S = (RetTy->isObjCIdType())
- ? getUnarySummary(FT, cfmakecollectable)
- : getPersistentStopSummary();
- }
- else if (!memcmp(FName, "IOBSDNameMatching", 17) ||
- !memcmp(FName, "IOServiceMatching", 17)) {
- // Part of <rdar://problem/6961230>. (IOKit)
- // This should be addressed using a API table.
- S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
- DoNothing, DoNothing);
- }
- break;
-
- case 21:
- if (!memcmp(FName, "IOServiceNameMatching", 21)) {
- // Part of <rdar://problem/6961230>. (IOKit)
- // This should be addressed using a API table.
- S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
- DoNothing, DoNothing);
- }
- break;
-
- case 24:
- if (!memcmp(FName, "IOServiceAddNotification", 24)) {
- // Part of <rdar://problem/6961230>. (IOKit)
- // This should be addressed using a API table.
- ScratchArgs = AF.Add(ScratchArgs, 2, DecRef);
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,DoNothing);
- }
- break;
-
- case 25:
- if (!memcmp(FName, "IORegistryEntryIDMatching", 25)) {
- // Part of <rdar://problem/6961230>. (IOKit)
- // This should be addressed using a API table.
- S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
- DoNothing, DoNothing);
- }
- break;
-
- case 26:
- if (!memcmp(FName, "IOOpenFirmwarePathMatching", 26)) {
- // Part of <rdar://problem/6961230>. (IOKit)
- // This should be addressed using a API table.
- S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
- DoNothing, DoNothing);
- }
- break;
-
- case 27:
- if (!memcmp(FName, "IOServiceGetMatchingService", 27)) {
- // Part of <rdar://problem/6961230>.
- // This should be addressed using a API table.
- ScratchArgs = AF.Add(ScratchArgs, 1, DecRef);
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
- }
- break;
- case 28:
- if (!memcmp(FName, "IOServiceGetMatchingServices", 28)) {
- // FIXES: <rdar://problem/6326900>
- // This should be addressed using a API table. This strcmp is also
- // a little gross, but there is no need to super optimize here.
- ScratchArgs = AF.Add(ScratchArgs, 1, DecRef);
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,
- DoNothing);
- }
- else if (!memcmp(FName, "CVPixelBufferCreateWithBytes", 28)) {
- // FIXES: <rdar://problem/7283567>
- // Eventually this can be improved by recognizing that the pixel
- // buffer passed to CVPixelBufferCreateWithBytes is released via
- // a callback and doing full IPA to make sure this is done correctly.
- // FIXME: This function has an out parameter that returns an
- // allocated object.
- ScratchArgs = AF.Add(ScratchArgs, 7, StopTracking);
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,
- DoNothing);
- }
- break;
-
- case 29:
- if (!memcmp(FName, "CGBitmapContextCreateWithData", 29)) {
- // FIXES: <rdar://problem/7358899>
- // Eventually this can be improved by recognizing that 'releaseInfo'
- // passed to CGBitmapContextCreateWithData is released via
- // a callback and doing full IPA to make sure this is done correctly.
- ScratchArgs = AF.Add(ScratchArgs, 8, StopTracking);
- S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
- DoNothing,DoNothing);
- }
- break;
-
- case 32:
- if (!memcmp(FName, "IOServiceAddMatchingNotification", 32)) {
- // Part of <rdar://problem/6961230>.
- // This should be addressed using a API table.
- ScratchArgs = AF.Add(ScratchArgs, 2, DecRef);
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
- }
- break;
-
- case 34:
- if (!memcmp(FName, "CVPixelBufferCreateWithPlanarBytes", 34)) {
- // FIXES: <rdar://problem/7283567>
- // Eventually this can be improved by recognizing that the pixel
- // buffer passed to CVPixelBufferCreateWithPlanarBytes is released
- // via a callback and doing full IPA to make sure this is done
- // correctly.
- ScratchArgs = AF.Add(ScratchArgs, 12, StopTracking);
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,
- DoNothing);
- }
- break;
+ if (FName == "pthread_create") {
+ // Part of: <rdar://problem/7299394>. This will be addressed
+ // better with IPA.
+ S = getPersistentStopSummary();
+ } else if (FName == "NSMakeCollectable") {
+ // Handle: id NSMakeCollectable(CFTypeRef)
+ S = (RetTy->isObjCIdType())
+ ? getUnarySummary(FT, cfmakecollectable)
+ : getPersistentStopSummary();
+ } else if (FName == "IOBSDNameMatching" ||
+ FName == "IOServiceMatching" ||
+ FName == "IOServiceNameMatching" ||
+ FName == "IORegistryEntryIDMatching" ||
+ FName == "IOOpenFirmwarePathMatching") {
+ // Part of <rdar://problem/6961230>. (IOKit)
+ // This should be addressed using a API table.
+ S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
+ DoNothing, DoNothing);
+ } else if (FName == "IOServiceGetMatchingService" ||
+ FName == "IOServiceGetMatchingServices") {
+ // FIXES: <rdar://problem/6326900>
+ // This should be addressed using a API table. This strcmp is also
+ // a little gross, but there is no need to super optimize here.
+ ScratchArgs = AF.Add(ScratchArgs, 1, DecRef);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+ } else if (FName == "IOServiceAddNotification" ||
+ FName == "IOServiceAddMatchingNotification") {
+ // Part of <rdar://problem/6961230>. (IOKit)
+ // This should be addressed using a API table.
+ ScratchArgs = AF.Add(ScratchArgs, 2, DecRef);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+ } else if (FName == "CVPixelBufferCreateWithBytes") {
+ // FIXES: <rdar://problem/7283567>
+ // Eventually this can be improved by recognizing that the pixel
+ // buffer passed to CVPixelBufferCreateWithBytes is released via
+ // a callback and doing full IPA to make sure this is done correctly.
+ // FIXME: This function has an out parameter that returns an
+ // allocated object.
+ ScratchArgs = AF.Add(ScratchArgs, 7, StopTracking);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+ } else if (FName == "CGBitmapContextCreateWithData") {
+ // FIXES: <rdar://problem/7358899>
+ // Eventually this can be improved by recognizing that 'releaseInfo'
+ // passed to CGBitmapContextCreateWithData is released via
+ // a callback and doing full IPA to make sure this is done correctly.
+ ScratchArgs = AF.Add(ScratchArgs, 8, StopTracking);
+ S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
+ DoNothing, DoNothing);
+ } else if (FName == "CVPixelBufferCreateWithPlanarBytes") {
+ // FIXES: <rdar://problem/7283567>
+ // Eventually this can be improved by recognizing that the pixel
+ // buffer passed to CVPixelBufferCreateWithPlanarBytes is released
+ // via a callback and doing full IPA to make sure this is done
+ // correctly.
+ ScratchArgs = AF.Add(ScratchArgs, 12, StopTracking);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
}
// Did we get a summary?
@@ -1312,10 +1043,10 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
if (RetTy->isPointerType()) {
// For CoreFoundation ('CF') types.
- if (isRefType(RetTy, "CF", &Ctx, FName)) {
+ if (cocoa::isRefType(RetTy, "CF", FName)) {
if (isRetain(FD, FName))
S = getUnarySummary(FT, cfretain);
- else if (strstr(FName, "MakeCollectable"))
+ else if (FName.find("MakeCollectable") != StringRef::npos)
S = getUnarySummary(FT, cfmakecollectable);
else
S = getCFCreateGetRuleSummary(FD, FName);
@@ -1324,7 +1055,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
}
// For CoreGraphics ('CG') types.
- if (isRefType(RetTy, "CG", &Ctx, FName)) {
+ if (cocoa::isRefType(RetTy, "CG", FName)) {
if (isRetain(FD, FName))
S = getUnarySummary(FT, cfretain);
else
@@ -1334,9 +1065,9 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
}
// For the Disk Arbitration API (DiskArbitration/DADisk.h)
- if (isRefType(RetTy, "DADisk") ||
- isRefType(RetTy, "DADissenter") ||
- isRefType(RetTy, "DASessionRef")) {
+ if (cocoa::isRefType(RetTy, "DADisk") ||
+ cocoa::isRefType(RetTy, "DADissenter") ||
+ cocoa::isRefType(RetTy, "DASessionRef")) {
S = getCFCreateGetRuleSummary(FD, FName);
break;
}
@@ -1348,10 +1079,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
// about that don't return a pointer type.
if (FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G')) {
// Test for 'CGCF'.
- if (FName[1] == 'G' && FName[2] == 'C' && FName[3] == 'F')
- FName += 4;
- else
- FName += 2;
+ FName = FName.substr(FName.startswith("CGCF") ? 4 : 2);
if (isRelease(FD, FName))
S = getUnarySummary(FT, cfrelease);
@@ -1398,12 +1126,13 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
RetainSummary*
RetainSummaryManager::getCFCreateGetRuleSummary(FunctionDecl* FD,
- const char* FName) {
+ StringRef FName) {
- if (strstr(FName, "Create") || strstr(FName, "Copy"))
+ if (FName.find("Create") != StringRef::npos ||
+ FName.find("Copy") != StringRef::npos)
return getCFSummaryCreateRule(FD);
- if (strstr(FName, "Get"))
+ if (FName.find("Get") != StringRef::npos)
return getCFSummaryGetRule(FD);
return getDefaultSummary();
@@ -1471,7 +1200,7 @@ RetainSummaryManager::getInitMethodSummary(QualType RetTy) {
assert(ScratchArgs.isEmpty());
// 'init' methods conceptually return a newly allocated object and claim
// the receiver.
- if (isTrackedObjCObjectType(RetTy) || isTrackedCFObjectType(RetTy))
+ if (cocoa::isCocoaObjectRef(RetTy) || cocoa::isCFObjectRef(RetTy))
return getPersistentSummary(ObjCInitRetE, DecRefMsg);
return getDefaultSummary();
@@ -1486,7 +1215,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
QualType RetTy = FD->getResultType();
// Determine if there is a special return effect for this method.
- if (isTrackedObjCObjectType(RetTy)) {
+ if (cocoa::isCocoaObjectRef(RetTy)) {
if (FD->getAttr<NSReturnsRetainedAttr>()) {
Summ.setRetEffect(ObjCAllocRetE);
}
@@ -1510,7 +1239,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
bool isTrackedLoc = false;
// Determine if there is a special return effect for this method.
- if (isTrackedObjCObjectType(MD->getResultType())) {
+ if (cocoa::isCocoaObjectRef(MD->getResultType())) {
if (MD->getAttr<NSReturnsRetainedAttr>()) {
Summ.setRetEffect(ObjCAllocRetE);
return;
@@ -1560,18 +1289,18 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
}
// Look for methods that return an owned object.
- if (isTrackedObjCObjectType(RetTy)) {
+ if (cocoa::isCocoaObjectRef(RetTy)) {
// EXPERIMENTAL: Assume the Cocoa conventions for all objects returned
// by instance methods.
- RetEffect E = followsFundamentalRule(S)
+ RetEffect E = cocoa::followsFundamentalRule(S)
? ObjCAllocRetE : RetEffect::MakeNotOwned(RetEffect::ObjC);
return getPersistentSummary(E, ReceiverEff, MayEscape);
}
// Look for methods that return an owned core foundation object.
- if (isTrackedCFObjectType(RetTy)) {
- RetEffect E = followsFundamentalRule(S)
+ if (cocoa::isCFObjectRef(RetTy)) {
+ RetEffect E = cocoa::followsFundamentalRule(S)
? RetEffect::MakeOwned(RetEffect::CF, true)
: RetEffect::MakeNotOwned(RetEffect::CF);
@@ -1653,7 +1382,7 @@ RetainSummaryManager::getInstanceMethodSummary(Selector S,
assert(ScratchArgs.isEmpty());
// "initXXX": pass-through for receiver.
- if (deriveNamingConvention(S) == InitRule)
+ if (cocoa::deriveNamingConvention(S) == cocoa::InitRule)
Summ = getInitMethodSummary(RetTy);
else
Summ = getCommonMethodSummary(MD, S, RetTy);
@@ -2880,10 +2609,12 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
StoreManager::InvalidatedSymbols IS;
- state = StoreMgr.InvalidateRegions(state, RegionsToInvalidate.data(),
+ Store store = state->getStore();
+ store = StoreMgr.InvalidateRegions(store, RegionsToInvalidate.data(),
RegionsToInvalidate.data() +
RegionsToInvalidate.size(),
Ex, Count, &IS);
+ state = state->makeWithStore(store);
for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(),
E = IS.end(); I!=E; ++I) {
// Remove any existing reference-count binding.
diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt
new file mode 100644
index 000000000000..7b21d08dcb71
--- /dev/null
+++ b/lib/Checker/CMakeLists.txt
@@ -0,0 +1,67 @@
+set(LLVM_NO_RTTI 1)
+
+add_clang_library(clangChecker
+ AdjustedReturnValueChecker.cpp
+ ArrayBoundChecker.cpp
+ AttrNonNullChecker.cpp
+ BasicConstraintManager.cpp
+ BasicObjCFoundationChecks.cpp
+ BasicStore.cpp
+ BasicValueFactory.cpp
+ BugReporter.cpp
+ BugReporterVisitors.cpp
+ BuiltinFunctionChecker.cpp
+ CFRefCount.cpp
+ CallAndMessageChecker.cpp
+ CallInliner.cpp
+ CastToStructChecker.cpp
+ CheckDeadStores.cpp
+ CheckObjCDealloc.cpp
+ CheckObjCInstMethSignature.cpp
+ CheckObjCUnusedIVars.cpp
+ CheckSecuritySyntaxOnly.cpp
+ CheckSizeofPointer.cpp
+ Checker.cpp
+ CocoaConventions.cpp
+ DereferenceChecker.cpp
+ DivZeroChecker.cpp
+ Environment.cpp
+ ExplodedGraph.cpp
+ FixedAddressChecker.cpp
+ FlatStore.cpp
+ GRBlockCounter.cpp
+ GRCoreEngine.cpp
+ GRExprEngine.cpp
+ GRExprEngineExperimentalChecks.cpp
+ GRState.cpp
+ LLVMConventionsChecker.cpp
+ MallocChecker.cpp
+ ManagerRegistry.cpp
+ MemRegion.cpp
+ NSAutoreleasePoolChecker.cpp
+ NSErrorChecker.cpp
+ NoReturnFunctionChecker.cpp
+ OSAtomicChecker.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
+ SimpleSValuator.cpp
+ Store.cpp
+ SymbolManager.cpp
+ UndefBranchChecker.cpp
+ UndefCapturedBlockVarChecker.cpp
+ UndefResultChecker.cpp
+ UndefinedArraySubscriptChecker.cpp
+ UndefinedAssignmentChecker.cpp
+ VLASizeChecker.cpp
+ ValueManager.cpp
+ )
diff --git a/lib/Analysis/CallAndMessageChecker.cpp b/lib/Checker/CallAndMessageChecker.cpp
index c287354650b8..9013c3818b0c 100644
--- a/lib/Analysis/CallAndMessageChecker.cpp
+++ b/lib/Checker/CallAndMessageChecker.cpp
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/TargetInfo.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/AST/ParentMap.h"
#include "GRExprEngineInternalChecks.h"
diff --git a/lib/Analysis/CallInliner.cpp b/lib/Checker/CallInliner.cpp
index d18bbcc0174a..d94994b19437 100644
--- a/lib/Analysis/CallInliner.cpp
+++ b/lib/Checker/CallInliner.cpp
@@ -11,9 +11,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
using namespace clang;
diff --git a/lib/Analysis/CastToStructChecker.cpp b/lib/Checker/CastToStructChecker.cpp
index 219c09f6ab7a..bef5bc285ee2 100644
--- a/lib/Analysis/CastToStructChecker.cpp
+++ b/lib/Checker/CastToStructChecker.cpp
@@ -13,7 +13,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Checker/CheckDeadStores.cpp
index 6e4d8998620d..4a7ca705488a 100644
--- a/lib/Analysis/CheckDeadStores.cpp
+++ b/lib/Checker/CheckDeadStores.cpp
@@ -12,11 +12,11 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/AST/ASTContext.h"
diff --git a/lib/Analysis/CheckObjCDealloc.cpp b/lib/Checker/CheckObjCDealloc.cpp
index 87c1f270a65c..d9606f1306d4 100644
--- a/lib/Analysis/CheckObjCDealloc.cpp
+++ b/lib/Checker/CheckObjCDealloc.cpp
@@ -13,9 +13,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/LocalCheckers.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/DeclObjC.h"
diff --git a/lib/Analysis/CheckObjCInstMethSignature.cpp b/lib/Checker/CheckObjCInstMethSignature.cpp
index 10ba896557df..8c43a45d92c0 100644
--- a/lib/Analysis/CheckObjCInstMethSignature.cpp
+++ b/lib/Checker/CheckObjCInstMethSignature.cpp
@@ -13,9 +13,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/LocalCheckers.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Type.h"
#include "clang/AST/ASTContext.h"
diff --git a/lib/Analysis/CheckObjCUnusedIVars.cpp b/lib/Checker/CheckObjCUnusedIVars.cpp
index d4067c900f3f..f2cf58191632 100644
--- a/lib/Analysis/CheckObjCUnusedIVars.cpp
+++ b/lib/Checker/CheckObjCUnusedIVars.cpp
@@ -13,9 +13,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/LocalCheckers.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/DeclObjC.h"
diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Checker/CheckSecuritySyntaxOnly.cpp
index f4874a5dfe4c..923baf50f3f6 100644
--- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp
+++ b/lib/Checker/CheckSecuritySyntaxOnly.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/TargetInfo.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/lib/Analysis/CheckSizeofPointer.cpp b/lib/Checker/CheckSizeofPointer.cpp
index 4f5da9f5a716..bbe494c99da5 100644
--- a/lib/Analysis/CheckSizeofPointer.cpp
+++ b/lib/Checker/CheckSizeofPointer.cpp
@@ -12,9 +12,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
using namespace clang;
diff --git a/lib/Analysis/Checker.cpp b/lib/Checker/Checker.cpp
index fb9d04d947b7..36323b9efb61 100644
--- a/lib/Analysis/Checker.cpp
+++ b/lib/Checker/Checker.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/Checker.h"
using namespace clang;
Checker::~Checker() {}
diff --git a/lib/Checker/CocoaConventions.cpp b/lib/Checker/CocoaConventions.cpp
new file mode 100644
index 000000000000..3ba887ccc7e3
--- /dev/null
+++ b/lib/Checker/CocoaConventions.cpp
@@ -0,0 +1,195 @@
+//===- CocoaConventions.h - Special handling of Cocoa conventions -*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Checker/DomainSpecific/CocoaConventions.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "llvm/ADT/StringExtras.h"
+
+using namespace clang;
+
+using llvm::StringRef;
+
+// The "fundamental rule" for naming conventions of methods:
+// (url broken into two lines)
+// http://developer.apple.com/documentation/Cocoa/Conceptual/
+// MemoryMgmt/Tasks/MemoryManagementRules.html
+//
+// "You take ownership of an object if you create it using a method whose name
+// begins with "alloc" or "new" or contains "copy" (for example, alloc,
+// newObject, or mutableCopy), or if you send it a retain message. You are
+// responsible for relinquishing ownership of objects you own using release
+// or autorelease. Any other time you receive an object, you must
+// not release it."
+//
+
+static bool isWordEnd(char ch, char prev, char next) {
+ return ch == '\0'
+ || (islower(prev) && isupper(ch)) // xxxC
+ || (isupper(prev) && isupper(ch) && islower(next)) // XXCreate
+ || !isalpha(ch);
+}
+
+static const char* parseWord(const char* s) {
+ char ch = *s, prev = '\0';
+ assert(ch != '\0');
+ char next = *(s+1);
+ while (!isWordEnd(ch, prev, next)) {
+ prev = ch;
+ ch = next;
+ next = *((++s)+1);
+ }
+ return s;
+}
+
+cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S) {
+ IdentifierInfo *II = S.getIdentifierInfoForSlot(0);
+
+ if (!II)
+ return NoConvention;
+
+ const char *s = II->getNameStart();
+
+ // A method/function name may contain a prefix. We don't know it is there,
+ // however, until we encounter the first '_'.
+ bool InPossiblePrefix = true;
+ bool AtBeginning = true;
+ NamingConvention C = NoConvention;
+
+ while (*s != '\0') {
+ // Skip '_'.
+ if (*s == '_') {
+ if (InPossiblePrefix) {
+ // If we already have a convention, return it. Otherwise, skip
+ // the prefix as if it wasn't there.
+ if (C != NoConvention)
+ break;
+
+ InPossiblePrefix = false;
+ AtBeginning = true;
+ assert(C == NoConvention);
+ }
+ ++s;
+ continue;
+ }
+
+ // Skip numbers, ':', etc.
+ if (!isalpha(*s)) {
+ ++s;
+ continue;
+ }
+
+ const char *wordEnd = parseWord(s);
+ assert(wordEnd > s);
+ unsigned len = wordEnd - s;
+
+ switch (len) {
+ default:
+ break;
+ case 3:
+ // Methods starting with 'new' follow the create rule.
+ if (AtBeginning && StringRef(s, len).equals_lower("new"))
+ C = CreateRule;
+ break;
+ case 4:
+ // Methods starting with 'alloc' or contain 'copy' follow the
+ // create rule
+ if (C == NoConvention && StringRef(s, len).equals_lower("copy"))
+ C = CreateRule;
+ else // Methods starting with 'init' follow the init rule.
+ if (AtBeginning && StringRef(s, len).equals_lower("init"))
+ C = InitRule;
+ break;
+ case 5:
+ if (AtBeginning && StringRef(s, len).equals_lower("alloc"))
+ C = CreateRule;
+ break;
+ }
+
+ // If we aren't in the prefix and have a derived convention then just
+ // return it now.
+ if (!InPossiblePrefix && C != NoConvention)
+ return C;
+
+ AtBeginning = false;
+ s = wordEnd;
+ }
+
+ // We will get here if there wasn't more than one word
+ // after the prefix.
+ return C;
+}
+
+bool cocoa::isRefType(QualType RetTy, llvm::StringRef Prefix,
+ llvm::StringRef Name) {
+ // Recursively walk the typedef stack, allowing typedefs of reference types.
+ while (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
+ llvm::StringRef TDName = TD->getDecl()->getIdentifier()->getName();
+ if (TDName.startswith(Prefix) && TDName.endswith("Ref"))
+ return true;
+
+ RetTy = TD->getDecl()->getUnderlyingType();
+ }
+
+ if (Name.empty())
+ return false;
+
+ // Is the type void*?
+ const PointerType* PT = RetTy->getAs<PointerType>();
+ if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType()))
+ return false;
+
+ // Does the name start with the prefix?
+ return Name.startswith(Prefix);
+}
+
+bool cocoa::isCFObjectRef(QualType T) {
+ return isRefType(T, "CF") || // Core Foundation.
+ isRefType(T, "CG") || // Core Graphics.
+ isRefType(T, "DADisk") || // Disk Arbitration API.
+ isRefType(T, "DADissenter") ||
+ isRefType(T, "DASessionRef");
+}
+
+
+bool cocoa::isCocoaObjectRef(QualType Ty) {
+ if (!Ty->isObjCObjectPointerType())
+ return false;
+
+ const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>();
+
+ // Can be true for objects with the 'NSObject' attribute.
+ if (!PT)
+ return true;
+
+ // We assume that id<..>, id, and "Class" all represent tracked objects.
+ if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
+ PT->isObjCClassType())
+ return true;
+
+ // Does the interface subclass NSObject?
+ // FIXME: We can memoize here if this gets too expensive.
+ const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
+
+ // Assume that anything declared with a forward declaration and no
+ // @interface subclasses NSObject.
+ if (ID->isForwardDecl())
+ return true;
+
+ for ( ; ID ; ID = ID->getSuperClass())
+ if (ID->getIdentifier()->getName() == "NSObject")
+ return true;
+
+ return false;
+}
diff --git a/lib/Analysis/DereferenceChecker.cpp b/lib/Checker/DereferenceChecker.cpp
index 98243874d7d9..0cbc4086701a 100644
--- a/lib/Analysis/DereferenceChecker.cpp
+++ b/lib/Checker/DereferenceChecker.cpp
@@ -12,10 +12,10 @@
//
//===----------------------------------------------------------------------===//
-#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 "clang/Checker/Checkers/DereferenceChecker.h"
+#include "clang/Checker/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Analysis/DivZeroChecker.cpp b/lib/Checker/DivZeroChecker.cpp
index 266c23609422..e1346e11b6fd 100644
--- a/lib/Analysis/DivZeroChecker.cpp
+++ b/lib/Checker/DivZeroChecker.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Analysis/Environment.cpp b/lib/Checker/Environment.cpp
index f04cf7b05fed..c2c9190fc9ff 100644
--- a/lib/Analysis/Environment.cpp
+++ b/lib/Checker/Environment.cpp
@@ -10,7 +10,7 @@
// This file defined the Environment and EnvironmentManager classes.
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRState.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "llvm/ADT/ImmutableMap.h"
diff --git a/lib/Analysis/ExplodedGraph.cpp b/lib/Checker/ExplodedGraph.cpp
index 3b339ffc0dfe..20429b951992 100644
--- a/lib/Analysis/ExplodedGraph.cpp
+++ b/lib/Checker/ExplodedGraph.cpp
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/ExplodedGraph.h"
+#include "clang/Checker/PathSensitive/GRState.h"
#include "clang/AST/Stmt.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/DenseMap.h"
diff --git a/lib/Analysis/FixedAddressChecker.cpp b/lib/Checker/FixedAddressChecker.cpp
index 031ca44b602e..04c17d6d7abb 100644
--- a/lib/Analysis/FixedAddressChecker.cpp
+++ b/lib/Checker/FixedAddressChecker.cpp
@@ -13,7 +13,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Checker/FlatStore.cpp b/lib/Checker/FlatStore.cpp
new file mode 100644
index 000000000000..dac66def5dc9
--- /dev/null
+++ b/lib/Checker/FlatStore.cpp
@@ -0,0 +1,166 @@
+//=== FlatStore.cpp - Flat region-based store model -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "llvm/ADT/ImmutableIntervalMap.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace clang;
+using llvm::Interval;
+
+// The actual store type.
+typedef llvm::ImmutableIntervalMap<SVal> BindingVal;
+typedef llvm::ImmutableMap<const MemRegion *, BindingVal> RegionBindings;
+
+namespace {
+class FlatStoreManager : public StoreManager {
+ RegionBindings::Factory RBFactory;
+ BindingVal::Factory BVFactory;
+
+public:
+ FlatStoreManager(GRStateManager &mgr)
+ : StoreManager(mgr),
+ RBFactory(mgr.getAllocator()),
+ BVFactory(mgr.getAllocator()) {}
+
+ SVal Retrieve(Store store, Loc L, QualType T);
+ Store Bind(Store store, Loc L, SVal val);
+ Store Remove(Store St, Loc L);
+ Store BindCompoundLiteral(Store store, const CompoundLiteralExpr* cl,
+ const LocationContext *LC, SVal v);
+
+ Store getInitialStore(const LocationContext *InitLoc) {
+ return RBFactory.GetEmptyMap().getRoot();
+ }
+
+ SubRegionMap *getSubRegionMap(Store store) {
+ return 0;
+ }
+
+ SVal ArrayToPointer(Loc Array);
+ Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots){
+ return store;
+ }
+
+ Store BindDecl(Store store, const VarRegion *VR, SVal initVal);
+
+ Store BindDeclWithNoInit(Store store, const VarRegion *VR);
+
+ typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols;
+
+ Store InvalidateRegion(Store store, const MemRegion *R, const Expr *E,
+ unsigned Count, InvalidatedSymbols *IS);
+
+ void print(Store store, llvm::raw_ostream& Out, const char* nl,
+ const char *sep);
+ void iterBindings(Store store, BindingsHandler& f);
+
+private:
+ static RegionBindings getRegionBindings(Store store) {
+ return RegionBindings(static_cast<const RegionBindings::TreeTy*>(store));
+ }
+
+ Interval RegionToInterval(const MemRegion *R);
+
+ SVal RetrieveRegionWithNoBinding(const MemRegion *R, QualType T);
+};
+} // end anonymous namespace
+
+StoreManager *clang::CreateFlatStoreManager(GRStateManager &StMgr) {
+ return new FlatStoreManager(StMgr);
+}
+
+SVal FlatStoreManager::Retrieve(Store store, Loc L, QualType T) {
+ const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
+ Interval I = RegionToInterval(R);
+ RegionBindings B = getRegionBindings(store);
+ const BindingVal *BV = B.lookup(R);
+ if (BV) {
+ const SVal *V = BVFactory.Lookup(*BV, I);
+ if (V)
+ return *V;
+ else
+ return RetrieveRegionWithNoBinding(R, T);
+ }
+ return RetrieveRegionWithNoBinding(R, T);
+}
+
+SVal FlatStoreManager::RetrieveRegionWithNoBinding(const MemRegion *R,
+ QualType T) {
+ if (R->hasStackNonParametersStorage())
+ return UndefinedVal();
+ else
+ return ValMgr.getRegionValueSymbolVal(R, T);
+}
+
+Store FlatStoreManager::Bind(Store store, Loc L, SVal val) {
+ const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
+ RegionBindings B = getRegionBindings(store);
+ const BindingVal *V = B.lookup(R);
+
+ BindingVal BV = BVFactory.GetEmptyMap();
+ if (V)
+ BV = *V;
+
+ Interval I = RegionToInterval(R);
+ BV = BVFactory.Add(BV, I, val);
+ B = RBFactory.Add(B, R, BV);
+ return B.getRoot();
+}
+
+Store FlatStoreManager::Remove(Store store, Loc L) {
+ return store;
+}
+
+Store FlatStoreManager::BindCompoundLiteral(Store store,
+ const CompoundLiteralExpr* cl,
+ const LocationContext *LC,
+ SVal v) {
+ return store;
+}
+
+SVal FlatStoreManager::ArrayToPointer(Loc Array) {
+ return Array;
+}
+
+Store FlatStoreManager::BindDecl(Store store, const VarRegion *VR,
+ SVal initVal) {
+ return store;
+}
+
+Store FlatStoreManager::BindDeclWithNoInit(Store store, const VarRegion *VR) {
+ return store;
+}
+
+Store FlatStoreManager::InvalidateRegion(Store store, const MemRegion *R,
+ const Expr *E, unsigned Count,
+ InvalidatedSymbols *IS) {
+ return store;
+}
+
+void FlatStoreManager::print(Store store, llvm::raw_ostream& Out,
+ const char* nl, const char *sep) {
+}
+
+void FlatStoreManager::iterBindings(Store store, BindingsHandler& f) {
+}
+
+Interval FlatStoreManager::RegionToInterval(const MemRegion *R) {
+ switch (R->getKind()) {
+ case MemRegion::VarRegionKind: {
+ QualType T = cast<VarRegion>(R)->getValueType(Ctx);
+ uint64_t Size = Ctx.getTypeSize(T);
+ return Interval(0, Size-1);
+ }
+ default:
+ llvm_unreachable("Region kind unhandled.");
+ return Interval(0, 0);
+ }
+}
diff --git a/lib/Analysis/GRBlockCounter.cpp b/lib/Checker/GRBlockCounter.cpp
index 4f4103ac45b4..3fa3e1ebb9c6 100644
--- a/lib/Analysis/GRBlockCounter.cpp
+++ b/lib/Checker/GRBlockCounter.cpp
@@ -13,7 +13,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/GRBlockCounter.h"
+#include "clang/Checker/PathSensitive/GRBlockCounter.h"
#include "llvm/ADT/ImmutableMap.h"
using namespace clang;
diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp
index 209452a3927a..d54b0777eda7 100644
--- a/lib/Analysis/GRCoreEngine.cpp
+++ b/lib/Checker/GRCoreEngine.cpp
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/PathSensitive/GRCoreEngine.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/AST/Expr.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/DenseMap.h"
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp
index 8f8d859e0ca0..7f863193743b 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Checker/GRExprEngine.cpp
@@ -12,11 +12,10 @@
// functions and build the ExplodedGraph at the expression level.
//
//===----------------------------------------------------------------------===//
-
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
-#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/PathSensitive/GRExprEngineBuilders.h"
+#include "clang/Checker/PathSensitive/Checker.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
@@ -48,7 +47,7 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
}
-static QualType GetCalleeReturnType(const CallExpr *CE) {
+static QualType GetCalleeReturnType(const CallExpr *CE) {
const Expr *Callee = CE->getCallee();
QualType T = Callee->getType();
if (const PointerType *PT = T->getAs<PointerType>()) {
@@ -62,7 +61,7 @@ static QualType GetCalleeReturnType(const CallExpr *CE) {
return T;
}
-static bool CalleeReturnsReference(const CallExpr *CE) {
+static bool CalleeReturnsReference(const CallExpr *CE) {
return (bool) GetCalleeReturnType(CE)->getAs<ReferenceType>();
}
@@ -177,10 +176,10 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
else {
CurrSet = (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_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit);
@@ -191,7 +190,7 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
// automatically.
}
-void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
+void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
ExplodedNodeSet &Dst,
const GRState *state,
ExplodedNode *Pred) {
@@ -220,8 +219,8 @@ void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
// CheckerEvalCall returns true if one of the checkers processed the node.
// This may return void when all call evaluation logic goes to some checker
// in the future.
-bool GRExprEngine::CheckerEvalCall(const CallExpr *CE,
- ExplodedNodeSet &Dst,
+bool GRExprEngine::CheckerEvalCall(const CallExpr *CE,
+ ExplodedNodeSet &Dst,
ExplodedNode *Pred) {
bool Evaluated = false;
ExplodedNodeSet DstTmp;
@@ -246,21 +245,21 @@ bool GRExprEngine::CheckerEvalCall(const CallExpr *CE,
return Evaluated;
}
-// FIXME: This is largely copy-paste from CheckerVisit(). Need to
+// FIXME: This is largely copy-paste from CheckerVisit(). Need to
// unify.
void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE,
ExplodedNodeSet &Dst,
ExplodedNodeSet &Src,
SVal location, SVal val, bool isPrevisit) {
-
+
if (Checkers.empty()) {
Dst.insert(Src);
return;
}
-
+
ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
-
+
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
{
ExplodedNodeSet *CurrSet = 0;
@@ -273,16 +272,16 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE,
void *tag = I->first;
Checker *checker = I->second;
-
+
for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
NI != NE; ++NI)
checker->GR_VisitBind(*CurrSet, *Builder, *this, AssignE, StoreE,
*NI, tag, location, val, isPrevisit);
-
+
// Update which NodeSet is the current one.
PrevSet = CurrSet;
}
-
+
// Don't autotransition. The CheckerContext objects should do this
// automatically.
}
@@ -300,7 +299,8 @@ static void RegisterInternalChecks(GRExprEngine &Eng) {
// 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.
+ // object.
+ RegisterAdjustedReturnValueChecker(Eng);
RegisterAttrNonNullChecker(Eng);
RegisterCallAndMessageChecker(Eng);
RegisterDereferenceChecker(Eng);
@@ -311,6 +311,7 @@ static void RegisterInternalChecks(GRExprEngine &Eng) {
RegisterUndefinedArraySubscriptChecker(Eng);
RegisterUndefinedAssignmentChecker(Eng);
RegisterUndefBranchChecker(Eng);
+ RegisterUndefCapturedBlockVarChecker(Eng);
RegisterUndefResultChecker(Eng);
// This is not a checker yet.
@@ -336,7 +337,7 @@ GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf)
BR(mgr, *this), TF(tf) {
// Register internal checks.
RegisterInternalChecks(*this);
-
+
// FIXME: Eventually remove the TF object entirely.
TF->RegisterChecks(*this);
TF->RegisterPrinters(getStateManager().Printers);
@@ -375,7 +376,7 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
// FIXME: It would be nice if we had a more general mechanism to add
// such preconditions. Some day.
do {
- const Decl *D = InitLoc->getDecl();
+ const Decl *D = InitLoc->getDecl();
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// Precondition: the first argument of 'main' is an integer guaranteed
// to be > 0.
@@ -387,11 +388,11 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
QualType T = PD->getType();
if (!T->isIntegerType())
break;
-
+
const MemRegion *R = state->getRegion(PD, InitLoc);
if (!R)
break;
-
+
SVal V = state->getSVal(loc::MemRegionVal(R));
SVal Constraint_untested = EvalBinOp(state, BinaryOperator::GT, V,
ValMgr.makeZeroVal(T),
@@ -399,23 +400,23 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
DefinedOrUnknownSVal *Constraint =
dyn_cast<DefinedOrUnknownSVal>(&Constraint_untested);
-
+
if (!Constraint)
break;
-
+
if (const GRState *newState = state->Assume(*Constraint, true))
state = newState;
-
+
break;
}
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
// Precondition: 'self' is always non-null upon entry to an Objective-C
// method.
const ImplicitParamDecl *SelfD = MD->getSelfDecl();
const MemRegion *R = state->getRegion(SelfD, InitLoc);
SVal V = state->getSVal(loc::MemRegionVal(R));
-
+
if (const Loc *LV = dyn_cast<Loc>(&V)) {
// Assume that the pointer value in 'self' is non-null.
state = state->Assume(*LV, true);
@@ -423,7 +424,7 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
}
}
} while (0);
-
+
return state;
}
@@ -434,19 +435,19 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
/// EvalAssume - Called by ConstraintManager. Used to call checker-specific
/// logic for handling assumptions on symbolic values.
const GRState *GRExprEngine::ProcessAssume(const GRState *state, SVal cond,
- bool assumption) {
+ bool assumption) {
for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
I != E; ++I) {
if (!state)
- return NULL;
-
+ return NULL;
+
state = I->second->EvalAssume(state, cond, assumption);
}
-
+
if (!state)
return NULL;
-
+
return TF->EvalAssume(state, cond, assumption);
}
@@ -615,7 +616,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
case Stmt::AsmStmtClass:
VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst);
break;
-
+
case Stmt::BlockDeclRefExprClass:
VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(S), Pred, Dst, false);
break;
@@ -637,7 +638,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
break;
}
- if (AMgr.shouldEagerlyAssume() &&
+ if (AMgr.shouldEagerlyAssume() &&
(B->isRelationalOp() || B->isEqualityOp())) {
ExplodedNodeSet Tmp;
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp, false);
@@ -695,7 +696,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
// This case isn't for branch processing, but for handling the
// initialization of a condition variable.
VisitCondInit(cast<ForStmt>(S)->getConditionVariable(), S, Pred, Dst);
- break;
+ break;
case Stmt::ImplicitCastExprClass:
case Stmt::CStyleCastExprClass: {
@@ -703,7 +704,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
VisitCast(C, C->getSubExpr(), Pred, Dst, false);
break;
}
-
+
case Stmt::IfStmtClass:
// This case isn't for branch processing, but for handling the
// initialization of a condition variable.
@@ -775,7 +776,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
case Stmt::StringLiteralClass:
VisitLValue(cast<StringLiteral>(S), Pred, Dst);
break;
-
+
case Stmt::SwitchStmtClass:
// This case isn't for branch processing, but for handling the
// initialization of a condition variable.
@@ -793,18 +794,18 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
VisitUnaryOperator(U, Pred, Dst, false);
break;
}
-
+
case Stmt::WhileStmtClass:
// This case isn't for branch processing, but for handling the
// initialization of a condition variable.
VisitCondInit(cast<WhileStmt>(S)->getConditionVariable(), S, Pred, Dst);
- break;
+ break;
}
}
void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
ExplodedNodeSet& Dst) {
-
+
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
Ex->getLocStart(),
"Error evaluating statement");
@@ -836,27 +837,27 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
case Stmt::CompoundAssignOperatorClass:
VisitBinaryOperator(cast<BinaryOperator>(Ex), Pred, Dst, true);
return;
-
+
case Stmt::BlockDeclRefExprClass:
VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(Ex), Pred, Dst, true);
return;
-
+
case Stmt::CallExprClass:
case Stmt::CXXOperatorCallExprClass: {
CallExpr *C = cast<CallExpr>(Ex);
assert(CalleeReturnsReferenceOrRecord(C));
- VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true);
+ VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true);
break;
}
-
+
case Stmt::CompoundLiteralExprClass:
VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(Ex), Pred, Dst, true);
- return;
+ return;
case Stmt::DeclRefExprClass:
VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true);
return;
-
+
case Stmt::ImplicitCastExprClass:
case Stmt::CStyleCastExprClass: {
CastExpr *C = cast<CastExpr>(Ex);
@@ -864,7 +865,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
VisitCast(C, C->getSubExpr(), Pred, Dst, true);
break;
}
-
+
case Stmt::MemberExprClass:
VisitMemberExpr(cast<MemberExpr>(Ex), Pred, Dst, true);
return;
@@ -872,11 +873,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
case Stmt::ObjCIvarRefExprClass:
VisitObjCIvarRefExpr(cast<ObjCIvarRefExpr>(Ex), Pred, Dst, true);
return;
-
+
case Stmt::ObjCMessageExprClass: {
ObjCMessageExpr *ME = cast<ObjCMessageExpr>(Ex);
assert(ReceiverReturnsReferenceOrRecord(ME));
- VisitObjCMessageExpr(ME, Pred, Dst, true);
+ VisitObjCMessageExpr(ME, Pred, Dst, true);
return;
}
@@ -911,7 +912,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
case Stmt::IntegerLiteralClass:
CreateCXXTemporaryObject(Ex, Pred, Dst);
return;
-
+
default:
// Arbitrary subexpressions can return aggregate temporaries that
// can be used in a lvalue context. We need to enhance our support
@@ -1083,7 +1084,7 @@ void GRExprEngine::ProcessBranch(Stmt* Condition, Stmt* Term,
SVal recovered = RecoverCastedSymbol(getStateManager(),
builder.getState(), Condition,
getContext());
-
+
if (!recovered.isUnknown()) {
X = recovered;
}
@@ -1165,7 +1166,7 @@ void GRExprEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) {
void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R,
ExplodedNode* Pred, ExplodedNodeSet& Dst) {
- assert(Ex == CurrentStmt &&
+ assert(Ex == CurrentStmt &&
Pred->getLocationContext()->getCFG()->isBlkExpr(Ex));
const GRState* state = GetState(Pred);
@@ -1203,7 +1204,7 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
if (CondV_untested.isUndef()) {
//ExplodedNode* N = builder.generateDefaultCaseNode(state, true);
- // FIXME: add checker
+ // FIXME: add checker
//UndefBranches.insert(N);
return;
@@ -1247,7 +1248,7 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt()));
DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt ? DefaultSt : state,
CondV, CaseVal);
-
+
// Now "assume" that the case matches.
if (const GRState* stateNew = state->Assume(Res, true)) {
builder.generateCaseStmtNode(I, stateNew);
@@ -1271,7 +1272,7 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
DefaultSt = NULL;
}
}
-
+
// Concretize the next value in the range.
if (V1.Val.getInt() == V2.Val.getInt())
break;
@@ -1314,7 +1315,7 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred,
MakeNode(Dst, B, Pred, state->BindExpr(B, X));
return;
}
-
+
DefinedOrUnknownSVal XD = cast<DefinedOrUnknownSVal>(X);
// We took the RHS. Because the value of the '&&' or '||' expression must
@@ -1347,16 +1348,16 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred,
void GRExprEngine::VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
-
+
ExplodedNodeSet Tmp;
-
+
CanQualType T = getContext().getCanonicalType(BE->getType());
SVal V = ValMgr.getBlockPointer(BE->getBlockDecl(), T,
Pred->getLocationContext());
MakeNode(Tmp, BE, Pred, GetState(Pred)->BindExpr(BE, V),
ProgramPoint::PostLValueKind);
-
+
// Post-visit the BlockExpr.
CheckerVisit(BE, Dst, Tmp, false);
}
@@ -1391,7 +1392,7 @@ void GRExprEngine::VisitCommonDeclRefExpr(Expr *Ex, const NamedDecl *D,
else
V = UnknownVal();
}
-
+
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V),
ProgramPoint::PostLValueKind);
}
@@ -1494,19 +1495,19 @@ void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Stmt *AssignE,
Stmt* StoreE, ExplodedNode* Pred,
const GRState* state, SVal location, SVal Val,
bool atDeclInit) {
-
-
+
+
// Do a previsit of the bind.
ExplodedNodeSet CheckedSet, Src;
Src.Add(Pred);
CheckerVisitBind(AssignE, StoreE, CheckedSet, Src, location, Val, true);
-
+
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I!=E; ++I) {
-
+
if (Pred != *I)
state = GetState(*I);
-
+
const GRState* newState = 0;
if (atDeclInit) {
@@ -1565,7 +1566,7 @@ void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr *AssignE,
SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind,
ProgramPoint::PostStoreKind);
SaveAndRestore<const void*> OldTag(Builder->Tag, tag);
-
+
// Proceed with the store.
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
EvalBind(Dst, AssignE, StoreE, *NI, GetState(*NI), location, Val);
@@ -1578,12 +1579,12 @@ void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred,
// Are we loading from a region? This actually results in two loads; one
// to fetch the address of the referenced value and one to fetch the
// referenced value.
- if (const TypedRegion *TR =
+ if (const TypedRegion *TR =
dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
-
+
QualType ValTy = TR->getValueType(getContext());
if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) {
- static int loadReferenceTag = 0;
+ static int loadReferenceTag = 0;
ExplodedNodeSet Tmp;
EvalLoadCommon(Tmp, Ex, Pred, state, location, &loadReferenceTag,
getContext().getPointerType(RT->getPointeeType()));
@@ -1593,11 +1594,11 @@ void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred,
state = GetState(*I);
location = state->getSVal(Ex);
EvalLoadCommon(Dst, Ex, *I, state, location, tag, LoadTy);
- }
+ }
return;
}
}
-
+
EvalLoadCommon(Dst, Ex, Pred, state, location, tag, LoadTy);
}
@@ -1605,16 +1606,16 @@ void GRExprEngine::EvalLoadCommon(ExplodedNodeSet& Dst, Expr *Ex,
ExplodedNode* Pred,
const GRState* state, SVal location,
const void *tag, QualType LoadTy) {
-
+
// Evaluate the location (checks for bad dereferences).
ExplodedNodeSet Tmp;
EvalLocation(Tmp, Ex, Pred, state, location, tag, true);
if (Tmp.empty())
return;
-
+
assert(!location.isUndef());
-
+
SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
SaveAndRestore<const void*> OldTag(Builder->Tag);
@@ -1627,7 +1628,7 @@ void GRExprEngine::EvalLoadCommon(ExplodedNodeSet& Dst, Expr *Ex,
ProgramPoint::PostLoadKind, tag);
}
else {
- SVal V = state->getSVal(cast<Loc>(location), LoadTy.isNull() ?
+ SVal V = state->getSVal(cast<Loc>(location), LoadTy.isNull() ?
Ex->getType() : LoadTy);
MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, V), ProgramPoint::PostLoadKind,
tag);
@@ -1644,11 +1645,11 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
Dst.Add(Pred);
return;
}
-
+
ExplodedNodeSet Src, Tmp;
Src.Add(Pred);
ExplodedNodeSet *PrevSet = &Src;
-
+
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
{
ExplodedNodeSet *CurrSet = 0;
@@ -1658,10 +1659,10 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
CurrSet = (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) {
// Use the 'state' argument only when the predecessor node is the
@@ -1670,7 +1671,7 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
*NI == Pred ? state : GetState(*NI),
location, tag, isLoad);
}
-
+
// Update which NodeSet is the current one.
PrevSet = CurrSet;
}
@@ -1688,7 +1689,7 @@ public:
CallExprWLItem(const CallExpr::arg_iterator &i, ExplodedNode *n)
: I(i), N(n) {}
-};
+};
} // end anonymous namespace
void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
@@ -1706,31 +1707,31 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
llvm::SmallVector<CallExprWLItem, 20> WorkList;
WorkList.reserve(AE - AI);
WorkList.push_back(CallExprWLItem(AI, Pred));
-
+
ExplodedNodeSet ArgsEvaluated;
while (!WorkList.empty()) {
CallExprWLItem Item = WorkList.back();
WorkList.pop_back();
-
+
if (Item.I == AE) {
ArgsEvaluated.insert(Item.N);
continue;
}
-
+
// Evaluate the argument.
ExplodedNodeSet Tmp;
const unsigned ParamIdx = Item.I - AI;
-
+
bool VisitAsLvalue = false;
if (Proto && ParamIdx < Proto->getNumArgs())
VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType();
-
+
if (VisitAsLvalue)
VisitLValue(*Item.I, Item.N, Tmp);
else
Visit(*Item.I, Item.N, Tmp);
-
+
// Enqueue evaluating the next argument on the worklist.
++(Item.I);
@@ -1741,32 +1742,32 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
// Now process the call itself.
ExplodedNodeSet DstTmp;
Expr* Callee = CE->getCallee()->IgnoreParens();
-
+
for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(),
NE=ArgsEvaluated.end(); NI != NE; ++NI) {
// Evaluate the callee.
ExplodedNodeSet DstTmp2;
- Visit(Callee, *NI, DstTmp2);
+ Visit(Callee, *NI, DstTmp2);
// Perform the previsit of the CallExpr, storing the results in DstTmp.
CheckerVisit(CE, DstTmp, DstTmp2, true);
}
-
+
// Finally, evaluate the function call. We try each of the checkers
// to see if the can evaluate the function call.
ExplodedNodeSet DstTmp3;
-
+
for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
DI != DE; ++DI) {
-
+
const GRState* state = GetState(*DI);
SVal L = state->getSVal(Callee);
-
+
// FIXME: Add support for symbolic function calls (calls involving
// function pointer values that are symbolic).
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
ExplodedNodeSet DstChecker;
-
+
// If the callee is processed by a checker, skip the rest logic.
if (CheckerEvalCall(CE, DstChecker, *DI))
DstTmp3.insert(DstChecker);
@@ -1774,17 +1775,17 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(),
DE_Checker = DstChecker.end();
DI_Checker != DE_Checker; ++DI_Checker) {
-
+
// Dispatch to the plug-in transfer function.
unsigned OldSize = DstTmp3.size();
SaveOr OldHasGen(Builder->HasGeneratedNode);
Pred = *DI_Checker;
-
+
// Dispatch to transfer function logic to handle the call itself.
// FIXME: Allow us to chain together transfer functions.
- assert(Builder && "GRStmtNodeBuilder must be defined.");
+ assert(Builder && "GRStmtNodeBuilder must be defined.");
getTF().EvalCall(DstTmp3, *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 && DstTmp3.size() == OldSize &&
@@ -1793,24 +1794,24 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
}
}
}
-
+
// Finally, perform the post-condition check of the CallExpr and store
// the created nodes in 'Dst'.
-
+
if (!(!asLValue && CalleeReturnsReference(CE))) {
CheckerVisit(CE, Dst, DstTmp3, false);
return;
}
-
+
// Handle the case where the called function returns a reference but
// we expect an rvalue. For such cases, convert the reference to
- // an rvalue.
+ // an rvalue.
// FIXME: This conversion doesn't actually happen unless the result
// of CallExpr is consumed by another expression.
ExplodedNodeSet DstTmp4;
CheckerVisit(CE, DstTmp4, DstTmp3, false);
QualType LoadTy = CE->getType();
-
+
static int *ConvertToRvalueTag = 0;
for (ExplodedNodeSet::iterator NI = DstTmp4.begin(), NE = DstTmp4.end();
NI!=NE; ++NI) {
@@ -1950,10 +1951,10 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S,
Stmt* elem = S->getElement();
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);
@@ -1993,90 +1994,96 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S,
// Transfer function: Objective-C message expressions.
//===----------------------------------------------------------------------===//
+namespace {
+class ObjCMsgWLItem {
+public:
+ ObjCMessageExpr::arg_iterator I;
+ ExplodedNode *N;
+
+ ObjCMsgWLItem(const ObjCMessageExpr::arg_iterator &i, ExplodedNode *n)
+ : I(i), N(n) {}
+};
+} // end anonymous namespace
+
void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
ExplodedNodeSet& Dst, bool asLValue){
- VisitObjCMessageExprArgHelper(ME, ME->arg_begin(), ME->arg_end(),
- Pred, Dst, asLValue);
-}
+ // Create a worklist to process both the arguments.
+ llvm::SmallVector<ObjCMsgWLItem, 20> WL;
-void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
- ObjCMessageExpr::arg_iterator AI,
- ObjCMessageExpr::arg_iterator AE,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst,
- bool asLValue) {
- if (AI == AE) {
+ // But first evaluate the receiver (if any).
+ ObjCMessageExpr::arg_iterator AI = ME->arg_begin(), AE = ME->arg_end();
+ if (Expr *Receiver = ME->getReceiver()) {
+ ExplodedNodeSet Tmp;
+ Visit(Receiver, Pred, Tmp);
- // Process the receiver.
+ if (Tmp.empty())
+ return;
- if (Expr* Receiver = ME->getReceiver()) {
- ExplodedNodeSet Tmp;
- Visit(Receiver, Pred, Tmp);
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I)
+ WL.push_back(ObjCMsgWLItem(AI, *I));
+ }
+ else
+ WL.push_back(ObjCMsgWLItem(AI, Pred));
- for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE;
- ++NI)
- VisitObjCMessageExprDispatchHelper(ME, *NI, Dst, asLValue);
+ // Evaluate the arguments.
+ ExplodedNodeSet ArgsEvaluated;
+ while (!WL.empty()) {
+ ObjCMsgWLItem Item = WL.back();
+ WL.pop_back();
- return;
+ if (Item.I == AE) {
+ ArgsEvaluated.insert(Item.N);
+ continue;
}
- VisitObjCMessageExprDispatchHelper(ME, Pred, Dst, asLValue);
- return;
- }
-
- ExplodedNodeSet Tmp;
- Visit(*AI, Pred, Tmp);
+ // Evaluate the subexpression.
+ ExplodedNodeSet Tmp;
- ++AI;
+ // FIXME: [Objective-C++] handle arguments that are references
+ Visit(*Item.I, Item.N, Tmp);
- for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI)
- VisitObjCMessageExprArgHelper(ME, AI, AE, *NI, Dst, asLValue);
-}
+ // Enqueue evaluating the next argument on the worklist.
+ ++(Item.I);
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
+ WL.push_back(ObjCMsgWLItem(Item.I, *NI));
+ }
-void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst,
- bool asLValue) {
+ // Now that the arguments are processed, handle the previsits checks.
+ ExplodedNodeSet DstPrevisit;
+ CheckerVisit(ME, DstPrevisit, ArgsEvaluated, true);
- // Handle previsits checks.
- ExplodedNodeSet Src, DstTmp;
- Src.Add(Pred);
-
- CheckerVisit(ME, DstTmp, Src, true);
-
- ExplodedNodeSet PostVisitSrc;
+ // Proceed with evaluate the message expression.
+ ExplodedNodeSet DstEval;
- for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
- DI!=DE; ++DI) {
+ for (ExplodedNodeSet::iterator DI = DstPrevisit.begin(),
+ DE = DstPrevisit.end(); DI != DE; ++DI) {
Pred = *DI;
bool RaisesException = false;
-
- unsigned OldSize = PostVisitSrc.size();
+ unsigned OldSize = DstEval.size();
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- SaveOr OldHasGen(Builder->HasGeneratedNode);
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
if (const Expr *Receiver = ME->getReceiver()) {
const GRState *state = Pred->getState();
// Bifurcate the state into nil and non-nil ones.
- DefinedOrUnknownSVal receiverVal =
+ DefinedOrUnknownSVal receiverVal =
cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
const GRState *notNilState, *nilState;
llvm::tie(notNilState, nilState) = state->Assume(receiverVal);
- // There are three cases: can be nil or non-nil, must be nil, must be
+ // There are three cases: can be nil or non-nil, must be nil, must be
// non-nil. We handle must be nil, and merge the rest two into non-nil.
if (nilState && !notNilState) {
- CheckerEvalNilReceiver(ME, PostVisitSrc, nilState, Pred);
+ CheckerEvalNilReceiver(ME, DstEval, nilState, Pred);
continue;
}
- assert(notNilState);
-
// Check if the "raise" message was sent.
+ assert(notNilState);
if (ME->getSelector() == RaiseSel)
RaisesException = true;
@@ -2086,7 +2093,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
Builder->BuildSinks = true;
// Dispatch to plug-in transfer function.
- EvalObjCMessageExpr(PostVisitSrc, ME, Pred, notNilState);
+ EvalObjCMessageExpr(DstEval, ME, Pred, notNilState);
}
else {
IdentifierInfo* ClsName = ME->getClassName();
@@ -2104,7 +2111,8 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
// Lazily create a cache of the selectors.
if (!NSExceptionInstanceRaiseSelectors) {
ASTContext& Ctx = getContext();
- NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS];
+ NSExceptionInstanceRaiseSelectors =
+ new Selector[NUM_RAISE_SELECTORS];
llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
unsigned idx = 0;
@@ -2133,36 +2141,35 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
Builder->BuildSinks = true;
// Dispatch to plug-in transfer function.
- EvalObjCMessageExpr(PostVisitSrc, ME, Pred, Builder->GetState(Pred));
+ EvalObjCMessageExpr(DstEval, ME, Pred, Builder->GetState(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 && PostVisitSrc.size() == OldSize &&
+ if (!Builder->BuildSinks && DstEval.size() == OldSize &&
!Builder->HasGeneratedNode)
- MakeNode(PostVisitSrc, ME, Pred, GetState(Pred));
+ MakeNode(DstEval, ME, Pred, GetState(Pred));
}
// Finally, perform the post-condition check of the ObjCMessageExpr and store
// the created nodes in 'Dst'.
if (!(!asLValue && ReceiverReturnsReference(ME))) {
- CheckerVisit(ME, Dst, PostVisitSrc, false);
+ CheckerVisit(ME, Dst, DstEval, false);
return;
}
-
+
// Handle the case where the message expression returns a reference but
// we expect an rvalue. For such cases, convert the reference to
- // an rvalue.
+ // an rvalue.
// FIXME: This conversion doesn't actually happen unless the result
// of ObjCMessageExpr is consumed by another expression.
ExplodedNodeSet DstRValueConvert;
- CheckerVisit(ME, DstRValueConvert, PostVisitSrc, false);
+ CheckerVisit(ME, DstRValueConvert, DstEval, false);
QualType LoadTy = ME->getType();
-
+
static int *ConvertToRvalueTag = 0;
for (ExplodedNodeSet::iterator NI = DstRValueConvert.begin(),
- NE = DstRValueConvert.end();
- NI!=NE; ++NI) {
+ NE = DstRValueConvert.end(); NI != NE; ++NI) {
const GRState *state = GetState(*NI);
EvalLoad(Dst, ME, *NI, state, state->getSVal(ME),
&ConvertToRvalueTag, LoadTy);
@@ -2173,7 +2180,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
// Transfer functions: Miscellaneous statements.
//===----------------------------------------------------------------------===//
-void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred,
+void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred,
ExplodedNodeSet &Dst, bool asLValue) {
ExplodedNodeSet S1;
QualType T = CastE->getType();
@@ -2235,8 +2242,8 @@ void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred,
ExplodedNode* N = *I;
const GRState* state = GetState(N);
SVal V = state->getSVal(Ex);
- const SValuator::CastResult &Res = SVator.EvalCast(V, state, T, ExTy);
- state = Res.getState()->BindExpr(CastE, Res.getSVal());
+ V = SVator.EvalCast(V, T, ExTy);
+ state = state->BindExpr(CastE, V);
MakeNode(Dst, CastE, N, state);
}
return;
@@ -2296,7 +2303,7 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
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 = GetState(N);
@@ -2311,12 +2318,12 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
// UnknownVal.
if (InitVal.isUnknown() ||
!getConstraintManager().canReasonAbout(InitVal)) {
- InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx,
+ InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx,
Builder->getCurrentBlockCount());
}
-
+
EvalBind(Dst, DS, DS, *I, state,
- loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
+ loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
}
else {
state = state->bindDeclWithNoInit(state->getRegion(VD, LC));
@@ -2327,26 +2334,26 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
void GRExprEngine::VisitCondInit(VarDecl *VD, Stmt *S,
ExplodedNode *Pred, ExplodedNodeSet& Dst) {
-
- Expr* InitEx = VD->getInit();
+
+ Expr* InitEx = VD->getInit();
ExplodedNodeSet Tmp;
Visit(InitEx, Pred, Tmp);
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
ExplodedNode *N = *I;
const GRState *state = GetState(N);
-
+
const LocationContext *LC = N->getLocationContext();
SVal InitVal = state->getSVal(InitEx);
-
+
// Recover some path-sensitivity if a scalar value evaluated to
// UnknownVal.
if (InitVal.isUnknown() ||
!getConstraintManager().canReasonAbout(InitVal)) {
- InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx,
+ InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx,
Builder->getCurrentBlockCount());
}
-
+
EvalBind(Dst, S, S, N, state,
loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
}
@@ -2461,12 +2468,14 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
}
else if (!T.getTypePtr()->isConstantSizeType()) {
// FIXME: Add support for VLAs.
+ Dst.Add(Pred);
return;
}
else if (T->isObjCInterfaceType()) {
// Some code tries to take the sizeof an ObjCInterfaceType, relying that
// the compiler has laid out its representation. Just report Unknown
// for these.
+ Dst.Add(Pred);
return;
}
else {
@@ -2475,10 +2484,10 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
}
}
else // Get alignment of the type.
- amt = CharUnits::fromQuantity(getContext().getTypeAlign(T) / 8);
+ amt = getContext().getTypeAlignInChars(T);
MakeNode(Dst, Ex, Pred,
- GetState(Pred)->BindExpr(Ex,
+ GetState(Pred)->BindExpr(Ex,
ValMgr.makeIntVal(amt.getQuantity(), Ex->getType())));
}
@@ -2567,7 +2576,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
assert(IV.getBitWidth() == getContext().getTypeSize(U->getType()));
assert(U->getType()->isIntegerType());
assert(IV.isSigned() == U->getType()->isSignedIntegerType());
- SVal X = ValMgr.makeIntVal(IV);
+ SVal X = ValMgr.makeIntVal(IV);
MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X));
return;
}
@@ -2715,7 +2724,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
if (V2_untested.isUnknownOrUndef()) {
MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested));
continue;
- }
+ }
DefinedSVal V2 = cast<DefinedSVal>(V2_untested);
// Handle all other values.
@@ -2770,19 +2779,19 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
}
-void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
+void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet & Dst) {
// Get the this object region from StoreManager.
const MemRegion *R =
ValMgr.getRegionManager().getCXXThisRegion(TE->getType(),
Pred->getLocationContext());
-
+
const GRState *state = GetState(Pred);
SVal V = state->getSVal(loc::MemRegionVal(R));
MakeNode(Dst, TE, Pred, state->BindExpr(TE, V));
}
-void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred,
+void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred,
ExplodedNodeSet& Dst) {
VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst);
}
@@ -2808,7 +2817,7 @@ void GRExprEngine::VisitAsmStmtHelperOutputs(AsmStmt* A,
void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A,
AsmStmt::inputs_iterator I,
AsmStmt::inputs_iterator E,
- ExplodedNode* Pred,
+ ExplodedNode* Pred,
ExplodedNodeSet& Dst) {
if (I == E) {
@@ -2846,7 +2855,7 @@ void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A,
void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
-
+
ExplodedNodeSet Src;
if (Expr *RetE = RS->getRetValue()) {
Visit(RetE, Pred, Src);
@@ -2854,25 +2863,25 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred,
else {
Src.Add(Pred);
}
-
+
ExplodedNodeSet CheckedSet;
CheckerVisit(RS, CheckedSet, Src, true);
-
+
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I != E; ++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 &&
+
+ // Handle the case where no nodes where generated.
+ if (!Builder->BuildSinks && Dst.size() == size &&
!Builder->HasGeneratedNode)
MakeNode(Dst, RS, Pred, GetState(Pred));
}
@@ -2926,7 +2935,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
// EXPERIMENTAL: "Conjured" symbols.
// FIXME: Handle structs.
QualType T = RHS->getType();
-
+
if ((RightV.isUnknown()||!getConstraintManager().canReasonAbout(RightV))
&& (Loc::IsLocType(T) || (T->isScalarType()&&T->isIntegerType()))) {
unsigned Count = Builder->getCurrentBlockCount();
@@ -2940,12 +2949,12 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
EvalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV,RightV);
continue;
}
-
+
if (!B->isAssignmentOp()) {
// Process non-assignments except commas or short-circuited
// logical expressions (LAnd and LOr).
SVal Result = EvalBinOp(state, Op, LeftV, RightV, B->getType());
-
+
if (Result.isUnknown()) {
if (OldSt != state) {
// Generate a new node if we have already created a new state.
@@ -2953,12 +2962,12 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
}
else
Tmp3.Add(*I2);
-
+
continue;
}
-
+
state = state->BindExpr(B, Result);
-
+
MakeNode(Tmp3, B, *I2, state);
continue;
}
@@ -3004,13 +3013,11 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
QualType RTy = getContext().getCanonicalType(RHS->getType());
// Promote LHS.
- llvm::tie(state, V) = SVator.EvalCast(V, state, CLHSTy, LTy);
+ V = SVator.EvalCast(V, CLHSTy, LTy);
// Compute the result of the operation.
- SVal Result;
- llvm::tie(state, Result) = SVator.EvalCast(EvalBinOp(state, Op, V,
- RightV, CTy),
- state, B->getType(), CTy);
+ SVal Result = SVator.EvalCast(EvalBinOp(state, Op, V, RightV, CTy),
+ B->getType(), CTy);
// EXPERIMENTAL: "Conjured" symbols.
// FIXME: Handle structs.
@@ -3030,12 +3037,12 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
LHSVal = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), LTy, Count);
// However, we need to convert the symbol to the computation type.
- llvm::tie(state, Result) = SVator.EvalCast(LHSVal, state, CTy, LTy);
+ Result = SVator.EvalCast(LHSVal, CTy, LTy);
}
else {
// The left-hand side may bind to a different value then the
// computation type.
- llvm::tie(state, LHSVal) = SVator.EvalCast(Result, state, LTy, CTy);
+ LHSVal = SVator.EvalCast(Result, LTy, CTy);
}
EvalStore(Tmp3, B, LHS, *I4, state->BindExpr(B, Result),
@@ -3047,24 +3054,24 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
CheckerVisit(B, Dst, Tmp3, false);
}
-void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
+void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
ExplodedNodeSet Tmp;
Visit(Ex, Pred, Tmp);
for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
const GRState *state = GetState(*I);
-
+
// Bind the temporary object to the value of the expression. Then bind
// the expression to the location of the object.
SVal V = state->getSVal(Ex);
- const MemRegion *R =
+ const MemRegion *R =
ValMgr.getRegionManager().getCXXObjectRegion(Ex,
Pred->getLocationContext());
state = state->bindLoc(loc::MemRegionVal(R), V);
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R)));
- }
+ }
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/GRExprEngineExperimentalChecks.cpp b/lib/Checker/GRExprEngineExperimentalChecks.cpp
index 33479b0cb7e5..89b4e4b6392f 100644
--- a/lib/Analysis/GRExprEngineExperimentalChecks.cpp
+++ b/lib/Checker/GRExprEngineExperimentalChecks.cpp
@@ -14,7 +14,7 @@
#include "GRExprEngineInternalChecks.h"
#include "GRExprEngineExperimentalChecks.h"
-#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
using namespace clang;
diff --git a/lib/Analysis/GRExprEngineExperimentalChecks.h b/lib/Checker/GRExprEngineExperimentalChecks.h
index 9a9da32e556e..9a9da32e556e 100644
--- a/lib/Analysis/GRExprEngineExperimentalChecks.h
+++ b/lib/Checker/GRExprEngineExperimentalChecks.h
diff --git a/lib/Analysis/GRExprEngineInternalChecks.h b/lib/Checker/GRExprEngineInternalChecks.h
index e2354ed09888..64a930d504cf 100644
--- a/lib/Analysis/GRExprEngineInternalChecks.h
+++ b/lib/Checker/GRExprEngineInternalChecks.h
@@ -19,6 +19,7 @@ namespace clang {
class GRExprEngine;
+void RegisterAdjustedReturnValueChecker(GRExprEngine &Eng);
void RegisterAttrNonNullChecker(GRExprEngine &Eng);
void RegisterDereferenceChecker(GRExprEngine &Eng);
void RegisterDivZeroChecker(GRExprEngine &Eng);
@@ -35,8 +36,8 @@ void RegisterArrayBoundChecker(GRExprEngine &Eng);
void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng);
void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng);
void RegisterUndefBranchChecker(GRExprEngine &Eng);
+void RegisterUndefCapturedBlockVarChecker(GRExprEngine &Eng);
void RegisterUndefResultChecker(GRExprEngine &Eng);
-
void RegisterNoReturnFunctionChecker(GRExprEngine &Eng);
void RegisterBuiltinFunctionChecker(GRExprEngine &Eng);
void RegisterOSAtomicChecker(GRExprEngine &Eng);
diff --git a/lib/Analysis/GRState.cpp b/lib/Checker/GRState.cpp
index 051d465f41b7..592f930316e1 100644
--- a/lib/Analysis/GRState.cpp
+++ b/lib/Checker/GRState.cpp
@@ -11,9 +11,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/GRStateTrait.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/raw_ostream.h"
@@ -50,7 +50,8 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
state, RegionRoots);
// Clean up the store.
- StoreMgr->RemoveDeadBindings(NewState, Loc, SymReaper, RegionRoots);
+ NewState.St = StoreMgr->RemoveDeadBindings(NewState.St, Loc, SymReaper,
+ RegionRoots);
return ConstraintMgr->RemoveDeadBindings(getPersistentState(NewState),
SymReaper);
@@ -301,7 +302,8 @@ bool ScanReachableSymbols::scan(const MemRegion *R) {
// Now look at the subregions.
if (!SRM.get())
- SRM.reset(state->getStateManager().getStoreManager().getSubRegionMap(state));
+ SRM.reset(state->getStateManager().getStoreManager().
+ getSubRegionMap(state->getStore()));
return SRM->iterSubRegions(R, *this);
}
diff --git a/lib/Checker/LLVMConventionsChecker.cpp b/lib/Checker/LLVMConventionsChecker.cpp
new file mode 100644
index 000000000000..14f0fc1280df
--- /dev/null
+++ b/lib/Checker/LLVMConventionsChecker.cpp
@@ -0,0 +1,335 @@
+//=== LLVMConventionsChecker.cpp - Check LLVM codebase conventions ---*- C++ -*-
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines LLVMConventionsChecker, a bunch of small little checks
+// for checking specific coding conventions in the LLVM/Clang codebase.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include <string>
+#include "llvm/ADT/StringRef.h"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Generic type checking routines.
+//===----------------------------------------------------------------------===//
+
+static bool IsLLVMStringRef(QualType T) {
+ const RecordType *RT = T->getAs<RecordType>();
+ if (!RT)
+ return false;
+
+ return llvm::StringRef(QualType(RT, 0).getAsString()) ==
+ "class llvm::StringRef";
+}
+
+static bool InStdNamespace(const Decl *D) {
+ const DeclContext *DC = D->getDeclContext();
+ const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext());
+ if (!ND)
+ return false;
+ const IdentifierInfo *II = ND->getIdentifier();
+ if (!II || II->getName() != "std")
+ return false;
+ DC = ND->getDeclContext();
+ return isa<TranslationUnitDecl>(DC);
+}
+
+static bool IsStdString(QualType T) {
+ if (const QualifiedNameType *QT = T->getAs<QualifiedNameType>())
+ T = QT->getNamedType();
+
+ const TypedefType *TT = T->getAs<TypedefType>();
+ if (!TT)
+ return false;
+
+ const TypedefDecl *TD = TT->getDecl();
+
+ if (!InStdNamespace(TD))
+ return false;
+
+ return TD->getName() == "string";
+}
+
+static bool InClangNamespace(const Decl *D) {
+ const DeclContext *DC = D->getDeclContext();
+ const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext());
+ if (!ND)
+ return false;
+ const IdentifierInfo *II = ND->getIdentifier();
+ if (!II || II->getName() != "clang")
+ return false;
+ DC = ND->getDeclContext();
+ return isa<TranslationUnitDecl>(DC);
+}
+
+static bool InLLVMNamespace(const Decl *D) {
+ const DeclContext *DC = D->getDeclContext();
+ const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext());
+ if (!ND)
+ return false;
+ const IdentifierInfo *II = ND->getIdentifier();
+ if (!II || II->getName() != "llvm")
+ return false;
+ DC = ND->getDeclContext();
+ return isa<TranslationUnitDecl>(DC);
+}
+
+static bool IsClangType(const RecordDecl *RD) {
+ return RD->getName() == "Type" && InClangNamespace(RD);
+}
+
+static bool IsClangDecl(const RecordDecl *RD) {
+ return RD->getName() == "Decl" && InClangNamespace(RD);
+}
+
+static bool IsClangStmt(const RecordDecl *RD) {
+ return RD->getName() == "Stmt" && InClangNamespace(RD);
+}
+
+static bool isClangAttr(const RecordDecl *RD) {
+ return RD->getName() == "Attr" && InClangNamespace(RD);
+}
+
+static bool IsStdVector(QualType T) {
+ const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
+ if (!TS)
+ return false;
+
+ TemplateName TM = TS->getTemplateName();
+ TemplateDecl *TD = TM.getAsTemplateDecl();
+
+ if (!TD || !InStdNamespace(TD))
+ return false;
+
+ return TD->getName() == "vector";
+}
+
+static bool IsSmallVector(QualType T) {
+ const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
+ if (!TS)
+ return false;
+
+ TemplateName TM = TS->getTemplateName();
+ TemplateDecl *TD = TM.getAsTemplateDecl();
+
+ if (!TD || !InLLVMNamespace(TD))
+ return false;
+
+ return TD->getName() == "SmallVector";
+}
+
+//===----------------------------------------------------------------------===//
+// CHECK: a llvm::StringRef should not be bound to a temporary std::string whose
+// lifetime is shorter than the StringRef's.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> {
+ BugReporter &BR;
+public:
+ StringRefCheckerVisitor(BugReporter &br) : BR(br) {}
+ void VisitChildren(Stmt *S) {
+ for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ;
+ I != E; ++I)
+ if (Stmt *child = *I)
+ Visit(child);
+ }
+ void VisitStmt(Stmt *S) { VisitChildren(S); }
+ void VisitDeclStmt(DeclStmt *DS);
+private:
+ void VisitVarDecl(VarDecl *VD);
+ void CheckStringRefBoundtoTemporaryString(VarDecl *VD);
+};
+} // end anonymous namespace
+
+static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR) {
+ StringRefCheckerVisitor walker(BR);
+ walker.Visit(D->getBody());
+}
+
+void StringRefCheckerVisitor::VisitDeclStmt(DeclStmt *S) {
+ VisitChildren(S);
+
+ for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end();I!=E; ++I)
+ if (VarDecl *VD = dyn_cast<VarDecl>(*I))
+ VisitVarDecl(VD);
+}
+
+void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) {
+ Expr *Init = VD->getInit();
+ if (!Init)
+ return;
+
+ // Pattern match for:
+ // llvm::StringRef x = call() (where call returns std::string)
+ if (!IsLLVMStringRef(VD->getType()))
+ return;
+ CXXExprWithTemporaries *Ex1 = dyn_cast<CXXExprWithTemporaries>(Init);
+ if (!Ex1)
+ return;
+ CXXConstructExpr *Ex2 = dyn_cast<CXXConstructExpr>(Ex1->getSubExpr());
+ if (!Ex2 || Ex2->getNumArgs() != 1)
+ return;
+ ImplicitCastExpr *Ex3 = dyn_cast<ImplicitCastExpr>(Ex2->getArg(0));
+ if (!Ex3)
+ return;
+ CXXConstructExpr *Ex4 = dyn_cast<CXXConstructExpr>(Ex3->getSubExpr());
+ if (!Ex4 || Ex4->getNumArgs() != 1)
+ return;
+ ImplicitCastExpr *Ex5 = dyn_cast<ImplicitCastExpr>(Ex4->getArg(0));
+ if (!Ex5)
+ return;
+ CXXBindTemporaryExpr *Ex6 = dyn_cast<CXXBindTemporaryExpr>(Ex5->getSubExpr());
+ if (!Ex6 || !IsStdString(Ex6->getType()))
+ return;
+
+ // Okay, badness! Report an error.
+ const char *desc = "StringRef should not be bound to temporary "
+ "std::string that it outlives";
+
+ BR.EmitBasicReport(desc, "LLVM Conventions", desc,
+ VD->getLocStart(), Init->getSourceRange());
+}
+
+//===----------------------------------------------------------------------===//
+// CHECK: Clang AST nodes should not have fields that can allocate
+// memory.
+//===----------------------------------------------------------------------===//
+
+static bool AllocatesMemory(QualType T) {
+ return IsStdVector(T) || IsStdString(T) || IsSmallVector(T);
+}
+
+// This type checking could be sped up via dynamic programming.
+static bool IsPartOfAST(const CXXRecordDecl *R) {
+ if (IsClangStmt(R) || IsClangType(R) || IsClangDecl(R) || isClangAttr(R))
+ return true;
+
+ for (CXXRecordDecl::base_class_const_iterator I = R->bases_begin(),
+ E = R->bases_end(); I!=E; ++I) {
+ CXXBaseSpecifier BS = *I;
+ QualType T = BS.getType();
+ if (const RecordType *baseT = T->getAs<RecordType>()) {
+ CXXRecordDecl *baseD = cast<CXXRecordDecl>(baseT->getDecl());
+ if (IsPartOfAST(baseD))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+namespace {
+class ASTFieldVisitor {
+ llvm::SmallVector<FieldDecl*, 10> FieldChain;
+ CXXRecordDecl *Root;
+ BugReporter &BR;
+public:
+ ASTFieldVisitor(CXXRecordDecl *root, BugReporter &br)
+ : Root(root), BR(br) {}
+
+ void Visit(FieldDecl *D);
+ void ReportError(QualType T);
+};
+} // end anonymous namespace
+
+static void CheckASTMemory(CXXRecordDecl *R, BugReporter &BR) {
+ if (!IsPartOfAST(R))
+ return;
+
+ for (RecordDecl::field_iterator I = R->field_begin(), E = R->field_end();
+ I != E; ++I) {
+ ASTFieldVisitor walker(R, BR);
+ walker.Visit(*I);
+ }
+}
+
+void ASTFieldVisitor::Visit(FieldDecl *D) {
+ FieldChain.push_back(D);
+
+ QualType T = D->getType();
+
+ if (AllocatesMemory(T))
+ ReportError(T);
+
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ const RecordDecl *RD = RT->getDecl()->getDefinition();
+ for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ I != E; ++I)
+ Visit(*I);
+ }
+
+ FieldChain.pop_back();
+}
+
+void ASTFieldVisitor::ReportError(QualType T) {
+ llvm::SmallString<1024> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ os << "AST class '" << Root->getName() << "' has a field '"
+ << FieldChain.front()->getName() << "' that allocates heap memory";
+ if (FieldChain.size() > 1) {
+ os << " via the following chain: ";
+ bool isFirst = true;
+ for (llvm::SmallVectorImpl<FieldDecl*>::iterator I=FieldChain.begin(),
+ E=FieldChain.end(); I!=E; ++I) {
+ if (!isFirst)
+ os << '.';
+ else
+ isFirst = false;
+ os << (*I)->getName();
+ }
+ }
+ os << " (type " << FieldChain.back()->getType().getAsString() << ")";
+ os.flush();
+
+ // Note that this will fire for every translation unit that uses this
+ // class. This is suboptimal, but at least scan-build will merge
+ // duplicate HTML reports. In the future we need a unified way of merging
+ // duplicate reports across translation units. For C++ classes we cannot
+ // just report warnings when we see an out-of-line method definition for a
+ // class, as that heuristic doesn't always work (the complete definition of
+ // the class may be in the header file, for example).
+ BR.EmitBasicReport("AST node allocates heap memory", "LLVM Conventions",
+ os.str(), FieldChain.front()->getLocStart());
+}
+
+//===----------------------------------------------------------------------===//
+// Entry point for all checks.
+//===----------------------------------------------------------------------===//
+
+static void ScanCodeDecls(DeclContext *DC, BugReporter &BR) {
+ for (DeclContext::decl_iterator I=DC->decls_begin(), E=DC->decls_end();
+ I!=E ; ++I) {
+
+ Decl *D = *I;
+
+ if (D->getBody())
+ CheckStringRefAssignedTemporary(D, BR);
+
+ if (CXXRecordDecl *R = dyn_cast<CXXRecordDecl>(D))
+ if (R->isDefinition())
+ CheckASTMemory(R, BR);
+
+ if (DeclContext *DC_child = dyn_cast<DeclContext>(D))
+ ScanCodeDecls(DC_child, BR);
+ }
+}
+
+void clang::CheckLLVMConventions(TranslationUnitDecl &TU,
+ BugReporter &BR) {
+ ScanCodeDecls(&TU, BR);
+}
+
diff --git a/lib/Checker/Makefile b/lib/Checker/Makefile
new file mode 100644
index 000000000000..673d152270ca
--- /dev/null
+++ b/lib/Checker/Makefile
@@ -0,0 +1,21 @@
+##===- clang/lib/Checker/Makefile --------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This implements analyses built on top of source-level CFGs.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+LIBRARYNAME := clangChecker
+BUILD_ARCHIVE = 1
+
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+
+include $(LEVEL)/Makefile.common
+
diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Checker/MallocChecker.cpp
index 28f4db788068..4ff98642e1c2 100644
--- a/lib/Analysis/MallocChecker.cpp
+++ b/lib/Checker/MallocChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#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 "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/PathSensitive/SymbolManager.h"
#include "llvm/ADT/ImmutableMap.h"
using namespace clang;
@@ -172,6 +172,11 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
const GRState *state) {
SVal ArgVal = state->getSVal(CE->getArg(0));
+
+ // If ptr is NULL, no operation is preformed.
+ if (ArgVal.isZeroConstant())
+ return state;
+
SymbolRef Sym = ArgVal.getAsLocSymbol();
assert(Sym);
diff --git a/lib/Analysis/ManagerRegistry.cpp b/lib/Checker/ManagerRegistry.cpp
index 8943db2a2343..d11a997cc0f6 100644
--- a/lib/Analysis/ManagerRegistry.cpp
+++ b/lib/Checker/ManagerRegistry.cpp
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/ManagerRegistry.h"
+#include "clang/Checker/ManagerRegistry.h"
using namespace clang;
diff --git a/lib/Analysis/MemRegion.cpp b/lib/Checker/MemRegion.cpp
index 87d60d340934..194015a11b11 100644
--- a/lib/Analysis/MemRegion.cpp
+++ b/lib/Checker/MemRegion.cpp
@@ -13,12 +13,11 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/raw_ostream.h"
-#include "clang/Analysis/PathSensitive/MemRegion.h"
-#include "clang/Analysis/PathSensitive/ValueManager.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Checker/PathSensitive/MemRegion.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/StmtVisitor.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -682,7 +681,7 @@ const MemRegion *MemRegion::StripCasts() const {
static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
const RecordDecl *D = RT->getDecl();
- if (!D->getDefinition(Ctx))
+ if (!D->getDefinition())
return false;
}
@@ -760,7 +759,7 @@ void BlockDataRegion::LazyInitializeReferencedVars() {
const VarDecl *VD = *I;
const VarRegion *VR = 0;
- if (!VD->getAttr<BlocksAttr>())
+ if (!VD->getAttr<BlocksAttr>() && VD->hasLocalStorage())
VR = MemMgr.getVarRegion(VD, this);
else {
if (LC)
diff --git a/lib/Analysis/NSAutoreleasePoolChecker.cpp b/lib/Checker/NSAutoreleasePoolChecker.cpp
index 2ff04878f7ab..29bac9c384c2 100644
--- a/lib/Analysis/NSAutoreleasePoolChecker.cpp
+++ b/lib/Checker/NSAutoreleasePoolChecker.cpp
@@ -15,9 +15,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "BasicObjCFoundationChecks.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Decl.h"
diff --git a/lib/Analysis/NSErrorChecker.cpp b/lib/Checker/NSErrorChecker.cpp
index e3cf57fd0c1b..e428e2e83f2a 100644
--- a/lib/Analysis/NSErrorChecker.cpp
+++ b/lib/Checker/NSErrorChecker.cpp
@@ -15,10 +15,10 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/LocalCheckers.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/Checkers/DereferenceChecker.h"
#include "BasicObjCFoundationChecks.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Decl.h"
diff --git a/lib/Analysis/NoReturnFunctionChecker.cpp b/lib/Checker/NoReturnFunctionChecker.cpp
index 5cfd9acd5f56..1455d87665db 100644
--- a/lib/Analysis/NoReturnFunctionChecker.cpp
+++ b/lib/Checker/NoReturnFunctionChecker.cpp
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/Checker.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
diff --git a/lib/Analysis/OSAtomicChecker.cpp b/lib/Checker/OSAtomicChecker.cpp
index 9d34e9ec5c8b..7f4aeca33178 100644
--- a/lib/Analysis/OSAtomicChecker.cpp
+++ b/lib/Checker/OSAtomicChecker.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/Checker.h"
#include "clang/Basic/Builtins.h"
#include "llvm/ADT/StringSwitch.h"
@@ -153,8 +153,7 @@ bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C,
// Handle implicit value casts.
if (const TypedRegion *R =
dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
- llvm::tie(state, val) = SVator.EvalCast(val, state,R->getValueType(Ctx),
- newValueExpr->getType());
+ val = SVator.EvalCast(val,R->getValueType(Ctx),newValueExpr->getType());
}
Engine.EvalStore(TmpStore, NULL, const_cast<Expr *>(theValueExpr), N,
diff --git a/lib/Analysis/PathDiagnostic.cpp b/lib/Checker/PathDiagnostic.cpp
index 734570a21e64..97500d95785c 100644
--- a/lib/Analysis/PathDiagnostic.cpp
+++ b/lib/Checker/PathDiagnostic.cpp
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
diff --git a/lib/Analysis/PointerArithChecker.cpp b/lib/Checker/PointerArithChecker.cpp
index 370233ce38bd..3d62d0c7b9d7 100644
--- a/lib/Analysis/PointerArithChecker.cpp
+++ b/lib/Checker/PointerArithChecker.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Analysis/PointerSubChecker.cpp b/lib/Checker/PointerSubChecker.cpp
index c597a2580751..acc848ac8edb 100644
--- a/lib/Analysis/PointerSubChecker.cpp
+++ b/lib/Checker/PointerSubChecker.cpp
@@ -13,7 +13,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Analysis/PthreadLockChecker.cpp b/lib/Checker/PthreadLockChecker.cpp
index e95095c7975e..74e266c3edfc 100644
--- a/lib/Analysis/PthreadLockChecker.cpp
+++ b/lib/Checker/PthreadLockChecker.cpp
@@ -12,9 +12,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
#include "GRExprEngineExperimentalChecks.h"
#include "llvm/ADT/ImmutableSet.h"
diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Checker/RangeConstraintManager.cpp
index 2cf3dfb6d0db..c904c33e08d2 100644
--- a/lib/Analysis/RangeConstraintManager.cpp
+++ b/lib/Checker/RangeConstraintManager.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "SimpleConstraintManager.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/GRStateTrait.h"
-#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
-#include "clang/Analysis/ManagerRegistry.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
+#include "clang/Checker/ManagerRegistry.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableSet.h"
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Checker/RegionStore.cpp
index a735ed94578e..f70105af1379 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Checker/RegionStore.cpp
@@ -14,10 +14,10 @@
// parameters are created lazily.
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/MemRegion.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/PathSensitive/MemRegion.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/Support/Optional.h"
#include "clang/Basic/TargetInfo.h"
@@ -32,81 +32,55 @@ using namespace clang;
#define USE_EXPLICIT_COMPOUND 0
//===----------------------------------------------------------------------===//
-// Representation of value bindings.
+// Representation of binding keys.
//===----------------------------------------------------------------------===//
namespace {
-class BindingVal {
+class BindingKey {
public:
- enum BindingKind { Direct, Default };
+ enum Kind { Direct = 0x0, Default = 0x1 };
private:
- SVal Value;
- BindingKind Kind;
-
+ llvm ::PointerIntPair<const MemRegion*, 1> P;
+ uint64_t Offset;
+
+ explicit BindingKey(const MemRegion *r, uint64_t offset, Kind k)
+ : P(r, (unsigned) k), Offset(offset) { assert(r); }
public:
- BindingVal(SVal V, BindingKind K) : Value(V), Kind(K) {}
-
- bool isDefault() const { return Kind == Default; }
-
- const SVal *getValue() const { return &Value; }
-
- const SVal *getDirectValue() const { return isDefault() ? 0 : &Value; }
-
- const SVal *getDefaultValue() const { return isDefault() ? &Value : 0; }
-
+
+ bool isDefault() const { return P.getInt() == Default; }
+ bool isDirect() const { return P.getInt() == Direct; }
+
+ const MemRegion *getRegion() const { return P.getPointer(); }
+ uint64_t getOffset() const { return Offset; }
+
void Profile(llvm::FoldingSetNodeID& ID) const {
- Value.Profile(ID);
- ID.AddInteger(Kind);
+ ID.AddPointer(P.getOpaqueValue());
+ ID.AddInteger(Offset);
}
-
- inline bool operator==(const BindingVal& R) const {
- return Value == R.Value && Kind == R.Kind;
- }
-
- inline bool operator!=(const BindingVal& R) const {
- return !(*this == R);
- }
-};
-}
-
-namespace llvm {
-static inline
-llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingVal V) {
- if (V.isDefault())
- os << "(default) ";
- else
- os << "(direct) ";
- os << *V.getValue();
- return os;
-}
-} // end llvm namespace
-
-//===----------------------------------------------------------------------===//
-// Representation of binding keys.
-//===----------------------------------------------------------------------===//
-
-namespace {
- class BindingKey : public std::pair<const MemRegion*, uint64_t> {
-public:
- explicit BindingKey(const MemRegion *r, uint64_t offset)
- : std::pair<const MemRegion*,uint64_t>(r, offset) { assert(r); }
- const MemRegion *getRegion() const { return first; }
- uint64_t getOffset() const { return second; }
+ static BindingKey Make(const MemRegion *R, Kind k);
- void Profile(llvm::FoldingSetNodeID& ID) const {
- ID.AddPointer(getRegion());
- ID.AddInteger(getOffset());
+ bool operator<(const BindingKey &X) const {
+ if (P.getOpaqueValue() < X.P.getOpaqueValue())
+ return true;
+ if (P.getOpaqueValue() > X.P.getOpaqueValue())
+ return false;
+ return Offset < X.Offset;
+ }
+
+ bool operator==(const BindingKey &X) const {
+ return P.getOpaqueValue() == X.P.getOpaqueValue() &&
+ Offset == X.Offset;
}
-
- static BindingKey Make(const MemRegion *R);
};
} // end anonymous namespace
namespace llvm {
static inline
llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingKey K) {
- os << '(' << K.getRegion() << ',' << K.getOffset() << ')';
+ os << '(' << K.getRegion() << ',' << K.getOffset()
+ << ',' << (K.isDirect() ? "direct" : "default")
+ << ')';
return os;
}
} // end llvm namespace
@@ -115,7 +89,7 @@ namespace llvm {
// Actual Store type.
//===----------------------------------------------------------------------===//
-typedef llvm::ImmutableMap<BindingKey, BindingVal> RegionBindings;
+typedef llvm::ImmutableMap<BindingKey, SVal> RegionBindings;
//===----------------------------------------------------------------------===//
// Fine-grained control of RegionStoreManager.
@@ -178,9 +152,11 @@ static bool IsAnyPointerOrIntptr(QualType ty, ASTContext &Ctx) {
namespace {
class RegionStoreSubRegionMap : public SubRegionMap {
- typedef llvm::ImmutableSet<const MemRegion*> SetTy;
- typedef llvm::DenseMap<const MemRegion*, SetTy> Map;
- SetTy::Factory F;
+public:
+ typedef llvm::ImmutableSet<const MemRegion*> Set;
+ typedef llvm::DenseMap<const MemRegion*, Set> Map;
+private:
+ Set::Factory F;
Map M;
public:
bool add(const MemRegion* Parent, const MemRegion* SubRegion) {
@@ -198,6 +174,11 @@ public:
void process(llvm::SmallVectorImpl<const SubRegion*> &WL, const SubRegion *R);
~RegionStoreSubRegionMap() {}
+
+ const Set *getSubRegions(const MemRegion *Parent) const {
+ Map::const_iterator I = M.find(Parent);
+ return I == M.end() ? NULL : &I->second;
+ }
bool iterSubRegions(const MemRegion* Parent, Visitor& V) const {
Map::const_iterator I = M.find(Parent);
@@ -205,30 +186,22 @@ public:
if (I == M.end())
return true;
- llvm::ImmutableSet<const MemRegion*> S = I->second;
- for (llvm::ImmutableSet<const MemRegion*>::iterator SI=S.begin(),SE=S.end();
- SI != SE; ++SI) {
+ Set S = I->second;
+ for (Set::iterator SI=S.begin(),SE=S.end(); SI != SE; ++SI) {
if (!V.Visit(Parent, *SI))
return false;
}
return true;
}
-
- typedef SetTy::iterator iterator;
-
- std::pair<iterator, iterator> begin_end(const MemRegion *R) {
- Map::iterator I = M.find(R);
- SetTy S = I == M.end() ? F.GetEmptySet() : I->second;
- return std::make_pair(S.begin(), S.end());
- }
};
+
class RegionStoreManager : public StoreManager {
const RegionStoreFeatures Features;
RegionBindings::Factory RBFactory;
- typedef llvm::DenseMap<const GRState *, RegionStoreSubRegionMap*> SMCache;
+ typedef llvm::DenseMap<Store, RegionStoreSubRegionMap*> SMCache;
SMCache SC;
public:
@@ -242,7 +215,9 @@ public:
delete (*I).second;
}
- SubRegionMap *getSubRegionMap(const GRState *state);
+ SubRegionMap *getSubRegionMap(Store store) {
+ return getRegionStoreSubRegionMap(store);
+ }
RegionStoreSubRegionMap *getRegionStoreSubRegionMap(Store store);
@@ -255,35 +230,7 @@ public:
/// setImplicitDefaultValue - Set the default binding for the provided
/// MemRegion to the value implicitly defined for compound literals when
/// the value is not specified.
- const GRState *setImplicitDefaultValue(const GRState *state,
- const MemRegion *R,
- QualType T);
-
- /// getLValueString - Returns an SVal representing the lvalue of a
- /// StringLiteral. Within RegionStore a StringLiteral has an
- /// associated StringRegion, and the lvalue of a StringLiteral is
- /// the lvalue of that region.
- SVal getLValueString(const StringLiteral* S);
-
- /// getLValueCompoundLiteral - Returns an SVal representing the
- /// lvalue of a compound literal. Within RegionStore a compound
- /// literal has an associated region, and the lvalue of the
- /// compound literal is the lvalue of that region.
- SVal getLValueCompoundLiteral(const CompoundLiteralExpr*);
-
- /// getLValueVar - Returns an SVal that represents the lvalue of a
- /// variable. Within RegionStore a variable has an associated
- /// VarRegion, and the lvalue of the variable is the lvalue of that region.
- SVal getLValueVar(const VarDecl *VD, const LocationContext *LC);
-
- SVal getLValueIvar(const ObjCIvarDecl* D, SVal Base);
-
- SVal getLValueField(const FieldDecl* D, SVal Base);
-
- SVal getLValueFieldOrIvar(const Decl* D, SVal Base);
-
- SVal getLValueElement(QualType elementType, SVal Offset, SVal Base);
-
+ Store setImplicitDefaultValue(Store store, const MemRegion *R, QualType T);
/// ArrayToPointer - Emulates the "decay" of an array to a pointer
/// type. 'Array' represents the lvalue of the array being decayed
@@ -293,8 +240,7 @@ public:
/// casts from arrays to pointers.
SVal ArrayToPointer(Loc Array);
- SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op,Loc L,
- NonLoc R, QualType resultTy);
+ SVal EvalBinOp(BinaryOperator::Opcode Op,Loc L, NonLoc R, QualType resultTy);
Store getInitialStore(const LocationContext *InitLoc) {
return RBFactory.GetEmptyMap().getRoot();
@@ -304,52 +250,57 @@ public:
// Binding values to regions.
//===-------------------------------------------------------------------===//
- const GRState *InvalidateRegion(const GRState *state, const MemRegion *R,
- const Expr *E, unsigned Count,
- InvalidatedSymbols *IS) {
- return RegionStoreManager::InvalidateRegions(state, &R, &R+1, E, Count, IS);
+ Store InvalidateRegion(Store store, const MemRegion *R, const Expr *E,
+ unsigned Count, InvalidatedSymbols *IS) {
+ return RegionStoreManager::InvalidateRegions(store, &R, &R+1, E, Count, IS);
}
- const GRState *InvalidateRegions(const GRState *state,
- const MemRegion * const *Begin,
- const MemRegion * const *End,
- const Expr *E, unsigned Count,
- InvalidatedSymbols *IS);
+ Store InvalidateRegions(Store store,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End,
+ const Expr *E, unsigned Count,
+ InvalidatedSymbols *IS);
-private:
+public: // Made public for helper classes.
+
void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R,
RegionStoreSubRegionMap &M);
- RegionBindings Add(RegionBindings B, BindingKey K, BindingVal V);
- RegionBindings Add(RegionBindings B, const MemRegion *R, BindingVal V);
+ RegionBindings Add(RegionBindings B, BindingKey K, SVal V);
+
+ RegionBindings Add(RegionBindings B, const MemRegion *R,
+ BindingKey::Kind k, SVal V);
- const BindingVal *Lookup(RegionBindings B, BindingKey K);
- const BindingVal *Lookup(RegionBindings B, const MemRegion *R);
+ const SVal *Lookup(RegionBindings B, BindingKey K);
+ const SVal *Lookup(RegionBindings B, const MemRegion *R, BindingKey::Kind k);
RegionBindings Remove(RegionBindings B, BindingKey K);
- RegionBindings Remove(RegionBindings B, const MemRegion *R);
+ RegionBindings Remove(RegionBindings B, const MemRegion *R,
+ BindingKey::Kind k);
+
+ RegionBindings Remove(RegionBindings B, const MemRegion *R) {
+ return Remove(Remove(B, R, BindingKey::Direct), R, BindingKey::Default);
+ }
+
Store Remove(Store store, BindingKey K);
-public:
- const GRState *Bind(const GRState *state, Loc LV, SVal V);
+public: // Part of public interface to class.
- const GRState *BindCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr* CL,
- const LocationContext *LC,
- SVal V);
+ Store Bind(Store store, Loc LV, SVal V);
- const GRState *BindDecl(const GRState *ST, const VarRegion *VR,
- SVal InitVal);
+ Store BindCompoundLiteral(Store store, const CompoundLiteralExpr* CL,
+ const LocationContext *LC, SVal V);
- const GRState *BindDeclWithNoInit(const GRState *state,
- const VarRegion *) {
- return state;
+ Store BindDecl(Store store, const VarRegion *VR, SVal InitVal);
+
+ Store BindDeclWithNoInit(Store store, const VarRegion *) {
+ return store;
}
/// BindStruct - Bind a compound value to a structure.
- const GRState *BindStruct(const GRState *, const TypedRegion* R, SVal V);
+ Store BindStruct(Store store, const TypedRegion* R, SVal V);
- const GRState *BindArray(const GRState *state, const TypedRegion* R, SVal V);
+ Store BindArray(Store store, const TypedRegion* R, SVal V);
/// KillStruct - Set the entire struct to unknown.
Store KillStruct(Store store, const TypedRegion* R);
@@ -372,20 +323,19 @@ public:
/// return undefined
/// else
/// return symbolic
- SValuator::CastResult Retrieve(const GRState *state, Loc L,
- QualType T = QualType());
+ SVal Retrieve(Store store, Loc L, QualType T = QualType());
- SVal RetrieveElement(const GRState *state, const ElementRegion *R);
+ SVal RetrieveElement(Store store, const ElementRegion *R);
- SVal RetrieveField(const GRState *state, const FieldRegion *R);
+ SVal RetrieveField(Store store, const FieldRegion *R);
- SVal RetrieveObjCIvar(const GRState *state, const ObjCIvarRegion *R);
+ SVal RetrieveObjCIvar(Store store, const ObjCIvarRegion *R);
- SVal RetrieveVar(const GRState *state, const VarRegion *R);
+ SVal RetrieveVar(Store store, const VarRegion *R);
- SVal RetrieveLazySymbol(const GRState *state, const TypedRegion *R);
+ SVal RetrieveLazySymbol(const TypedRegion *R);
- SVal RetrieveFieldOrElementCommon(const GRState *state, const TypedRegion *R,
+ SVal RetrieveFieldOrElementCommon(Store store, const TypedRegion *R,
QualType Ty, const MemRegion *superR);
/// Retrieve the values in a struct and return a CompoundVal, used when doing
@@ -393,20 +343,18 @@ public:
/// struct s x, y;
/// x = y;
/// y's value is retrieved by this method.
- SVal RetrieveStruct(const GRState *St, const TypedRegion* R);
+ SVal RetrieveStruct(Store store, const TypedRegion* R);
- SVal RetrieveArray(const GRState *St, const TypedRegion* R);
+ SVal RetrieveArray(Store store, const TypedRegion* R);
/// Get the state and region whose binding this region R corresponds to.
- std::pair<const GRState*, const MemRegion*>
+ std::pair<Store, const MemRegion*>
GetLazyBinding(RegionBindings B, const MemRegion *R);
- const GRState* CopyLazyBindings(nonloc::LazyCompoundVal V,
- const GRState *state,
- const TypedRegion *R);
+ Store CopyLazyBindings(nonloc::LazyCompoundVal V, Store store,
+ const TypedRegion *R);
- const ElementRegion *GetElementZeroRegion(const SymbolicRegion *SR,
- QualType T);
+ const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T);
//===------------------------------------------------------------------===//
// State pruning.
@@ -414,7 +362,7 @@ public:
/// RemoveDeadBindings - Scans the RegionStore of 'state' for dead values.
/// It returns a new Store with these values removed.
- void RemoveDeadBindings(GRState &state, Stmt* Loc, SymbolReaper& SymReaper,
+ Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
const GRState *EnterStackFrame(const GRState *state,
@@ -500,10 +448,6 @@ RegionStoreManager::getRegionStoreSubRegionMap(Store store) {
return M;
}
-SubRegionMap *RegionStoreManager::getSubRegionMap(const GRState *state) {
- return getRegionStoreSubRegionMap(state->getStore());
-}
-
//===----------------------------------------------------------------------===//
// Binding invalidation.
//===----------------------------------------------------------------------===//
@@ -511,258 +455,227 @@ SubRegionMap *RegionStoreManager::getSubRegionMap(const GRState *state) {
void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B,
const MemRegion *R,
RegionStoreSubRegionMap &M) {
- RegionStoreSubRegionMap::iterator I, E;
-
- for (llvm::tie(I, E) = M.begin_end(R); I != E; ++I)
- RemoveSubRegionBindings(B, *I, M);
+
+ if (const RegionStoreSubRegionMap::Set *S = M.getSubRegions(R))
+ for (RegionStoreSubRegionMap::Set::iterator I = S->begin(), E = S->end();
+ I != E; ++I)
+ RemoveSubRegionBindings(B, *I, M);
B = Remove(B, R);
}
-const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
- const MemRegion * const *I,
- const MemRegion * const *E,
- const Expr *Ex,
- unsigned Count,
- InvalidatedSymbols *IS) {
- ASTContext& Ctx = StateMgr.getContext();
-
- // Get the mapping of regions -> subregions.
- llvm::OwningPtr<RegionStoreSubRegionMap>
- SubRegions(getRegionStoreSubRegionMap(state->getStore()));
+namespace {
+class InvalidateRegionsWorker {
+ typedef BumpVector<BindingKey> RegionCluster;
+ typedef llvm::DenseMap<const MemRegion *, RegionCluster *> ClusterMap;
+ typedef llvm::SmallVector<std::pair<const MemRegion *,RegionCluster*>, 10>
+ WorkList;
+
+ BumpVectorContext BVC;
+ ClusterMap ClusterM;
+ WorkList WL;
- RegionBindings B = GetRegionBindings(state->getStore());
-
- llvm::DenseMap<const MemRegion *, unsigned> Visited;
- llvm::SmallVector<const MemRegion *, 10> WorkList;
+ RegionStoreManager &RM;
+ StoreManager::InvalidatedSymbols *IS;
+ ASTContext &Ctx;
+ ValueManager &ValMgr;
- for ( ; I != E; ++I) {
- // Strip away casts.
- WorkList.push_back((*I)->StripCasts());
+public:
+ InvalidateRegionsWorker(RegionStoreManager &rm,
+ StoreManager::InvalidatedSymbols *is,
+ ASTContext &ctx, ValueManager &valMgr)
+ : RM(rm), IS(is), Ctx(ctx), ValMgr(valMgr) {}
+
+ Store InvalidateRegions(Store store, const MemRegion * const *I,
+ const MemRegion * const *E,
+ const Expr *Ex, unsigned Count);
+
+private:
+ void AddToWorkList(BindingKey K);
+ void AddToWorkList(const MemRegion *R);
+ void AddToCluster(BindingKey K);
+ RegionCluster **getCluster(const MemRegion *R);
+ void VisitBinding(SVal V);
+};
+}
+
+void InvalidateRegionsWorker::AddToCluster(BindingKey K) {
+ const MemRegion *R = K.getRegion();
+ const MemRegion *baseR = R->getBaseRegion();
+ RegionCluster **CPtr = getCluster(baseR);
+ assert(*CPtr);
+ (*CPtr)->push_back(K, BVC);
+}
+
+void InvalidateRegionsWorker::AddToWorkList(BindingKey K) {
+ AddToWorkList(K.getRegion());
+}
+
+void InvalidateRegionsWorker::AddToWorkList(const MemRegion *R) {
+ const MemRegion *baseR = R->getBaseRegion();
+ RegionCluster **CPtr = getCluster(baseR);
+ if (RegionCluster *C = *CPtr) {
+ WL.push_back(std::make_pair(baseR, C));
+ *CPtr = NULL;
+ }
+}
+
+InvalidateRegionsWorker::RegionCluster **
+InvalidateRegionsWorker::getCluster(const MemRegion *R) {
+ RegionCluster *&CRef = ClusterM[R];
+ if (!CRef) {
+ void *Mem = BVC.getAllocator().Allocate<RegionCluster>();
+ CRef = new (Mem) RegionCluster(BVC, 10);
}
+ return &CRef;
+}
+
+void InvalidateRegionsWorker::VisitBinding(SVal V) {
+ // A symbol? Mark it touched by the invalidation.
+ if (IS)
+ if (SymbolRef Sym = V.getAsSymbol())
+ IS->insert(Sym);
- while (!WorkList.empty()) {
- const MemRegion *R = WorkList.back();
- WorkList.pop_back();
-
- // Have we visited this region before?
- unsigned &visited = Visited[R];
- if (visited)
- continue;
- visited = 1;
+ if (const MemRegion *R = V.getAsRegion()) {
+ AddToWorkList(R);
+ return;
+ }
+
+ // Is it a LazyCompoundVal? All references get invalidated as well.
+ if (const nonloc::LazyCompoundVal *LCS =
+ dyn_cast<nonloc::LazyCompoundVal>(&V)) {
+
+ const MemRegion *LazyR = LCS->getRegion();
+ RegionBindings B = RegionStoreManager::GetRegionBindings(LCS->getStore());
+
+ for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI){
+ const MemRegion *baseR = RI.getKey().getRegion();
+ if (cast<SubRegion>(baseR)->isSubRegionOf(LazyR))
+ VisitBinding(RI.getData());
+ }
- // Add subregions to work list.
- RegionStoreSubRegionMap::iterator I, E;
- for (llvm::tie(I, E) = SubRegions->begin_end(R); I!=E; ++I)
- WorkList.push_back(*I);
+ return;
+ }
+}
- // Get the old binding. Is it a region? If so, add it to the worklist.
- if (Optional<SVal> V = getDirectBinding(B, R)) {
- if (const MemRegion *RV = V->getAsRegion())
- WorkList.push_back(RV);
+Store InvalidateRegionsWorker::InvalidateRegions(Store store,
+ const MemRegion * const *I,
+ const MemRegion * const *E,
+ const Expr *Ex, unsigned Count)
+{
+ RegionBindings B = RegionStoreManager::GetRegionBindings(store);
+
+ // Scan the entire store and make the region clusters.
+ for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI) {
+ AddToCluster(RI.getKey());
+ if (const MemRegion *R = RI.getData().getAsRegion()) {
+ // Generate a cluster, but don't add the region to the cluster
+ // if there aren't any bindings.
+ getCluster(R->getBaseRegion());
+ }
+ }
+
+ // Add the cluster for I .. E to a worklist.
+ for ( ; I != E; ++I)
+ AddToWorkList(*I);
+
+ while (!WL.empty()) {
+ const MemRegion *baseR;
+ RegionCluster *C;
+ llvm::tie(baseR, C) = WL.back();
+ WL.pop_back();
+
+ for (RegionCluster::iterator I = C->begin(), E = C->end(); I != E; ++I) {
+ BindingKey K = *I;
- // A symbol? Mark it touched by the invalidation.
- if (IS) {
- if (SymbolRef Sym = V->getAsSymbol())
- IS->insert(Sym);
- }
+ // Get the old binding. Is it a region? If so, add it to the worklist.
+ if (const SVal *V = RM.Lookup(B, K))
+ VisitBinding(*V);
+
+ B = RM.Remove(B, K);
}
+
+ // Now inspect the base region.
- // Symbolic region? Mark that symbol touched by the invalidation.
if (IS) {
- if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
+ // Symbolic region? Mark that symbol touched by the invalidation.
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
IS->insert(SR->getSymbol());
}
// BlockDataRegion? If so, invalidate captured variables that are passed
// by reference.
- if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
+ if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(baseR)) {
for (BlockDataRegion::referenced_vars_iterator
- I = BR->referenced_vars_begin(), E = BR->referenced_vars_end() ;
- I != E; ++I) {
- const VarRegion *VR = *I;
- if (VR->getDecl()->getAttr<BlocksAttr>())
- WorkList.push_back(VR);
+ BI = BR->referenced_vars_begin(), BE = BR->referenced_vars_end() ;
+ BI != BE; ++BI) {
+ const VarRegion *VR = *BI;
+ const VarDecl *VD = VR->getDecl();
+ if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage())
+ AddToWorkList(VR);
}
continue;
}
-
- // Handle the region itself.
- if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R)) {
+
+ if (isa<AllocaRegion>(baseR) || isa<SymbolicRegion>(baseR)) {
// Invalidate the region by setting its default value to
// conjured symbol. The type of the symbol is irrelavant.
- DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
+ DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(baseR, Ex, Ctx.IntTy,
Count);
- B = Add(B, R, BindingVal(V, BindingVal::Default));
+ B = RM.Add(B, baseR, BindingKey::Default, V);
continue;
}
-
- if (!R->isBoundable())
- continue;
-
- const TypedRegion *TR = cast<TypedRegion>(R);
+
+ if (!baseR->isBoundable())
+ continue;
+
+ const TypedRegion *TR = cast<TypedRegion>(baseR);
QualType T = TR->getValueType(Ctx);
-
- if (const RecordType *RT = T->getAsStructureType()) {
- const RecordDecl *RD = RT->getDecl()->getDefinition(Ctx);
+ // Invalidate the binding.
+ if (const RecordType *RT = T->getAsStructureType()) {
+ const RecordDecl *RD = RT->getDecl()->getDefinition();
// No record definition. There is nothing we can do.
- if (!RD)
+ if (!RD) {
+ B = RM.Remove(B, baseR);
continue;
+ }
// Invalidate the region by setting its default value to
// conjured symbol. The type of the symbol is irrelavant.
- DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
+ DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(baseR, Ex, Ctx.IntTy,
Count);
- B = Add(B, R, BindingVal(V, BindingVal::Default));
+ B = RM.Add(B, baseR, BindingKey::Default, V);
continue;
- }
-
+ }
+
if (const ArrayType *AT = Ctx.getAsArrayType(T)) {
// Set the default value of the array to conjured symbol.
DefinedOrUnknownSVal V =
- ValMgr.getConjuredSymbolVal(R, Ex, AT->getElementType(), Count);
- B = Add(B, R, BindingVal(V, BindingVal::Default));
+ ValMgr.getConjuredSymbolVal(baseR, Ex, AT->getElementType(), Count);
+ B = RM.Add(B, baseR, BindingKey::Default, V);
continue;
}
-
- if ((isa<FieldRegion>(R)||isa<ElementRegion>(R)||isa<ObjCIvarRegion>(R))
- && Visited[cast<SubRegion>(R)->getSuperRegion()]) {
- // For fields and elements whose super region has also been invalidated,
- // only remove the old binding. The super region will get set with a
- // default value from which we can lazily derive a new symbolic value.
- B = Remove(B, R);
- continue;
- }
-
- // Invalidate the binding.
- DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, T, Count);
+
+ DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(baseR, Ex, T, Count);
assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
- B = Add(B, R, BindingVal(V, BindingVal::Direct));
+ B = RM.Add(B, baseR, BindingKey::Direct, V);
}
// Create a new state with the updated bindings.
- return state->makeWithStore(B.getRoot());
-}
-
-//===----------------------------------------------------------------------===//
-// getLValueXXX methods.
-//===----------------------------------------------------------------------===//
-
-/// getLValueString - Returns an SVal representing the lvalue of a
-/// StringLiteral. Within RegionStore a StringLiteral has an
-/// associated StringRegion, and the lvalue of a StringLiteral is the
-/// lvalue of that region.
-SVal RegionStoreManager::getLValueString(const StringLiteral* S) {
- return loc::MemRegionVal(MRMgr.getStringRegion(S));
-}
-
-/// getLValueVar - Returns an SVal that represents the lvalue of a
-/// variable. Within RegionStore a variable has an associated
-/// VarRegion, and the lvalue of the variable is the lvalue of that region.
-SVal RegionStoreManager::getLValueVar(const VarDecl *VD,
- const LocationContext *LC) {
- return loc::MemRegionVal(MRMgr.getVarRegion(VD, LC));
-}
-
-SVal RegionStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) {
- return getLValueFieldOrIvar(D, Base);
-}
-
-SVal RegionStoreManager::getLValueField(const FieldDecl* D, SVal Base) {
- return getLValueFieldOrIvar(D, Base);
-}
-
-SVal RegionStoreManager::getLValueFieldOrIvar(const Decl* D, SVal Base) {
- if (Base.isUnknownOrUndef())
- return Base;
-
- Loc BaseL = cast<Loc>(Base);
- const MemRegion* BaseR = 0;
-
- switch (BaseL.getSubKind()) {
- case loc::MemRegionKind:
- BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
- break;
-
- case loc::GotoLabelKind:
- // These are anormal cases. Flag an undefined value.
- return UndefinedVal();
-
- case loc::ConcreteIntKind:
- // While these seem funny, this can happen through casts.
- // FIXME: What we should return is the field offset. For example,
- // add the field offset to the integer value. That way funny things
- // like this work properly: &(((struct foo *) 0xa)->f)
- return Base;
-
- default:
- assert(0 && "Unhandled Base.");
- return Base;
- }
-
- // NOTE: We must have this check first because ObjCIvarDecl is a subclass
- // of FieldDecl.
- if (const ObjCIvarDecl *ID = dyn_cast<ObjCIvarDecl>(D))
- return loc::MemRegionVal(MRMgr.getObjCIvarRegion(ID, BaseR));
-
- return loc::MemRegionVal(MRMgr.getFieldRegion(cast<FieldDecl>(D), BaseR));
+ return B.getRoot();
}
-SVal RegionStoreManager::getLValueElement(QualType elementType, SVal Offset,
- SVal Base) {
-
- // If the base is an unknown or undefined value, just return it back.
- // FIXME: For absolute pointer addresses, we just return that value back as
- // well, although in reality we should return the offset added to that
- // value.
- if (Base.isUnknownOrUndef() || isa<loc::ConcreteInt>(Base))
- return Base;
-
- // Only handle integer offsets... for now.
- if (!isa<nonloc::ConcreteInt>(Offset))
- return UnknownVal();
-
- const MemRegion* BaseRegion = cast<loc::MemRegionVal>(Base).getRegion();
-
- // Pointer of any type can be cast and used as array base.
- const ElementRegion *ElemR = dyn_cast<ElementRegion>(BaseRegion);
-
- // Convert the offset to the appropriate size and signedness.
- Offset = ValMgr.convertToArrayIndex(Offset);
-
- if (!ElemR) {
- //
- // If the base region is not an ElementRegion, create one.
- // This can happen in the following example:
- //
- // char *p = __builtin_alloc(10);
- // p[1] = 8;
- //
- // Observe that 'p' binds to an AllocaRegion.
- //
- return loc::MemRegionVal(MRMgr.getElementRegion(elementType, Offset,
- BaseRegion, getContext()));
- }
-
- SVal BaseIdx = ElemR->getIndex();
-
- if (!isa<nonloc::ConcreteInt>(BaseIdx))
- return UnknownVal();
-
- const llvm::APSInt& BaseIdxI = cast<nonloc::ConcreteInt>(BaseIdx).getValue();
- const llvm::APSInt& OffI = cast<nonloc::ConcreteInt>(Offset).getValue();
- assert(BaseIdxI.isSigned());
-
- // Compute the new index.
- SVal NewIdx = nonloc::ConcreteInt(getBasicVals().getValue(BaseIdxI + OffI));
-
- // Construct the new ElementRegion.
- const MemRegion *ArrayR = ElemR->getSuperRegion();
- return loc::MemRegionVal(MRMgr.getElementRegion(elementType, NewIdx, ArrayR,
- getContext()));
+Store RegionStoreManager::InvalidateRegions(Store store,
+ const MemRegion * const *I,
+ const MemRegion * const *E,
+ const Expr *Ex, unsigned Count,
+ InvalidatedSymbols *IS) {
+ InvalidateRegionsWorker W(*this, IS, getContext(),
+ StateMgr.getValueManager());
+ return W.InvalidateRegions(store, I, E, Ex, Count);
}
-
+
//===----------------------------------------------------------------------===//
// Extents for regions.
//===----------------------------------------------------------------------===//
@@ -885,8 +798,7 @@ SVal RegionStoreManager::ArrayToPointer(Loc Array) {
// Pointer arithmetic.
//===----------------------------------------------------------------------===//
-SVal RegionStoreManager::EvalBinOp(const GRState *state,
- BinaryOperator::Opcode Op, Loc L, NonLoc R,
+SVal RegionStoreManager::EvalBinOp(BinaryOperator::Opcode Op, Loc L, NonLoc R,
QualType resultTy) {
// Assume the base location is MemRegionVal.
if (!isa<loc::MemRegionVal>(L))
@@ -989,33 +901,33 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
//===----------------------------------------------------------------------===//
Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B,
- const MemRegion *R) {
- if (const BindingVal *BV = Lookup(B, R))
- return Optional<SVal>::create(BV->getDirectValue());
-
+ const MemRegion *R) {
+ if (const SVal *V = Lookup(B, R, BindingKey::Direct))
+ return *V;
+
return Optional<SVal>();
}
Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
const MemRegion *R) {
-
if (R->isBoundable())
if (const TypedRegion *TR = dyn_cast<TypedRegion>(R))
if (TR->getValueType(getContext())->isUnionType())
return UnknownVal();
- if (const BindingVal *V = Lookup(B, R))
- return Optional<SVal>::create(V->getDefaultValue());
+ if (const SVal *V = Lookup(B, R, BindingKey::Default))
+ return *V;
return Optional<SVal>();
}
Optional<SVal> RegionStoreManager::getBinding(RegionBindings B,
const MemRegion *R) {
- if (const BindingVal *BV = Lookup(B, R))
- return Optional<SVal>::create(BV->getValue());
-
- return Optional<SVal>();
+
+ if (Optional<SVal> V = getDirectBinding(B, R))
+ return V;
+
+ return getDefaultBinding(B, R);
}
static bool IsReinterpreted(QualType RTy, QualType UsedTy, ASTContext &Ctx) {
@@ -1042,42 +954,29 @@ static bool IsReinterpreted(QualType RTy, QualType UsedTy, ASTContext &Ctx) {
}
const ElementRegion *
-RegionStoreManager::GetElementZeroRegion(const SymbolicRegion *SR, QualType T) {
+RegionStoreManager::GetElementZeroRegion(const MemRegion *R, QualType T) {
ASTContext &Ctx = getContext();
SVal idx = ValMgr.makeZeroArrayIndex();
assert(!T.isNull());
- return MRMgr.getElementRegion(T, idx, SR, Ctx);
+ return MRMgr.getElementRegion(T, idx, R, Ctx);
}
-
-
-
-SValuator::CastResult
-RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
+SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
assert(!isa<UnknownVal>(L) && "location unknown");
assert(!isa<UndefinedVal>(L) && "location undefined");
// FIXME: Is this even possible? Shouldn't this be treated as a null
// dereference at a higher level?
if (isa<loc::ConcreteInt>(L))
- return SValuator::CastResult(state, UndefinedVal());
+ return UndefinedVal();
const MemRegion *MR = cast<loc::MemRegionVal>(L).getRegion();
- // FIXME: return symbolic value for these cases.
- // Example:
- // void f(int* p) { int x = *p; }
- // char* p = alloca();
- // read(p);
- // c = *p;
- if (isa<AllocaRegion>(MR))
- return SValuator::CastResult(state, UnknownVal());
-
- if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
- MR = GetElementZeroRegion(SR, T);
+ if (isa<AllocaRegion>(MR) || isa<SymbolicRegion>(MR))
+ MR = GetElementZeroRegion(MR, T);
if (isa<CodeTextRegion>(MR))
- return SValuator::CastResult(state, UnknownVal());
+ return UnknownVal();
// FIXME: Perhaps this method should just take a 'const MemRegion*' argument
// instead of 'Loc', and have the other Loc cases handled at a higher level.
@@ -1105,23 +1004,21 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
#endif
if (RTy->isStructureType())
- return SValuator::CastResult(state, RetrieveStruct(state, R));
+ return RetrieveStruct(store, R);
// FIXME: Handle unions.
if (RTy->isUnionType())
- return SValuator::CastResult(state, UnknownVal());
+ return UnknownVal();
if (RTy->isArrayType())
- return SValuator::CastResult(state, RetrieveArray(state, R));
+ return RetrieveArray(store, R);
// FIXME: handle Vector types.
if (RTy->isVectorType())
- return SValuator::CastResult(state, UnknownVal());
+ return UnknownVal();
if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
- return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveField(state, FR), FR,
- T, false));
+ return CastRetrievedVal(RetrieveField(store, FR), FR, T, false);
if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) {
// FIXME: Here we actually perform an implicit conversion from the loaded
@@ -1129,9 +1026,7 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
// more intelligently. For example, an 'element' can encompass multiple
// bound regions (e.g., several bound bytes), or could be a subset of
// a larger value.
- return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveElement(state, ER),
- ER, T, false));
+ return CastRetrievedVal(RetrieveElement(store, ER), ER, T, false);
}
if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
@@ -1141,9 +1036,7 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
// reinterpretted, it is possible we stored a different value that could
// fit within the ivar. Either we need to cast these when storing them
// or reinterpret them lazily (as we do here).
- return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveObjCIvar(state, IVR),
- IVR, T, false));
+ return CastRetrievedVal(RetrieveObjCIvar(store, IVR), IVR, T, false);
}
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
@@ -1153,18 +1046,15 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
// variable is reinterpretted, it is possible we stored a different value
// that could fit within the variable. Either we need to cast these when
// storing them or reinterpret them lazily (as we do here).
- return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveVar(state, VR), VR, T,
- false));
+ return CastRetrievedVal(RetrieveVar(store, VR), VR, T, false);
}
- RegionBindings B = GetRegionBindings(state->getStore());
- const BindingVal *V = Lookup(B, R);
+ RegionBindings B = GetRegionBindings(store);
+ const SVal *V = Lookup(B, R, BindingKey::Direct);
// Check if the region has a binding.
if (V)
- if (SVal const *SV = V->getValue())
- return SValuator::CastResult(state, *SV);
+ return *V;
// The location does not have a bound value. This means that it has
// the value it had upon its creation and/or entry to the analyzed
@@ -1174,44 +1064,45 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
// upon creation. All heap allocated blocks are considered to
// have undefined values as well unless they are explicitly bound
// to specific values.
- return SValuator::CastResult(state, UndefinedVal());
+ return UndefinedVal();
}
// All other values are symbolic.
- return SValuator::CastResult(state, ValMgr.getRegionValueSymbolVal(R, RTy));
+ return ValMgr.getRegionValueSymbolVal(R, RTy);
}
-std::pair<const GRState*, const MemRegion*>
+std::pair<Store, const MemRegion *>
RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R) {
if (Optional<SVal> OV = getDirectBinding(B, R))
if (const nonloc::LazyCompoundVal *V =
dyn_cast<nonloc::LazyCompoundVal>(OV.getPointer()))
- return std::make_pair(V->getState(), V->getRegion());
+ return std::make_pair(V->getStore(), V->getRegion());
if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- const std::pair<const GRState *, const MemRegion *> &X =
+ const std::pair<Store, const MemRegion *> &X =
GetLazyBinding(B, ER->getSuperRegion());
- if (X.first)
+ if (X.second)
return std::make_pair(X.first,
MRMgr.getElementRegionWithSuper(ER, X.second));
}
else if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) {
- const std::pair<const GRState *, const MemRegion *> &X =
+ const std::pair<Store, const MemRegion *> &X =
GetLazyBinding(B, FR->getSuperRegion());
- if (X.first)
+ if (X.second)
return std::make_pair(X.first,
MRMgr.getFieldRegionWithSuper(FR, X.second));
}
-
- return std::make_pair((const GRState*) 0, (const MemRegion *) 0);
+ // The NULL MemRegion indicates an non-existent lazy binding. A NULL Store is
+ // possible for a valid lazy binding.
+ return std::make_pair((Store) 0, (const MemRegion *) 0);
}
-SVal RegionStoreManager::RetrieveElement(const GRState* state,
+SVal RegionStoreManager::RetrieveElement(Store store,
const ElementRegion* R) {
// Check if the region has a binding.
- RegionBindings B = GetRegionBindings(state->getStore());
+ RegionBindings B = GetRegionBindings(store);
if (Optional<SVal> V = getDirectBinding(B, R))
return *V;
@@ -1256,29 +1147,29 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state,
dyn_cast<nonloc::LazyCompoundVal>(V)) {
R = MRMgr.getElementRegionWithSuper(R, LCV->getRegion());
- return RetrieveElement(LCV->getState(), R);
+ return RetrieveElement(LCV->getStore(), R);
}
// Other cases: give up.
return UnknownVal();
}
- return RetrieveFieldOrElementCommon(state, R, R->getElementType(), superR);
+ return RetrieveFieldOrElementCommon(store, R, R->getElementType(), superR);
}
-SVal RegionStoreManager::RetrieveField(const GRState* state,
+SVal RegionStoreManager::RetrieveField(Store store,
const FieldRegion* R) {
// Check if the region has a binding.
- RegionBindings B = GetRegionBindings(state->getStore());
+ RegionBindings B = GetRegionBindings(store);
if (Optional<SVal> V = getDirectBinding(B, R))
return *V;
QualType Ty = R->getValueType(getContext());
- return RetrieveFieldOrElementCommon(state, R, Ty, R->getSuperRegion());
+ return RetrieveFieldOrElementCommon(store, R, Ty, R->getSuperRegion());
}
-SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state,
+SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store,
const TypedRegion *R,
QualType Ty,
const MemRegion *superR) {
@@ -1286,7 +1177,7 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state,
// At this point we have already checked in either RetrieveElement or
// RetrieveField if 'R' has a direct binding.
- RegionBindings B = GetRegionBindings(state->getStore());
+ RegionBindings B = GetRegionBindings(store);
while (superR) {
if (const Optional<SVal> &D = getDefaultBinding(B, superR)) {
@@ -1313,18 +1204,14 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state,
}
// Lazy binding?
- const GRState *lazyBindingState = NULL;
+ Store lazyBindingStore = NULL;
const MemRegion *lazyBindingRegion = NULL;
- llvm::tie(lazyBindingState, lazyBindingRegion) = GetLazyBinding(B, R);
-
- if (lazyBindingState) {
- assert(lazyBindingRegion && "Lazy-binding region not set");
-
- if (isa<ElementRegion>(R))
- return RetrieveElement(lazyBindingState,
- cast<ElementRegion>(lazyBindingRegion));
+ llvm::tie(lazyBindingStore, lazyBindingRegion) = GetLazyBinding(B, R);
- return RetrieveField(lazyBindingState,
+ if (lazyBindingRegion) {
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(lazyBindingRegion))
+ return RetrieveElement(lazyBindingStore, ER);
+ return RetrieveField(lazyBindingStore,
cast<FieldRegion>(lazyBindingRegion));
}
@@ -1345,11 +1232,10 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state,
return ValMgr.getRegionValueSymbolVal(R, Ty);
}
-SVal RegionStoreManager::RetrieveObjCIvar(const GRState* state,
- const ObjCIvarRegion* R) {
+SVal RegionStoreManager::RetrieveObjCIvar(Store store, const ObjCIvarRegion* R){
// Check if the region has a binding.
- RegionBindings B = GetRegionBindings(state->getStore());
+ RegionBindings B = GetRegionBindings(store);
if (Optional<SVal> V = getDirectBinding(B, R))
return *V;
@@ -1365,30 +1251,42 @@ SVal RegionStoreManager::RetrieveObjCIvar(const GRState* state,
return UnknownVal();
}
- return RetrieveLazySymbol(state, R);
+ return RetrieveLazySymbol(R);
}
-SVal RegionStoreManager::RetrieveVar(const GRState *state,
- const VarRegion *R) {
+SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) {
// Check if the region has a binding.
- RegionBindings B = GetRegionBindings(state->getStore());
+ RegionBindings B = GetRegionBindings(store);
if (Optional<SVal> V = getDirectBinding(B, R))
return *V;
// Lazily derive a value for the VarRegion.
const VarDecl *VD = R->getDecl();
+ QualType T = VD->getType();
+ const MemSpaceRegion *MS = R->getMemorySpace();
+
+ if (isa<UnknownSpaceRegion>(MS) ||
+ isa<StackArgumentsSpaceRegion>(MS))
+ return ValMgr.getRegionValueSymbolVal(R, T);
- if (R->hasGlobalsOrParametersStorage() ||
- isa<UnknownSpaceRegion>(R->getMemorySpace()))
- return ValMgr.getRegionValueSymbolVal(R, VD->getType());
+ if (isa<GlobalsSpaceRegion>(MS)) {
+ if (VD->isFileVarDecl())
+ return ValMgr.getRegionValueSymbolVal(R, T);
+ if (T->isIntegerType())
+ return ValMgr.makeIntVal(0, T);
+ if (T->isPointerType())
+ return ValMgr.makeNull();
+
+ return UnknownVal();
+ }
+
return UndefinedVal();
}
-SVal RegionStoreManager::RetrieveLazySymbol(const GRState *state,
- const TypedRegion *R) {
+SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) {
QualType valTy = R->getValueType(getContext());
@@ -1396,8 +1294,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const GRState *state,
return ValMgr.getRegionValueSymbolVal(R, valTy);
}
-SVal RegionStoreManager::RetrieveStruct(const GRState *state,
- const TypedRegion* R) {
+SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) {
QualType T = R->getValueType(getContext());
assert(T->isStructureType());
@@ -1417,18 +1314,17 @@ SVal RegionStoreManager::RetrieveStruct(const GRState *state,
Field != FieldEnd; ++Field) {
FieldRegion* FR = MRMgr.getFieldRegion(*Field, R);
QualType FTy = (*Field)->getType();
- SVal FieldValue = Retrieve(state, loc::MemRegionVal(FR), FTy).getSVal();
+ SVal FieldValue = Retrieve(store, loc::MemRegionVal(FR), FTy).getSVal();
StructVal = getBasicVals().consVals(FieldValue, StructVal);
}
return ValMgr.makeCompoundVal(T, StructVal);
#else
- return ValMgr.makeLazyCompoundVal(state, R);
+ return ValMgr.makeLazyCompoundVal(store, R);
#endif
}
-SVal RegionStoreManager::RetrieveArray(const GRState *state,
- const TypedRegion * R) {
+SVal RegionStoreManager::RetrieveArray(Store store, const TypedRegion * R) {
#if USE_EXPLICIT_COMPOUND
QualType T = R->getValueType(getContext());
ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr());
@@ -1440,14 +1336,14 @@ SVal RegionStoreManager::RetrieveArray(const GRState *state,
ElementRegion* ER = MRMgr.getElementRegion(CAT->getElementType(), Idx, R,
getContext());
QualType ETy = ER->getElementType();
- SVal ElementVal = Retrieve(state, loc::MemRegionVal(ER), ETy).getSVal();
+ SVal ElementVal = Retrieve(store, loc::MemRegionVal(ER), ETy).getSVal();
ArrayVal = getBasicVals().consVals(ElementVal, ArrayVal);
}
return ValMgr.makeCompoundVal(T, ArrayVal);
#else
assert(isa<ConstantArrayType>(R->getValueType(getContext())));
- return ValMgr.makeLazyCompoundVal(state, R);
+ return ValMgr.makeLazyCompoundVal(store, R);
#endif
}
@@ -1458,14 +1354,14 @@ SVal RegionStoreManager::RetrieveArray(const GRState *state,
Store RegionStoreManager::Remove(Store store, Loc L) {
if (isa<loc::MemRegionVal>(L))
if (const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion())
- return Remove(store, BindingKey::Make(R));
+ return Remove(GetRegionBindings(store), R).getRoot();
return store;
}
-const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
+Store RegionStoreManager::Bind(Store store, Loc L, SVal V) {
if (isa<loc::ConcreteInt>(L))
- return state;
+ return store;
// If we get here, the location should be a region.
const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
@@ -1473,7 +1369,7 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
// Check if the region is a struct region.
if (const TypedRegion* TR = dyn_cast<TypedRegion>(R))
if (TR->getValueType(getContext())->isStructureType())
- return BindStruct(state, TR, V);
+ return BindStruct(store, TR, V);
// Special case: the current region represents a cast and it and the super
// region both have pointer types or intptr_t types. If so, perform the
@@ -1490,14 +1386,13 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
if (IsAnyPointerOrIntptr(superTy, Ctx) &&
IsAnyPointerOrIntptr(erTy, Ctx)) {
- SValuator::CastResult cr =
- ValMgr.getSValuator().EvalCast(V, state, superTy, erTy);
- return Bind(cr.getState(), loc::MemRegionVal(superR), cr.getSVal());
+ V = ValMgr.getSValuator().EvalCast(V, superTy, erTy);
+ return Bind(store, loc::MemRegionVal(superR), V);
}
// For now, just invalidate the fields of the struct/union/class.
// FIXME: Precisely handle the fields of the record.
if (superTy->isRecordType())
- return InvalidateRegion(state, superR, NULL, 0, NULL);
+ return InvalidateRegion(store, superR, NULL, 0, NULL);
}
}
}
@@ -1516,39 +1411,35 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
}
// Perform the binding.
- RegionBindings B = GetRegionBindings(state->getStore());
- return state->makeWithStore(Add(B, R,
- BindingVal(V, BindingVal::Direct)).getRoot());
+ RegionBindings B = GetRegionBindings(store);
+ return Add(B, R, BindingKey::Direct, V).getRoot();
}
-const GRState *RegionStoreManager::BindDecl(const GRState *ST,
- const VarRegion *VR,
- SVal InitVal) {
+Store RegionStoreManager::BindDecl(Store store, const VarRegion *VR,
+ SVal InitVal) {
QualType T = VR->getDecl()->getType();
if (T->isArrayType())
- return BindArray(ST, VR, InitVal);
+ return BindArray(store, VR, InitVal);
if (T->isStructureType())
- return BindStruct(ST, VR, InitVal);
+ return BindStruct(store, VR, InitVal);
- return Bind(ST, ValMgr.makeLoc(VR), InitVal);
+ return Bind(store, ValMgr.makeLoc(VR), InitVal);
}
// FIXME: this method should be merged into Bind().
-const GRState *
-RegionStoreManager::BindCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr *CL,
- const LocationContext *LC,
- SVal V) {
- return Bind(state, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)),
+Store RegionStoreManager::BindCompoundLiteral(Store store,
+ const CompoundLiteralExpr *CL,
+ const LocationContext *LC,
+ SVal V) {
+ return Bind(store, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)),
V);
}
-const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state,
- const MemRegion *R,
- QualType T) {
- Store store = state->getStore();
+Store RegionStoreManager::setImplicitDefaultValue(Store store,
+ const MemRegion *R,
+ QualType T) {
RegionBindings B = GetRegionBindings(store);
SVal V;
@@ -1562,23 +1453,24 @@ const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state,
V = ValMgr.makeZeroVal(ValMgr.getContext().IntTy);
}
else {
- return state;
+ return store;
}
- return state->makeWithStore(Add(B, R,
- BindingVal(V, BindingVal::Default)).getRoot());
+ return Add(B, R, BindingKey::Default, V).getRoot();
}
-const GRState *RegionStoreManager::BindArray(const GRState *state,
- const TypedRegion* R,
- SVal Init) {
-
- QualType T = R->getValueType(getContext());
- ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr());
- QualType ElementTy = CAT->getElementType();
-
- uint64_t size = CAT->getSize().getZExtValue();
-
+Store RegionStoreManager::BindArray(Store store, const TypedRegion* R,
+ SVal Init) {
+
+ ASTContext &Ctx = getContext();
+ const ArrayType *AT =
+ cast<ArrayType>(Ctx.getCanonicalType(R->getValueType(Ctx)));
+ QualType ElementTy = AT->getElementType();
+ Optional<uint64_t> Size;
+
+ if (const ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(AT))
+ Size = CAT->getSize().getZExtValue();
+
// Check if the init expr is a StringLiteral.
if (isa<loc::MemRegionVal>(Init)) {
const MemRegion* InitR = cast<loc::MemRegionVal>(Init).getRegion();
@@ -1590,6 +1482,11 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
// Copy bytes from the string literal into the target array. Trailing bytes
// in the array that are not covered by the string literal are initialized
// to zero.
+
+ // We assume that string constants are bound to
+ // constant arrays.
+ uint64_t size = Size.getValue();
+
for (uint64_t i = 0; i < size; ++i, ++j) {
if (j >= len)
break;
@@ -1599,26 +1496,26 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
getContext());
SVal V = ValMgr.makeIntVal(str[j], sizeof(char)*8, true);
- state = Bind(state, loc::MemRegionVal(ER), V);
+ store = Bind(store, loc::MemRegionVal(ER), V);
}
- return state;
+ return store;
}
// Handle lazy compound values.
if (nonloc::LazyCompoundVal *LCV = dyn_cast<nonloc::LazyCompoundVal>(&Init))
- return CopyLazyBindings(*LCV, state, R);
+ return CopyLazyBindings(*LCV, store, R);
// Remaining case: explicit compound values.
if (Init.isUnknown())
- return setImplicitDefaultValue(state, R, ElementTy);
+ return setImplicitDefaultValue(store, R, ElementTy);
nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(Init);
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
uint64_t i = 0;
- for (; i < size; ++i, ++VI) {
+ for (; Size.hasValue() ? i < Size.getValue() : true ; ++i, ++VI) {
// The init list might be shorter than the array length.
if (VI == VE)
break;
@@ -1626,27 +1523,25 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
SVal Idx = ValMgr.makeArrayIndex(i);
const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext());
- if (CAT->getElementType()->isStructureType())
- state = BindStruct(state, ER, *VI);
+ if (ElementTy->isStructureType())
+ store = BindStruct(store, ER, *VI);
else
- // FIXME: Do we need special handling of nested arrays?
- state = Bind(state, ValMgr.makeLoc(ER), *VI);
+ store = Bind(store, ValMgr.makeLoc(ER), *VI);
}
// If the init list is shorter than the array length, set the
// array default value.
- if (i < size)
- state = setImplicitDefaultValue(state, R, ElementTy);
+ if (Size.hasValue() && i < Size.getValue())
+ store = setImplicitDefaultValue(store, R, ElementTy);
- return state;
+ return store;
}
-const GRState *
-RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
- SVal V) {
+Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R,
+ SVal V) {
if (!Features.supportsFields())
- return state;
+ return store;
QualType T = R->getValueType(getContext());
assert(T->isStructureType());
@@ -1655,16 +1550,16 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
RecordDecl* RD = RT->getDecl();
if (!RD->isDefinition())
- return state;
+ return store;
// Handle lazy compound values.
if (const nonloc::LazyCompoundVal *LCV=dyn_cast<nonloc::LazyCompoundVal>(&V))
- return CopyLazyBindings(*LCV, state, R);
+ return CopyLazyBindings(*LCV, store, R);
// We may get non-CompoundVal accidentally due to imprecise cast logic.
// Ignore them and kill the field values.
if (V.isUnknown() || !isa<nonloc::CompoundVal>(V))
- return state->makeWithStore(KillStruct(state->getStore(), R));
+ return KillStruct(store, R);
nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(V);
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
@@ -1680,22 +1575,21 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
const FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
if (FTy->isArrayType())
- state = BindArray(state, FR, *VI);
+ store = BindArray(store, FR, *VI);
else if (FTy->isStructureType())
- state = BindStruct(state, FR, *VI);
+ store = BindStruct(store, FR, *VI);
else
- state = Bind(state, ValMgr.makeLoc(FR), *VI);
+ store = Bind(store, ValMgr.makeLoc(FR), *VI);
}
// There may be fewer values in the initialize list than the fields of struct.
if (FI != FE) {
- Store store = state->getStore();
RegionBindings B = GetRegionBindings(store);
- B = Add(B, R, BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default));
- state = state->makeWithStore(B.getRoot());
+ B = Add(B, R, BindingKey::Default, ValMgr.makeIntVal(0, false));
+ store = B.getRoot();
}
- return state;
+ return store;
}
Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R) {
@@ -1705,74 +1599,70 @@ Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R) {
RemoveSubRegionBindings(B, R, *SubRegions);
// Set the default value of the struct region to "unknown".
- B = Add(B, R, BindingVal(UnknownVal(), BindingVal::Default));
-
- return B.getRoot();
+ return Add(B, R, BindingKey::Default, UnknownVal()).getRoot();
}
-const GRState*
-RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V,
- const GRState *state,
- const TypedRegion *R) {
+Store RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V,
+ Store store, const TypedRegion *R) {
// Nuke the old bindings stemming from R.
- RegionBindings B = GetRegionBindings(state->getStore());
+ RegionBindings B = GetRegionBindings(store);
llvm::OwningPtr<RegionStoreSubRegionMap>
- SubRegions(getRegionStoreSubRegionMap(state->getStore()));
+ SubRegions(getRegionStoreSubRegionMap(store));
// B and DVM are updated after the call to RemoveSubRegionBindings.
RemoveSubRegionBindings(B, R, *SubRegions.get());
// Now copy the bindings. This amounts to just binding 'V' to 'R'. This
// results in a zero-copy algorithm.
- return state->makeWithStore(Add(B, R,
- BindingVal(V, BindingVal::Direct)).getRoot());
+ return Add(B, R, BindingKey::Direct, V).getRoot();
}
//===----------------------------------------------------------------------===//
// "Raw" retrievals and bindings.
//===----------------------------------------------------------------------===//
-BindingKey BindingKey::Make(const MemRegion *R) {
+BindingKey BindingKey::Make(const MemRegion *R, Kind k) {
if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
const RegionRawOffset &O = ER->getAsRawOffset();
if (O.getRegion())
- return BindingKey(O.getRegion(), O.getByteOffset());
+ return BindingKey(O.getRegion(), O.getByteOffset(), k);
// FIXME: There are some ElementRegions for which we cannot compute
// raw offsets yet, including regions with symbolic offsets.
}
- return BindingKey(R, 0);
+ return BindingKey(R, 0, k);
}
-RegionBindings RegionStoreManager::Add(RegionBindings B, BindingKey K,
- BindingVal V) {
+RegionBindings RegionStoreManager::Add(RegionBindings B, BindingKey K, SVal V) {
return RBFactory.Add(B, K, V);
}
RegionBindings RegionStoreManager::Add(RegionBindings B, const MemRegion *R,
- BindingVal V) {
- return Add(B, BindingKey::Make(R), V);
+ BindingKey::Kind k, SVal V) {
+ return Add(B, BindingKey::Make(R, k), V);
}
-const BindingVal *RegionStoreManager::Lookup(RegionBindings B, BindingKey K) {
+const SVal *RegionStoreManager::Lookup(RegionBindings B, BindingKey K) {
return B.lookup(K);
}
-const BindingVal *RegionStoreManager::Lookup(RegionBindings B,
- const MemRegion *R) {
- return Lookup(B, BindingKey::Make(R));
+const SVal *RegionStoreManager::Lookup(RegionBindings B,
+ const MemRegion *R,
+ BindingKey::Kind k) {
+ return Lookup(B, BindingKey::Make(R, k));
}
RegionBindings RegionStoreManager::Remove(RegionBindings B, BindingKey K) {
return RBFactory.Remove(B, K);
}
-RegionBindings RegionStoreManager::Remove(RegionBindings B, const MemRegion *R){
- return Remove(B, BindingKey::Make(R));
+RegionBindings RegionStoreManager::Remove(RegionBindings B, const MemRegion *R,
+ BindingKey::Kind k){
+ return Remove(B, BindingKey::Make(R, k));
}
Store RegionStoreManager::Remove(Store store, BindingKey K) {
@@ -1784,13 +1674,12 @@ Store RegionStoreManager::Remove(Store store, BindingKey K) {
// State pruning.
//===----------------------------------------------------------------------===//
-void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
- SymbolReaper& SymReaper,
+Store RegionStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
+ SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
{
- typedef std::pair<const GRState*, const MemRegion *> RBDNode;
+ typedef std::pair<Store, const MemRegion *> RBDNode;
- Store store = state.getStore();
RegionBindings B = GetRegionBindings(store);
// The backmap from regions to subregions.
@@ -1825,7 +1714,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
if (SymReaper.isLive(Loc, VR))
- WorkList.push_back(std::make_pair(&state, VR));
+ WorkList.push_back(std::make_pair(store, VR));
continue;
}
@@ -1833,7 +1722,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
llvm::SmallVectorImpl<RBDNode> &Q =
SymReaper.isLive(SR->getSymbol()) ? WorkList : Postponed;
- Q.push_back(std::make_pair(&state, SR));
+ Q.push_back(std::make_pair(store, SR));
continue;
}
@@ -1847,7 +1736,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
// Enqueue the RegionRoots onto WorkList.
for (llvm::SmallVectorImpl<const MemRegion*>::iterator I=RegionRoots.begin(),
E=RegionRoots.end(); I!=E; ++I) {
- WorkList.push_back(std::make_pair(&state, *I));
+ WorkList.push_back(std::make_pair(store, *I));
}
RegionRoots.clear();
@@ -1864,23 +1753,24 @@ tryAgain:
Visited.insert(N);
const MemRegion *R = N.second;
- const GRState *state_N = N.first;
+ Store store_N = N.first;
// Enqueue subregions.
RegionStoreSubRegionMap *M;
- if (&state == state_N)
+ if (store == store_N)
M = SubRegions.get();
else {
- RegionStoreSubRegionMap *& SM = SC[state_N];
+ RegionStoreSubRegionMap *& SM = SC[store_N];
if (!SM)
- SM = getRegionStoreSubRegionMap(state_N->getStore());
+ SM = getRegionStoreSubRegionMap(store_N);
M = SM;
}
-
- RegionStoreSubRegionMap::iterator I, E;
- for (llvm::tie(I, E) = M->begin_end(R); I != E; ++I)
- WorkList.push_back(std::make_pair(state_N, *I));
+
+ if (const RegionStoreSubRegionMap::Set *S = M->getSubRegions(R))
+ for (RegionStoreSubRegionMap::Set::iterator I = S->begin(), E = S->end();
+ I != E; ++I)
+ WorkList.push_back(std::make_pair(store_N, *I));
// Enqueue the super region.
if (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
@@ -1891,7 +1781,7 @@ tryAgain:
// pointer arithmetic can get us to the other fields or elements.
assert(isa<FieldRegion>(R) || isa<ElementRegion>(R)
|| isa<ObjCIvarRegion>(R));
- WorkList.push_back(std::make_pair(state_N, superR));
+ WorkList.push_back(std::make_pair(store_N, superR));
}
}
@@ -1908,14 +1798,13 @@ tryAgain:
RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end();
RI != RE; ++RI) {
if ((*RI)->getDecl()->getAttr<BlocksAttr>())
- WorkList.push_back(std::make_pair(state_N, *RI));
+ WorkList.push_back(std::make_pair(store_N, *RI));
}
// No possible data bindings on a BlockDataRegion. Continue to the
// next region in the worklist.
continue;
}
- Store store_N = state_N->getStore();
RegionBindings B_N = GetRegionBindings(store_N);
// Get the data binding for R (if any).
@@ -1927,7 +1816,7 @@ tryAgain:
dyn_cast<nonloc::LazyCompoundVal>(V.getPointer())) {
const LazyCompoundValData *D = LCV->getCVData();
- WorkList.push_back(std::make_pair(D->getState(), D->getRegion()));
+ WorkList.push_back(std::make_pair(D->getStore(), D->getRegion()));
}
else {
// Update the set of live symbols.
@@ -1937,7 +1826,7 @@ tryAgain:
// If V is a region, then add it to the worklist.
if (const MemRegion *RX = V->getAsRegion())
- WorkList.push_back(std::make_pair(state_N, RX));
+ WorkList.push_back(std::make_pair(store_N, RX));
}
}
}
@@ -1960,27 +1849,27 @@ tryAgain:
// We have now scanned the store, marking reachable regions and symbols
// as live. We now remove all the regions that are dead from the store
// as well as update DSymbols with the set symbols that are now dead.
+ Store new_store = store;
for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
const MemRegion* R = I.getKey().getRegion();
// If this region live? Is so, none of its symbols are dead.
- if (Visited.count(std::make_pair(&state, R)))
+ if (Visited.count(std::make_pair(store, R)))
continue;
// Remove this dead region from the store.
- store = Remove(store, I.getKey());
+ new_store = Remove(new_store, I.getKey());
// Mark all non-live symbols that this region references as dead.
if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
SymReaper.maybeDead(SymR->getSymbol());
- SVal X = *I.getData().getValue();
+ SVal X = I.getData();
SVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
for (; SI != SE; ++SI)
SymReaper.maybeDead(*SI);
}
- // Write the store back.
- state.setStore(store);
+ return new_store;
}
GRState const *RegionStoreManager::EnterStackFrame(GRState const *state,
@@ -1993,12 +1882,13 @@ GRState const *RegionStoreManager::EnterStackFrame(GRState const *state,
CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end();
// Copy the arg expression value to the arg variables.
+ Store store = state->getStore();
for (; AI != AE; ++AI, ++PI) {
SVal ArgVal = state->getSVal(*AI);
- state = Bind(state, ValMgr.makeLoc(MRMgr.getVarRegion(*PI, frame)), ArgVal);
+ store = Bind(store, ValMgr.makeLoc(MRMgr.getVarRegion(*PI, frame)), ArgVal);
}
- return state;
+ return state->makeWithStore(store);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/ReturnPointerRangeChecker.cpp b/lib/Checker/ReturnPointerRangeChecker.cpp
index b0350cb576ff..949ded507c5b 100644
--- a/lib/Analysis/ReturnPointerRangeChecker.cpp
+++ b/lib/Checker/ReturnPointerRangeChecker.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
using namespace clang;
diff --git a/lib/Checker/ReturnStackAddressChecker.cpp b/lib/Checker/ReturnStackAddressChecker.cpp
new file mode 100644
index 000000000000..9cbabba4a5f5
--- /dev/null
+++ b/lib/Checker/ReturnStackAddressChecker.cpp
@@ -0,0 +1,125 @@
+//== 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/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallString.h"
+
+using namespace clang;
+
+namespace {
+class ReturnStackAddressChecker :
+ public CheckerVisitor<ReturnStackAddressChecker> {
+ BuiltinBug *BT;
+public:
+ ReturnStackAddressChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
+private:
+ void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE);
+};
+}
+
+void clang::RegisterReturnStackAddressChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new ReturnStackAddressChecker());
+}
+
+void *ReturnStackAddressChecker::getTag() {
+ static int x = 0; return &x;
+}
+
+void ReturnStackAddressChecker::EmitStackError(CheckerContext &C,
+ const MemRegion *R,
+ const Expr *RetE) {
+ ExplodedNode *N = C.GenerateSink();
+
+ if (!N)
+ return;
+
+ if (!BT)
+ BT = new BuiltinBug("Return of address to stack-allocated memory");
+
+ // Generate a report for this bug.
+ llvm::SmallString<512> buf;
+ llvm::raw_svector_ostream os(buf);
+ SourceRange range;
+
+ // Get the base region, stripping away fields and elements.
+ R = R->getBaseRegion();
+
+ // 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 if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
+ const BlockDecl *BD = BR->getCodeRegion()->getDecl();
+ SourceLocation L = BD->getLocStart();
+ range = BD->getSourceRange();
+ os << "Address of stack-allocated block declared on line "
+ << C.getSourceManager().getInstantiationLineNumber(L)
+ << " returned to caller";
+ }
+ else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+ os << "Address of stack memory associated with local variable '"
+ << VR->getString() << "' returned";
+ range = VR->getDecl()->getSourceRange();
+ }
+ else {
+ assert(false && "Invalid region in ReturnStackAddressChecker.");
+ return;
+ }
+
+ RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
+ report->addRange(RetE->getSourceRange());
+ if (range.isValid())
+ report->addRange(range);
+
+ C.EmitReport(report);
+}
+
+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;
+
+ if (R->hasStackStorage()) {
+ EmitStackError(C, R, RetE);
+ return;
+ }
+}
diff --git a/lib/Analysis/ReturnUndefChecker.cpp b/lib/Checker/ReturnUndefChecker.cpp
index 7cd71265805b..ee259883e48c 100644
--- a/lib/Analysis/ReturnUndefChecker.cpp
+++ b/lib/Checker/ReturnUndefChecker.cpp
@@ -14,9 +14,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
diff --git a/lib/Analysis/SVals.cpp b/lib/Checker/SVals.cpp
index fbdb73b0ef2e..28b3fce050bb 100644
--- a/lib/Analysis/SVals.cpp
+++ b/lib/Checker/SVals.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRState.h"
#include "clang/Basic/IdentifierTable.h"
using namespace clang;
@@ -153,8 +153,8 @@ void SVal::symbol_iterator::expand() {
assert(false && "unhandled expansion case");
}
-const GRState *nonloc::LazyCompoundVal::getState() const {
- return static_cast<const LazyCompoundValData*>(Data)->getState();
+const void *nonloc::LazyCompoundVal::getStore() const {
+ return static_cast<const LazyCompoundValData*>(Data)->getStore();
}
const TypedRegion *nonloc::LazyCompoundVal::getRegion() const {
@@ -299,7 +299,7 @@ void NonLoc::dumpToStream(llvm::raw_ostream& os) const {
}
case nonloc::LazyCompoundValKind: {
const nonloc::LazyCompoundVal &C = *cast<nonloc::LazyCompoundVal>(this);
- os << "lazyCompoundVal{" << (void*) C.getState() << ',' << C.getRegion()
+ os << "lazyCompoundVal{" << (void*) C.getStore() << ',' << C.getRegion()
<< '}';
break;
}
diff --git a/lib/Analysis/SValuator.cpp b/lib/Checker/SValuator.cpp
index 8392fcf65a2c..542fc1b1078d 100644
--- a/lib/Analysis/SValuator.cpp
+++ b/lib/Checker/SValuator.cpp
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/SValuator.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/SValuator.h"
+#include "clang/Checker/PathSensitive/GRState.h"
using namespace clang;
@@ -53,25 +53,29 @@ DefinedOrUnknownSVal SValuator::EvalEQ(const GRState *ST,
ValMgr.getContext().IntTy));
}
-SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
- QualType castTy, QualType originalTy){
-
+SVal SValuator::EvalCast(SVal val, QualType castTy, QualType originalTy) {
if (val.isUnknownOrUndef() || castTy == originalTy)
- return CastResult(state, val);
+ return val;
ASTContext &C = ValMgr.getContext();
// For const casts, just propagate the value.
if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType())
if (C.hasSameUnqualifiedType(castTy, originalTy))
- return CastResult(state, val);
+ return val;
+ // Check for casts to real or complex numbers. We don't handle these at all
+ // right now.
+ if (castTy->isFloatingType() || castTy->isAnyComplexType())
+ return UnknownVal();
+
+ // Check for casts from integers to integers.
if (castTy->isIntegerType() && originalTy->isIntegerType())
- return CastResult(state, EvalCastNL(cast<NonLoc>(val), castTy));
+ return EvalCastNL(cast<NonLoc>(val), castTy);
// Check for casts from pointers to integers.
if (castTy->isIntegerType() && Loc::IsLocType(originalTy))
- return CastResult(state, EvalCastL(cast<Loc>(val), castTy));
+ return EvalCastL(cast<Loc>(val), castTy);
// Check for casts from integers to pointers.
if (Loc::IsLocType(castTy) && originalTy->isIntegerType()) {
@@ -79,10 +83,9 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
if (const MemRegion *R = LV->getLoc().getAsRegion()) {
StoreManager &storeMgr = ValMgr.getStateManager().getStoreManager();
R = storeMgr.CastRegion(R, castTy);
- return R ? CastResult(state, loc::MemRegionVal(R))
- : CastResult(state, UnknownVal());
+ return R ? SVal(loc::MemRegionVal(R)) : UnknownVal();
}
- return CastResult(state, LV->getLoc());
+ return LV->getLoc();
}
goto DispatchCast;
}
@@ -90,7 +93,7 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
// Just pass through function and block pointers.
if (originalTy->isBlockPointerType() || originalTy->isFunctionPointerType()) {
assert(Loc::IsLocType(castTy));
- return CastResult(state, val);
+ return val;
}
// Check for casts from array type to another type.
@@ -101,7 +104,7 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
// Are we casting from an array to a pointer? If so just pass on
// the decayed value.
if (castTy->isPointerType())
- return CastResult(state, val);
+ return val;
// Are we casting from an array to an integer? If so, cast the decayed
// pointer value to an integer.
@@ -111,7 +114,7 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
// need the original decayed type.
// QualType elemTy = cast<ArrayType>(originalTy)->getElementType();
// QualType pointerTy = C.getPointerType(elemTy);
- return CastResult(state, EvalCastL(cast<Loc>(val), castTy));
+ return EvalCastL(cast<Loc>(val), castTy);
}
// Check for casts from a region to a specific type.
@@ -144,21 +147,11 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
// different type. If the MemRegion* returned is NULL, this expression
// evaluates to UnknownVal.
R = storeMgr.CastRegion(R, castTy);
- return R ? CastResult(state, loc::MemRegionVal(R))
- : CastResult(state, UnknownVal());
+ return R ? SVal(loc::MemRegionVal(R)) : UnknownVal();
}
DispatchCast:
// All other cases.
- return CastResult(state,
- isa<Loc>(val) ? EvalCastL(cast<Loc>(val), castTy)
- : EvalCastNL(cast<NonLoc>(val), castTy));
-}
-
-SValuator::DefinedOrUnknownCastResult
-SValuator::EvalCast(DefinedOrUnknownSVal V, const GRState *ST,
- QualType castTy, QualType originalType) {
- SValuator::CastResult X = EvalCast((SVal) V, ST, castTy, originalType);
- return DefinedOrUnknownCastResult(X.getState(),
- cast<DefinedOrUnknownSVal>(X.getSVal()));
+ return isa<Loc>(val) ? EvalCastL(cast<Loc>(val), castTy)
+ : EvalCastNL(cast<NonLoc>(val), castTy);
}
diff --git a/lib/Analysis/SimpleConstraintManager.cpp b/lib/Checker/SimpleConstraintManager.cpp
index eca20d574db3..8c423a99777d 100644
--- a/lib/Analysis/SimpleConstraintManager.cpp
+++ b/lib/Checker/SimpleConstraintManager.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "SimpleConstraintManager.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/Checker.h"
namespace clang {
diff --git a/lib/Analysis/SimpleConstraintManager.h b/lib/Checker/SimpleConstraintManager.h
index 818239831948..5f20e0072b20 100644
--- a/lib/Analysis/SimpleConstraintManager.h
+++ b/lib/Checker/SimpleConstraintManager.h
@@ -14,8 +14,8 @@
#ifndef LLVM_CLANG_ANALYSIS_SIMPLE_CONSTRAINT_MANAGER_H
#define LLVM_CLANG_ANALYSIS_SIMPLE_CONSTRAINT_MANAGER_H
-#include "clang/Analysis/PathSensitive/ConstraintManager.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/ConstraintManager.h"
+#include "clang/Checker/PathSensitive/GRState.h"
namespace clang {
diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Checker/SimpleSValuator.cpp
index 8f2f5a1b134c..fb1d74a99046 100644
--- a/lib/Analysis/SimpleSValuator.cpp
+++ b/lib/Checker/SimpleSValuator.cpp
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/SValuator.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/SValuator.h"
+#include "clang/Checker/PathSensitive/GRState.h"
using namespace clang;
@@ -423,6 +423,6 @@ SVal SimpleSValuator::EvalBinOpLN(const GRState *state,
}
// Delegate pointer arithmetic to the StoreManager.
- return state->getStateManager().getStoreManager().EvalBinOp(state, op, lhs,
+ return state->getStateManager().getStoreManager().EvalBinOp(op, lhs,
rhs, resultTy);
}
diff --git a/lib/Analysis/Store.cpp b/lib/Checker/Store.cpp
index 1724a9250c25..e524cb3d7cc3 100644
--- a/lib/Analysis/Store.cpp
+++ b/lib/Checker/Store.cpp
@@ -11,15 +11,15 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/Store.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/Store.h"
+#include "clang/Checker/PathSensitive/GRState.h"
#include "clang/AST/CharUnits.h"
using namespace clang;
StoreManager::StoreManager(GRStateManager &stateMgr)
: ValMgr(stateMgr.getValueManager()), StateMgr(stateMgr),
- MRMgr(ValMgr.getRegionManager()) {}
+ MRMgr(ValMgr.getRegionManager()), Ctx(stateMgr.getContext()) {}
const MemRegion *StoreManager::MakeElementRegion(const MemRegion *Base,
QualType EleTy, uint64_t index) {
@@ -31,7 +31,7 @@ const MemRegion *StoreManager::MakeElementRegion(const MemRegion *Base,
static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
const RecordDecl *D = RT->getDecl();
- if (!D->getDefinition(Ctx))
+ if (!D->getDefinition())
return false;
}
@@ -224,27 +224,104 @@ SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
return V;
}
-const GRState *StoreManager::InvalidateRegions(const GRState *state,
- const MemRegion * const *I,
- const MemRegion * const *End,
- const Expr *E,
- unsigned Count,
- InvalidatedSymbols *IS) {
+Store StoreManager::InvalidateRegions(Store store,
+ const MemRegion * const *I,
+ const MemRegion * const *End,
+ const Expr *E, unsigned Count,
+ InvalidatedSymbols *IS) {
for ( ; I != End ; ++I)
- state = InvalidateRegion(state, *I, E, Count, IS);
+ store = InvalidateRegion(store, *I, E, Count, IS);
- return state;
+ return store;
}
-//===----------------------------------------------------------------------===//
-// Common getLValueXXX methods.
-//===----------------------------------------------------------------------===//
+SVal StoreManager::getLValueFieldOrIvar(const Decl* D, SVal Base) {
+ if (Base.isUnknownOrUndef())
+ return Base;
+
+ Loc BaseL = cast<Loc>(Base);
+ const MemRegion* BaseR = 0;
+
+ switch (BaseL.getSubKind()) {
+ case loc::MemRegionKind:
+ BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
+ break;
+
+ case loc::GotoLabelKind:
+ // These are anormal cases. Flag an undefined value.
+ return UndefinedVal();
+
+ case loc::ConcreteIntKind:
+ // While these seem funny, this can happen through casts.
+ // FIXME: What we should return is the field offset. For example,
+ // add the field offset to the integer value. That way funny things
+ // like this work properly: &(((struct foo *) 0xa)->f)
+ return Base;
+
+ default:
+ assert(0 && "Unhandled Base.");
+ return Base;
+ }
+
+ // NOTE: We must have this check first because ObjCIvarDecl is a subclass
+ // of FieldDecl.
+ if (const ObjCIvarDecl *ID = dyn_cast<ObjCIvarDecl>(D))
+ return loc::MemRegionVal(MRMgr.getObjCIvarRegion(ID, BaseR));
+
+ return loc::MemRegionVal(MRMgr.getFieldRegion(cast<FieldDecl>(D), BaseR));
+}
+
+SVal StoreManager::getLValueElement(QualType elementType, SVal Offset,
+ SVal Base) {
+
+ // If the base is an unknown or undefined value, just return it back.
+ // FIXME: For absolute pointer addresses, we just return that value back as
+ // well, although in reality we should return the offset added to that
+ // value.
+ if (Base.isUnknownOrUndef() || isa<loc::ConcreteInt>(Base))
+ return Base;
+
+ // Only handle integer offsets... for now.
+ if (!isa<nonloc::ConcreteInt>(Offset))
+ return UnknownVal();
+
+ const MemRegion* BaseRegion = cast<loc::MemRegionVal>(Base).getRegion();
+
+ // Pointer of any type can be cast and used as array base.
+ const ElementRegion *ElemR = dyn_cast<ElementRegion>(BaseRegion);
+
+ // Convert the offset to the appropriate size and signedness.
+ Offset = ValMgr.convertToArrayIndex(Offset);
+
+ if (!ElemR) {
+ //
+ // If the base region is not an ElementRegion, create one.
+ // This can happen in the following example:
+ //
+ // char *p = __builtin_alloc(10);
+ // p[1] = 8;
+ //
+ // Observe that 'p' binds to an AllocaRegion.
+ //
+ return loc::MemRegionVal(MRMgr.getElementRegion(elementType, Offset,
+ BaseRegion, Ctx));
+ }
+
+ SVal BaseIdx = ElemR->getIndex();
+
+ if (!isa<nonloc::ConcreteInt>(BaseIdx))
+ return UnknownVal();
+
+ const llvm::APSInt& BaseIdxI = cast<nonloc::ConcreteInt>(BaseIdx).getValue();
+ const llvm::APSInt& OffI = cast<nonloc::ConcreteInt>(Offset).getValue();
+ assert(BaseIdxI.isSigned());
+
+ // Compute the new index.
+ SVal NewIdx = nonloc::ConcreteInt(
+ ValMgr.getBasicValueFactory().getValue(BaseIdxI + OffI));
-/// getLValueCompoundLiteral - Returns an SVal representing the lvalue
-/// of a compound literal. Within RegionStore a compound literal
-/// has an associated region, and the lvalue of the compound literal
-/// is the lvalue of that region.
-SVal StoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL,
- const LocationContext *LC) {
- return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC));
+ // Construct the new ElementRegion.
+ const MemRegion *ArrayR = ElemR->getSuperRegion();
+ return loc::MemRegionVal(MRMgr.getElementRegion(elementType, NewIdx, ArrayR,
+ Ctx));
}
diff --git a/lib/Analysis/SymbolManager.cpp b/lib/Checker/SymbolManager.cpp
index 3fe36b064e3d..40bdcf65bca4 100644
--- a/lib/Analysis/SymbolManager.cpp
+++ b/lib/Checker/SymbolManager.cpp
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/SymbolManager.h"
-#include "clang/Analysis/PathSensitive/MemRegion.h"
+#include "clang/Checker/PathSensitive/SymbolManager.h"
+#include "clang/Checker/PathSensitive/MemRegion.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
diff --git a/lib/Analysis/UndefBranchChecker.cpp b/lib/Checker/UndefBranchChecker.cpp
index c739d1ac4b22..e047b187b108 100644
--- a/lib/Analysis/UndefBranchChecker.cpp
+++ b/lib/Checker/UndefBranchChecker.cpp
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/Checker.h"
using namespace clang;
diff --git a/lib/Checker/UndefCapturedBlockVarChecker.cpp b/lib/Checker/UndefCapturedBlockVarChecker.cpp
new file mode 100644
index 000000000000..a8d7284b40ac
--- /dev/null
+++ b/lib/Checker/UndefCapturedBlockVarChecker.cpp
@@ -0,0 +1,101 @@
+// UndefCapturedBlockVarChecker.cpp - Uninitialized captured vars -*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker detects blocks that capture uninitialized values.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+namespace {
+class UndefCapturedBlockVarChecker
+ : public CheckerVisitor<UndefCapturedBlockVarChecker> {
+ BugType *BT;
+
+public:
+ UndefCapturedBlockVarChecker() : BT(0) {}
+ static void *getTag() { static int tag = 0; return &tag; }
+ void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE);
+};
+} // end anonymous namespace
+
+void clang::RegisterUndefCapturedBlockVarChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new UndefCapturedBlockVarChecker());
+}
+
+static const BlockDeclRefExpr *FindBlockDeclRefExpr(const Stmt *S,
+ const VarDecl *VD){
+ if (const BlockDeclRefExpr *BR = dyn_cast<BlockDeclRefExpr>(S))
+ if (BR->getDecl() == VD)
+ return BR;
+
+ for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
+ I!=E; ++I)
+ if (const Stmt *child = *I) {
+ const BlockDeclRefExpr *BR = FindBlockDeclRefExpr(child, VD);
+ if (BR)
+ return BR;
+ }
+
+ return NULL;
+}
+
+void
+UndefCapturedBlockVarChecker::PostVisitBlockExpr(CheckerContext &C,
+ const BlockExpr *BE) {
+ if (!BE->hasBlockDeclRefExprs())
+ return;
+
+ const GRState *state = C.getState();
+ const BlockDataRegion *R =
+ cast<BlockDataRegion>(state->getSVal(BE).getAsRegion());
+
+ BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
+ E = R->referenced_vars_end();
+
+ for (; I != E; ++I) {
+ // This VarRegion is the region associated with the block; we need
+ // the one associated with the encompassing context.
+ const VarRegion *VR = *I;
+ const VarDecl *VD = VR->getDecl();
+
+ if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage())
+ continue;
+
+ // Get the VarRegion associated with VD in the local stack frame.
+ const LocationContext *LC = C.getPredecessor()->getLocationContext();
+ VR = C.getValueManager().getRegionManager().getVarRegion(VD, LC);
+
+ if (state->getSVal(VR).isUndef())
+ if (ExplodedNode *N = C.GenerateSink()) {
+ if (!BT)
+ BT = new BuiltinBug("Captured block variable is uninitialized");
+
+ // Generate a bug report.
+ llvm::SmallString<128> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ os << "Variable '" << VD->getName() << "' is captured by block with "
+ "a garbage value";
+
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N);
+ if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD))
+ R->addRange(Ex->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerFindLastStore, VR);
+ // need location of block
+ C.EmitReport(R);
+ }
+ }
+}
diff --git a/lib/Analysis/UndefResultChecker.cpp b/lib/Checker/UndefResultChecker.cpp
index acc86dda5a97..fb2283a62044 100644
--- a/lib/Analysis/UndefResultChecker.cpp
+++ b/lib/Checker/UndefResultChecker.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
using namespace clang;
diff --git a/lib/Analysis/UndefinedArraySubscriptChecker.cpp b/lib/Checker/UndefinedArraySubscriptChecker.cpp
index d6aacaf1f85e..a2792ad17ba1 100644
--- a/lib/Analysis/UndefinedArraySubscriptChecker.cpp
+++ b/lib/Checker/UndefinedArraySubscriptChecker.cpp
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Analysis/UndefinedAssignmentChecker.cpp b/lib/Checker/UndefinedAssignmentChecker.cpp
index 4630b823a91e..7c33c1d39235 100644
--- a/lib/Analysis/UndefinedAssignmentChecker.cpp
+++ b/lib/Checker/UndefinedAssignmentChecker.cpp
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
using namespace clang;
diff --git a/lib/Analysis/VLASizeChecker.cpp b/lib/Checker/VLASizeChecker.cpp
index 2690d6f0cffc..51ad1e2daf5e 100644
--- a/lib/Analysis/VLASizeChecker.cpp
+++ b/lib/Checker/VLASizeChecker.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
using namespace clang;
diff --git a/lib/Analysis/ValueManager.cpp b/lib/Checker/ValueManager.cpp
index d09137330cb2..5359489a2299 100644
--- a/lib/Analysis/ValueManager.cpp
+++ b/lib/Checker/ValueManager.cpp
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/ValueManager.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/Checker/PathSensitive/ValueManager.h"
+#include "clang/Analysis/AnalysisContext.h"
using namespace clang;
using namespace llvm;
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index ca5b6fa97c26..46b62441d6e4 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -13,6 +13,7 @@
#include "CGDebugInfo.h"
#include "CodeGenFunction.h"
+#include "CGObjCRuntime.h"
#include "CodeGenModule.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/Module.h"
@@ -176,7 +177,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
// block literal.
// __invoke
CharUnits subBlockSize;
- uint64_t subBlockAlign;
+ CharUnits subBlockAlign;
llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls;
bool subBlockHasCopyDispose = false;
llvm::Function *Fn
@@ -249,7 +250,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
llvm::StructType *Ty = llvm::StructType::get(VMContext, Types, true);
llvm::AllocaInst *A = CreateTempAlloca(Ty);
- A->setAlignment(subBlockAlign);
+ A->setAlignment(subBlockAlign.getQuantity());
V = A;
std::vector<HelperInfo> NoteForHelper(subBlockDeclRefDecls.size());
@@ -355,7 +356,21 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
}
QualType BPT = BE->getType();
- return Builder.CreateBitCast(V, ConvertType(BPT));
+ V = Builder.CreateBitCast(V, ConvertType(BPT));
+ // See if this is a __weak block variable and the must call objc_read_weak
+ // on it.
+ const FunctionType *ftype = BPT->getPointeeType()->getAs<FunctionType>();
+ QualType RES = ftype->getResultType();
+ if (RES.isObjCGCWeak()) {
+ // Must cast argument to id*
+ const llvm::Type *ObjectPtrTy =
+ ConvertType(CGM.getContext().getObjCIdType());
+ const llvm::Type *PtrObjectPtrTy =
+ llvm::PointerType::getUnqual(ObjectPtrTy);
+ V = Builder.CreateBitCast(V, PtrObjectPtrTy);
+ V = CGM.getObjCRuntime().EmitObjCWeakRead(*this, V);
+ }
+ return V;
}
@@ -496,10 +511,12 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
// Load the function.
llvm::Value *Func = Builder.CreateLoad(FuncPtr, "tmp");
- QualType ResultType = FnType->getAs<FunctionType>()->getResultType();
+ const FunctionType *FuncTy = FnType->getAs<FunctionType>();
+ QualType ResultType = FuncTy->getResultType();
const CGFunctionInfo &FnInfo =
- CGM.getTypes().getFunctionInfo(ResultType, Args);
+ CGM.getTypes().getFunctionInfo(ResultType, Args, FuncTy->getCallConv(),
+ FuncTy->getNoReturnAttr());
// Cast the function pointer to the right type.
const llvm::Type *BlockFTy =
@@ -593,8 +610,8 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
// Block literal size. For global blocks we just use the size of the generic
// block literal struct.
- CharUnits BlockLiteralSize = CharUnits::fromQuantity(
- TheTargetData.getTypeStoreSizeInBits(getGenericBlockLiteralType()) / 8);
+ CharUnits BlockLiteralSize =
+ CGM.GetTargetTypeStoreSize(getGenericBlockLiteralType());
DescriptorFields[1] =
llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize.getQuantity());
@@ -615,7 +632,7 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
CodeGenFunction::BlockInfo Info(0, n);
CharUnits subBlockSize;
- uint64_t subBlockAlign;
+ CharUnits subBlockAlign;
llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls;
bool subBlockHasCopyDispose = false;
llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
@@ -678,7 +695,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
const Decl *OuterFuncDecl,
llvm::DenseMap<const Decl*, llvm::Value*> ldm,
CharUnits &Size,
- uint64_t &Align,
+ CharUnits &Align,
llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls,
bool &subBlockHasCopyDispose) {
@@ -698,13 +715,14 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
LocalDeclMap[VD] = i->second;
}
- BlockOffset = CharUnits::fromQuantity(
- CGM.getTargetData()
- .getTypeStoreSizeInBits(CGM.getGenericBlockLiteralType()) / 8);
- BlockAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
+ BlockOffset =
+ CGM.GetTargetTypeStoreSize(CGM.getGenericBlockLiteralType());
+ BlockAlign = getContext().getTypeAlignInChars(getContext().VoidPtrTy);
const FunctionType *BlockFunctionType = BExpr->getFunctionType();
QualType ResultType;
+ CallingConv CC = BlockFunctionType->getCallConv();
+ bool NoReturn = BlockFunctionType->getNoReturnAttr();
bool IsVariadic;
if (const FunctionProtoType *FTy =
dyn_cast<FunctionProtoType>(BlockFunctionType)) {
@@ -743,7 +761,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
Args.push_back(std::make_pair(*i, (*i)->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(ResultType, Args);
+ CGM.getTypes().getFunctionInfo(ResultType, Args, CC, NoReturn);
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, IsVariadic);
@@ -777,10 +795,9 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
if (CGDebugInfo *DI = getDebugInfo()) {
// Emit debug information for all the BlockDeclRefDecls.
- for (unsigned i=0; i < BlockDeclRefDecls.size(); ++i) {
- const Expr *E = BlockDeclRefDecls[i];
- const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
- if (BDRE) {
+ for (unsigned i = 0, e = BlockDeclRefDecls.size(); i != e; ++i) {
+ if (const BlockDeclRefExpr *BDRE =
+ dyn_cast<BlockDeclRefExpr>(BlockDeclRefDecls[i])) {
const ValueDecl *D = BDRE->getDecl();
DI->setLocation(D->getLocation());
DI->EmitDeclareOfBlockDeclRefVariable(BDRE,
@@ -798,9 +815,10 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
FinishFunction(cast<CompoundStmt>(BExpr->getBody())->getRBracLoc());
// The runtime needs a minimum alignment of a void *.
- uint64_t MinAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
+ CharUnits MinAlign = getContext().getTypeAlignInChars(getContext().VoidPtrTy);
BlockOffset = CharUnits::fromQuantity(
- llvm::RoundUpToAlignment(BlockOffset.getQuantity(), MinAlign));
+ llvm::RoundUpToAlignment(BlockOffset.getQuantity(),
+ MinAlign.getQuantity()));
Size = BlockOffset;
Align = BlockAlign;
@@ -813,20 +831,20 @@ CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
const ValueDecl *D = dyn_cast<ValueDecl>(BDRE->getDecl());
CharUnits Size = getContext().getTypeSizeInChars(D->getType());
- uint64_t Align = getContext().getDeclAlignInBytes(D);
+ CharUnits Align = getContext().getDeclAlign(D);
if (BDRE->isByRef()) {
Size = getContext().getTypeSizeInChars(getContext().VoidPtrTy);
- Align = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
+ Align = getContext().getTypeAlignInChars(getContext().VoidPtrTy);
}
- assert ((Align > 0) && "alignment must be 1 byte or more");
+ assert ((Align.isPositive()) && "alignment must be 1 byte or more");
CharUnits OldOffset = BlockOffset;
// Ensure proper alignment, even if it means we have to have a gap
BlockOffset = CharUnits::fromQuantity(
- llvm::RoundUpToAlignment(BlockOffset.getQuantity(), Align));
+ llvm::RoundUpToAlignment(BlockOffset.getQuantity(), Align.getQuantity()));
BlockAlign = std::max(Align, BlockAlign);
CharUnits Pad = BlockOffset - OldOffset;
@@ -868,7 +886,7 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T,
Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args);
+ CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
@@ -949,7 +967,7 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose,
Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args);
+ CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
@@ -1033,7 +1051,7 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) {
Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args);
+ CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
@@ -1096,7 +1114,7 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args);
+ CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index f42244c52e0e..a9f5ae05c109 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -177,8 +177,9 @@ public:
/// BlockOffset - The offset in bytes for the next allocation of an
/// imported block variable.
CharUnits BlockOffset;
- /// BlockAlign - Maximal alignment needed for the Block expressed in bytes.
- uint64_t BlockAlign;
+ /// BlockAlign - Maximal alignment needed for the Block expressed in
+ /// characters.
+ CharUnits BlockAlign;
/// getBlockOffset - Allocate an offset for the ValueDecl from a
/// BlockDeclRefExpr in a block literal (BlockExpr).
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index f11d52e4334c..beaf7b89c003 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -304,6 +304,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Size = Builder.CreateIntCast(Size, llvm::Type::getInt32Ty(VMContext), false, "tmp");
return RValue::get(Builder.CreateAlloca(llvm::Type::getInt8Ty(VMContext), Size, "tmp"));
}
+ case Builtin::BIbzero:
case Builtin::BI__builtin_bzero: {
Value *Address = EmitScalarExpr(E->getArg(0));
Builder.CreateCall4(CGM.getMemSetFn(), Address,
@@ -656,7 +657,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// Unknown builtin, for now just dump it out and return undef.
if (hasAggregateLLVMType(E->getType()))
- return RValue::getAggregate(CreateTempAlloca(ConvertType(E->getType())));
+ return RValue::getAggregate(CreateMemTemp(E->getType()));
return RValue::get(llvm::UndefValue::get(ConvertType(E->getType())));
}
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 4323f84d9633..28c4c6b4b57b 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -165,7 +165,8 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
GlobalDecl GD, bool Extern,
const CovariantThunkAdjustment &Adjustment) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ QualType ResultType = FPT->getResultType();
FunctionArgList Args;
ImplicitParamDecl *ThisDecl =
@@ -190,7 +191,6 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
StartFunction(FD, ResultType, Fn, Args, SourceLocation());
// generate body
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
const llvm::Type *Ty =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
FPT->isVariadic());
@@ -232,7 +232,9 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
CallArgs.push_back(std::make_pair(EmitCallArg(Arg, ArgType), ArgType));
}
- RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs,
+ FPT->getCallConv(),
+ FPT->getNoReturnAttr()),
Callee, ReturnValueSlot(), CallArgs, MD);
if (ShouldAdjustReturnPointer && !Adjustment.ReturnAdjustment.isEmpty()) {
bool CanBeZero = !(ResultType->isReferenceType()
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 2dda0b883f04..b064c125ad00 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -33,12 +33,19 @@ using namespace CodeGen;
// FIXME: Use iterator and sidestep silly type array creation.
+static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) {
+ switch (CC) {
+ default: return llvm::CallingConv::C;
+ case CC_X86StdCall: return llvm::CallingConv::X86_StdCall;
+ case CC_X86FastCall: return llvm::CallingConv::X86_FastCall;
+ }
+}
+
const
CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionNoProtoType *FTNP) {
- // FIXME: Set calling convention correctly, it needs to be associated with the
- // type somehow.
return getFunctionInfo(FTNP->getResultType(),
- llvm::SmallVector<QualType, 16>(), 0);
+ llvm::SmallVector<QualType, 16>(),
+ FTNP->getCallConv(), FTNP->getNoReturnAttr());
}
const
@@ -47,20 +54,19 @@ CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionProtoType *FTP) {
// FIXME: Kill copy.
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
ArgTys.push_back(FTP->getArgType(i));
- // FIXME: Set calling convention correctly, it needs to be associated with the
- // type somehow.
- return getFunctionInfo(FTP->getResultType(), ArgTys, 0);
+ return getFunctionInfo(FTP->getResultType(), ArgTys,
+ FTP->getCallConv(), FTP->getNoReturnAttr());
}
-static unsigned getCallingConventionForDecl(const Decl *D) {
+static CallingConv getCallingConventionForDecl(const Decl *D) {
// Set the appropriate calling convention for the Function.
if (D->hasAttr<StdCallAttr>())
- return llvm::CallingConv::X86_StdCall;
+ return CC_X86StdCall;
if (D->hasAttr<FastCallAttr>())
- return llvm::CallingConv::X86_FastCall;
+ return CC_X86FastCall;
- return llvm::CallingConv::C;
+ return CC_C;
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD,
@@ -75,7 +81,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD,
// FIXME: Set calling convention correctly, it needs to be associated with the
// type somehow.
- return getFunctionInfo(FTP->getResultType(), ArgTys, 0);
+ return getFunctionInfo(FTP->getResultType(), ArgTys,
+ FTP->getCallConv(), FTP->getNoReturnAttr());
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) {
@@ -87,8 +94,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) {
const FunctionProtoType *FTP = MD->getType()->getAs<FunctionProtoType>();
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
ArgTys.push_back(FTP->getArgType(i));
- return getFunctionInfo(FTP->getResultType(), ArgTys,
- getCallingConventionForDecl(MD));
+ return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(),
+ FTP->getNoReturnAttr());
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D,
@@ -105,8 +112,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D,
const FunctionProtoType *FTP = D->getType()->getAs<FunctionProtoType>();
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
ArgTys.push_back(FTP->getArgType(i));
- return getFunctionInfo(FTP->getResultType(), ArgTys,
- getCallingConventionForDecl(D));
+ return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(),
+ FTP->getNoReturnAttr());
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D,
@@ -123,8 +130,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D,
const FunctionProtoType *FTP = D->getType()->getAs<FunctionProtoType>();
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
ArgTys.push_back(FTP->getArgType(i));
- return getFunctionInfo(FTP->getResultType(), ArgTys,
- getCallingConventionForDecl(D));
+ return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(),
+ FTP->getNoReturnAttr());
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) {
@@ -132,19 +139,19 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) {
if (MD->isInstance())
return getFunctionInfo(MD);
- unsigned CallingConvention = getCallingConventionForDecl(FD);
const FunctionType *FTy = FD->getType()->getAs<FunctionType>();
if (const FunctionNoProtoType *FNTP = dyn_cast<FunctionNoProtoType>(FTy))
return getFunctionInfo(FNTP->getResultType(),
llvm::SmallVector<QualType, 16>(),
- CallingConvention);
+ FNTP->getCallConv(), FNTP->getNoReturnAttr());
const FunctionProtoType *FPT = cast<FunctionProtoType>(FTy);
llvm::SmallVector<QualType, 16> ArgTys;
// FIXME: Kill copy.
for (unsigned i = 0, e = FPT->getNumArgs(); i != e; ++i)
ArgTys.push_back(FPT->getArgType(i));
- return getFunctionInfo(FPT->getResultType(), ArgTys, CallingConvention);
+ return getFunctionInfo(FPT->getResultType(), ArgTys,
+ FPT->getCallConv(), FPT->getNoReturnAttr());
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) {
@@ -156,37 +163,56 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) {
e = MD->param_end(); i != e; ++i)
ArgTys.push_back((*i)->getType());
return getFunctionInfo(MD->getResultType(), ArgTys,
- getCallingConventionForDecl(MD));
+ getCallingConventionForDecl(MD),
+ /*NoReturn*/ false);
+}
+
+const CGFunctionInfo &CodeGenTypes::getFunctionInfo(GlobalDecl GD) {
+ // FIXME: Do we need to handle ObjCMethodDecl?
+ const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
+
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
+ return getFunctionInfo(CD, GD.getCtorType());
+
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD))
+ return getFunctionInfo(DD, GD.getDtorType());
+
+ return getFunctionInfo(FD);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
const CallArgList &Args,
- unsigned CallingConvention){
+ CallingConv CC,
+ bool NoReturn) {
// FIXME: Kill copy.
llvm::SmallVector<QualType, 16> ArgTys;
for (CallArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i)
ArgTys.push_back(i->second);
- return getFunctionInfo(ResTy, ArgTys, CallingConvention);
+ return getFunctionInfo(ResTy, ArgTys, CC, NoReturn);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
const FunctionArgList &Args,
- unsigned CallingConvention){
+ CallingConv CC,
+ bool NoReturn) {
// FIXME: Kill copy.
llvm::SmallVector<QualType, 16> ArgTys;
for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i)
ArgTys.push_back(i->second);
- return getFunctionInfo(ResTy, ArgTys, CallingConvention);
+ return getFunctionInfo(ResTy, ArgTys, CC, NoReturn);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
const llvm::SmallVector<QualType, 16> &ArgTys,
- unsigned CallingConvention){
+ CallingConv CallConv,
+ bool NoReturn) {
+ unsigned CC = ClangCallConvToLLVMCallConv(CallConv);
+
// Lookup or create unique function info.
llvm::FoldingSetNodeID ID;
- CGFunctionInfo::Profile(ID, CallingConvention, ResTy,
+ CGFunctionInfo::Profile(ID, CC, NoReturn, ResTy,
ArgTys.begin(), ArgTys.end());
void *InsertPos = 0;
@@ -195,7 +221,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
return *FI;
// Construct the function info.
- FI = new CGFunctionInfo(CallingConvention, ResTy, ArgTys);
+ FI = new CGFunctionInfo(CC, NoReturn, ResTy, ArgTys);
FunctionInfos.InsertNode(FI, InsertPos);
// Compute ABI information.
@@ -205,10 +231,12 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
}
CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention,
+ bool _NoReturn,
QualType ResTy,
const llvm::SmallVector<QualType, 16> &ArgTys)
: CallingConvention(_CallingConvention),
- EffectiveCallingConvention(_CallingConvention)
+ EffectiveCallingConvention(_CallingConvention),
+ NoReturn(_NoReturn)
{
NumArgs = ArgTys.size();
Args = new ArgInfo[1 + NumArgs];
@@ -258,7 +286,7 @@ CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV,
QualType FT = FD->getType();
// FIXME: What are the right qualifiers here?
- LValue LV = EmitLValueForField(Addr, FD, false, 0);
+ LValue LV = EmitLValueForField(Addr, FD, 0);
if (CodeGenFunction::hasAggregateLLVMType(FT)) {
AI = ExpandTypeFromArgs(FT, LV, AI);
} else {
@@ -285,7 +313,7 @@ CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
QualType FT = FD->getType();
// FIXME: What are the right qualifiers here?
- LValue LV = EmitLValueForField(Addr, FD, false, 0);
+ LValue LV = EmitLValueForField(Addr, FD, 0);
if (CodeGenFunction::hasAggregateLLVMType(FT)) {
ExpandTypeToArgs(FT, RValue::getAggregate(LV.getAddress()), Args);
} else {
@@ -490,6 +518,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
CallingConv = FI.getEffectiveCallingConvention();
+ if (FI.isNoReturn())
+ FuncAttrs |= llvm::Attribute::NoReturn;
+
// FIXME: handle sseregparm someday...
if (TargetDecl) {
if (TargetDecl->hasAttr<NoThrowAttr>())
@@ -685,7 +716,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// Create a temporary alloca to hold the argument; the rest of
// codegen expects to access aggregates & complex values by
// reference.
- V = CreateTempAlloca(ConvertTypeForMem(Ty));
+ V = CreateMemTemp(Ty);
Builder.CreateStore(AI, V);
} else {
if (!getContext().typesAreCompatible(Ty, Arg->getType())) {
@@ -702,8 +733,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// If this structure was expanded into multiple arguments then
// we need to create a temporary and reconstruct it from the
// arguments.
- llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(Ty),
- Arg->getName() + ".addr");
+ llvm::Value *Temp = CreateMemTemp(Ty, Arg->getName() + ".addr");
// FIXME: What are the right qualifiers here?
llvm::Function::arg_iterator End =
ExpandTypeFromArgs(Ty, LValue::MakeAddr(Temp, Qualifiers()), AI);
@@ -719,7 +749,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
case ABIArgInfo::Ignore:
// Initialize the local variable appropriately.
if (hasAggregateLLVMType(Ty)) {
- EmitParmDecl(*Arg, CreateTempAlloca(ConvertTypeForMem(Ty)));
+ EmitParmDecl(*Arg, CreateMemTemp(Ty));
} else {
EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType())));
}
@@ -732,7 +762,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// FIXME: This is very wasteful; EmitParmDecl is just going to drop the
// result in a new alloca anyway, so we could just store into that
// directly if we broke the abstraction down more.
- llvm::Value *V = CreateTempAlloca(ConvertTypeForMem(Ty), "coerce");
+ llvm::Value *V = CreateMemTemp(Ty, "coerce");
CreateCoercedStore(AI, V, /*DestIsVolatile=*/false, *this);
// Match to what EmitParmDecl is expecting for this type.
if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
@@ -803,7 +833,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
RValue CodeGenFunction::EmitCallArg(const Expr *E, QualType ArgType) {
if (ArgType->isReferenceType())
- return EmitReferenceBindingToExpr(E, ArgType);
+ return EmitReferenceBindingToExpr(E);
return EmitAnyExprToTemp(E);
}
@@ -827,7 +857,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (CGM.ReturnTypeUsesSret(CallInfo)) {
llvm::Value *Value = ReturnValue.getValue();
if (!Value)
- Value = CreateTempAlloca(ConvertTypeForMem(RetTy));
+ Value = CreateMemTemp(RetTy);
Args.push_back(Value);
}
@@ -843,7 +873,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
case ABIArgInfo::Indirect:
if (RV.isScalar() || RV.isComplex()) {
// Make a temporary alloca to pass the argument.
- Args.push_back(CreateTempAlloca(ConvertTypeForMem(I->second)));
+ Args.push_back(CreateMemTemp(I->second));
if (RV.isScalar())
EmitStoreOfScalar(RV.getScalarVal(), Args.back(), false, I->second);
else
@@ -874,10 +904,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// FIXME: Avoid the conversion through memory if possible.
llvm::Value *SrcPtr;
if (RV.isScalar()) {
- SrcPtr = CreateTempAlloca(ConvertTypeForMem(I->second), "coerce");
+ SrcPtr = CreateMemTemp(I->second, "coerce");
EmitStoreOfScalar(RV.getScalarVal(), SrcPtr, false, I->second);
} else if (RV.isComplex()) {
- SrcPtr = CreateTempAlloca(ConvertTypeForMem(I->second), "coerce");
+ SrcPtr = CreateMemTemp(I->second, "coerce");
StoreComplexToAddr(RV.getComplexVal(), SrcPtr, false);
} else
SrcPtr = RV.getAggregateAddr();
@@ -982,7 +1012,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
bool DestIsVolatile = ReturnValue.isVolatile();
if (!DestPtr) {
- DestPtr = CreateTempAlloca(ConvertTypeForMem(RetTy), "agg.tmp");
+ DestPtr = CreateMemTemp(RetTy, "agg.tmp");
DestIsVolatile = false;
}
Builder.CreateStore(CI, DestPtr, DestIsVolatile);
@@ -1000,7 +1030,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
bool DestIsVolatile = ReturnValue.isVolatile();
if (!DestPtr) {
- DestPtr = CreateTempAlloca(ConvertTypeForMem(RetTy), "coerce");
+ DestPtr = CreateMemTemp(RetTy, "coerce");
DestIsVolatile = false;
}
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index 427ab5f4cbc8..9601e9ae9a27 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -69,6 +69,9 @@ namespace CodeGen {
/// depend on the ABI.
unsigned EffectiveCallingConvention;
+ /// Whether this function is noreturn.
+ bool NoReturn;
+
unsigned NumArgs;
ArgInfo *Args;
@@ -77,6 +80,7 @@ namespace CodeGen {
typedef ArgInfo *arg_iterator;
CGFunctionInfo(unsigned CallingConvention,
+ bool NoReturn,
QualType ResTy,
const llvm::SmallVector<QualType, 16> &ArgTys);
~CGFunctionInfo() { delete[] Args; }
@@ -88,6 +92,8 @@ namespace CodeGen {
unsigned arg_size() const { return NumArgs; }
+ bool isNoReturn() const { return NoReturn; }
+
/// getCallingConvention - Return the user specified calling
/// convention.
unsigned getCallingConvention() const { return CallingConvention; }
@@ -108,6 +114,7 @@ namespace CodeGen {
void Profile(llvm::FoldingSetNodeID &ID) {
ID.AddInteger(getCallingConvention());
+ ID.AddBoolean(NoReturn);
getReturnType().Profile(ID);
for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it)
it->type.Profile(ID);
@@ -115,10 +122,12 @@ namespace CodeGen {
template<class Iterator>
static void Profile(llvm::FoldingSetNodeID &ID,
unsigned CallingConvention,
+ bool NoReturn,
QualType ResTy,
Iterator begin,
Iterator end) {
ID.AddInteger(CallingConvention);
+ ID.AddBoolean(NoReturn);
ResTy.Profile(ID);
for (; begin != end; ++begin)
begin->Profile(ID);
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index a822ca2b7417..fa5a47f31564 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -19,11 +19,11 @@ using namespace clang;
using namespace CodeGen;
static uint64_t
-ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths,
+ComputeNonVirtualBaseClassOffset(ASTContext &Context,
+ const CXXBasePath &Path,
unsigned Start) {
uint64_t Offset = 0;
- const CXXBasePath &Path = Paths.front();
for (unsigned i = Start, e = Path.size(); i != e; ++i) {
const CXXBasePathElement& Element = Path[i];
@@ -44,20 +44,21 @@ ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths,
}
llvm::Constant *
-CodeGenModule::GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl) {
- if (ClassDecl == BaseClassDecl)
+CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *Class,
+ const CXXRecordDecl *BaseClass) {
+ if (Class == BaseClass)
return 0;
CXXBasePaths Paths(/*FindAmbiguities=*/false,
/*RecordPaths=*/true, /*DetectVirtual=*/false);
- if (!const_cast<CXXRecordDecl *>(ClassDecl)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
+ if (!const_cast<CXXRecordDecl *>(Class)->
+ isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClass), Paths)) {
assert(false && "Class must be derived from the passed in base class!");
return 0;
}
- uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(), Paths, 0);
+ uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(),
+ Paths.front(), 0);
if (!Offset)
return 0;
@@ -67,51 +68,6 @@ CodeGenModule::GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl,
return llvm::ConstantInt::get(PtrDiffTy, Offset);
}
-static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF,
- llvm::Value *BaseValue,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl) {
- CXXBasePaths Paths(/*FindAmbiguities=*/false,
- /*RecordPaths=*/true, /*DetectVirtual=*/false);
- if (!const_cast<CXXRecordDecl *>(ClassDecl)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
- assert(false && "Class must be derived from the passed in base class!");
- return 0;
- }
-
- unsigned Start = 0;
- llvm::Value *VirtualOffset = 0;
-
- const CXXBasePath &Path = Paths.front();
- const CXXRecordDecl *VBase = 0;
- for (unsigned i = 0, e = Path.size(); i != e; ++i) {
- const CXXBasePathElement& Element = Path[i];
- if (Element.Base->isVirtual()) {
- Start = i+1;
- QualType VBaseType = Element.Base->getType();
- VBase = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
- }
- }
- if (VBase)
- VirtualOffset =
- CGF.GetVirtualCXXBaseClassOffset(BaseValue, ClassDecl, VBase);
-
- uint64_t Offset =
- ComputeNonVirtualBaseClassOffset(CGF.getContext(), Paths, Start);
-
- if (!Offset)
- return VirtualOffset;
-
- const llvm::Type *PtrDiffTy =
- CGF.ConvertType(CGF.getContext().getPointerDiffType());
- llvm::Value *NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset);
-
- if (VirtualOffset)
- return CGF.Builder.CreateAdd(VirtualOffset, NonVirtualOffset);
-
- return NonVirtualOffset;
-}
-
// FIXME: This probably belongs in CGVtable, but it relies on
// the static function ComputeNonVirtualBaseClassOffset, so we should make that
// a CodeGenModule member function as well.
@@ -144,25 +100,91 @@ CodeGenModule::ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl,
getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl);
uint64_t Offset =
- ComputeNonVirtualBaseClassOffset(getContext(), Paths, Start);
+ ComputeNonVirtualBaseClassOffset(getContext(), Paths.front(), Start);
return ThunkAdjustment(Offset, VirtualOffset);
}
+/// Gets the address of a virtual base class within a complete object.
+/// This should only be used for (1) non-virtual bases or (2) virtual bases
+/// when the type is known to be complete (e.g. in complete destructors).
+///
+/// The object pointed to by 'This' is assumed to be non-null.
+llvm::Value *
+CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This,
+ bool isBaseVirtual,
+ const CXXRecordDecl *Derived,
+ const CXXRecordDecl *Base) {
+ // 'this' must be a pointer (in some address space) to Derived.
+ assert(This->getType()->isPointerTy() &&
+ cast<llvm::PointerType>(This->getType())->getElementType()
+ == ConvertType(Derived));
+
+ // Compute the offset of the virtual base.
+ uint64_t Offset;
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived);
+ if (isBaseVirtual)
+ Offset = Layout.getVBaseClassOffset(Base);
+ else
+ Offset = Layout.getBaseClassOffset(Base);
+
+ // Shift and cast down to the base type.
+ // TODO: for complete types, this should be possible with a GEP.
+ llvm::Value *V = This;
+ if (Offset) {
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
+ V = Builder.CreateBitCast(V, Int8PtrTy);
+ V = Builder.CreateConstInBoundsGEP1_64(V, Offset / 8);
+ }
+ V = Builder.CreateBitCast(V, ConvertType(Base)->getPointerTo());
+
+ return V;
+}
+
llvm::Value *
CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl,
+ const CXXRecordDecl *Class,
+ const CXXRecordDecl *BaseClass,
bool NullCheckValue) {
QualType BTy =
getContext().getCanonicalType(
- getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
+ getContext().getTypeDeclType(BaseClass));
const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy));
- if (ClassDecl == BaseClassDecl) {
+ if (Class == BaseClass) {
// Just cast back.
return Builder.CreateBitCast(Value, BasePtrTy);
}
+
+ CXXBasePaths Paths(/*FindAmbiguities=*/false,
+ /*RecordPaths=*/true, /*DetectVirtual=*/false);
+ if (!const_cast<CXXRecordDecl *>(Class)->
+ isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClass), Paths)) {
+ assert(false && "Class must be derived from the passed in base class!");
+ return 0;
+ }
+
+ unsigned Start = 0;
+ llvm::Value *VirtualOffset = 0;
+
+ const CXXBasePath &Path = Paths.front();
+ const CXXRecordDecl *VBase = 0;
+ for (unsigned i = 0, e = Path.size(); i != e; ++i) {
+ const CXXBasePathElement& Element = Path[i];
+ if (Element.Base->isVirtual()) {
+ Start = i+1;
+ QualType VBaseType = Element.Base->getType();
+ VBase = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
+ }
+ }
+
+ uint64_t Offset =
+ ComputeNonVirtualBaseClassOffset(getContext(), Paths.front(), Start);
+ if (!Offset && !VBase) {
+ // Just cast back.
+ return Builder.CreateBitCast(Value, BasePtrTy);
+ }
+
llvm::BasicBlock *CastNull = 0;
llvm::BasicBlock *CastNotNull = 0;
llvm::BasicBlock *CastEnd = 0;
@@ -179,16 +201,27 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
EmitBlock(CastNotNull);
}
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ if (VBase)
+ VirtualOffset = GetVirtualBaseClassOffset(Value, Class, VBase);
- llvm::Value *Offset =
- GetCXXBaseClassOffset(*this, Value, ClassDecl, BaseClassDecl);
+ const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
+ llvm::Value *NonVirtualOffset = 0;
+ if (Offset)
+ NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset);
- if (Offset) {
- // Apply the offset.
- Value = Builder.CreateBitCast(Value, Int8PtrTy);
- Value = Builder.CreateGEP(Value, Offset, "add.ptr");
- }
+ llvm::Value *BaseOffset;
+ if (VBase) {
+ if (NonVirtualOffset)
+ BaseOffset = Builder.CreateAdd(VirtualOffset, NonVirtualOffset);
+ else
+ BaseOffset = VirtualOffset;
+ } else
+ BaseOffset = NonVirtualOffset;
+
+ // Apply the base offset.
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
+ Value = Builder.CreateBitCast(Value, Int8PtrTy);
+ Value = Builder.CreateGEP(Value, BaseOffset, "add.ptr");
// Cast back.
Value = Builder.CreateBitCast(Value, BasePtrTy);
@@ -212,19 +245,27 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
llvm::Value *
CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *DerivedClassDecl,
+ const CXXRecordDecl *Class,
+ const CXXRecordDecl *DerivedClass,
bool NullCheckValue) {
QualType DerivedTy =
getContext().getCanonicalType(
- getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(DerivedClassDecl)));
+ getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(DerivedClass)));
const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
- if (ClassDecl == DerivedClassDecl) {
+ if (Class == DerivedClass) {
// Just cast back.
return Builder.CreateBitCast(Value, DerivedPtrTy);
}
+ llvm::Value *NonVirtualOffset =
+ CGM.GetNonVirtualBaseClassOffset(DerivedClass, Class);
+
+ if (!NonVirtualOffset) {
+ // No offset, we can just cast back.
+ return Builder.CreateBitCast(Value, DerivedPtrTy);
+ }
+
llvm::BasicBlock *CastNull = 0;
llvm::BasicBlock *CastNotNull = 0;
llvm::BasicBlock *CastEnd = 0;
@@ -241,17 +282,13 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
EmitBlock(CastNotNull);
}
- llvm::Value *Offset = GetCXXBaseClassOffset(*this, Value, DerivedClassDecl,
- ClassDecl);
- if (Offset) {
- // Apply the offset.
- Value = Builder.CreatePtrToInt(Value, Offset->getType());
- Value = Builder.CreateSub(Value, Offset);
- Value = Builder.CreateIntToPtr(Value, DerivedPtrTy);
- } else {
- // Just cast.
- Value = Builder.CreateBitCast(Value, DerivedPtrTy);
- }
+ // Apply the offset.
+ Value = Builder.CreatePtrToInt(Value, NonVirtualOffset->getType());
+ Value = Builder.CreateSub(Value, NonVirtualOffset);
+ Value = Builder.CreateIntToPtr(Value, DerivedPtrTy);
+
+ // Just cast.
+ Value = Builder.CreateBitCast(Value, DerivedPtrTy);
if (NullCheckValue) {
Builder.CreateBr(CastEnd);
@@ -327,9 +364,9 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
// Push the Src ptr.
CallArgs.push_back(std::make_pair(RValue::get(Src),
BaseCopyCtor->getParamDecl(0)->getType()));
- QualType ResultType =
- BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType();
- EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ const FunctionProtoType *FPT
+ = BaseCopyCtor->getType()->getAs<FunctionProtoType>();
+ EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor);
}
EmitBlock(ContinueBlock);
@@ -412,8 +449,7 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) :
RValue::getAggregate(Src);
CallArgs.push_back(std::make_pair(SrcValue, SrcTy));
- QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
- EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
Callee, ReturnValueSlot(), CallArgs, MD);
}
EmitBlock(ContinueBlock);
@@ -503,9 +539,9 @@ void CodeGenFunction::EmitClassMemberwiseCopy(
// Push the Src ptr.
CallArgs.push_back(std::make_pair(RValue::get(Src),
BaseCopyCtor->getParamDecl(0)->getType()));
- QualType ResultType =
- BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType();
- EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ const FunctionProtoType *FPT =
+ BaseCopyCtor->getType()->getAs<FunctionProtoType>();
+ EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor);
}
}
@@ -550,9 +586,7 @@ void CodeGenFunction::EmitClassCopyAssignment(
RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) :
RValue::getAggregate(Src);
CallArgs.push_back(std::make_pair(SrcValue, SrcTy));
- QualType ResultType =
- MD->getType()->getAs<FunctionType>()->getResultType();
- EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
Callee, ReturnValueSlot(), CallArgs, MD);
}
@@ -629,8 +663,8 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
- LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0);
+ LValue LHS = EmitLValueForField(LoadOfThis, Field, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, Field, 0);
if (Array) {
const llvm::Type *BasePtr = ConvertType(FieldType);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
@@ -647,26 +681,9 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
continue;
}
- if (Field->getType()->isReferenceType()) {
- unsigned FieldIndex = CGM.getTypes().getLLVMFieldNo(Field);
-
- llvm::Value *LHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex,
- "lhs.ref");
-
- llvm::Value *RHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex,
- "rhs.ref");
-
- // Load the value in RHS.
- RHS = Builder.CreateLoad(RHS);
-
- // And store it in the LHS
- Builder.CreateStore(RHS, LHS);
-
- continue;
- }
// Do a built-in assignment of scalar data members.
- LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0);
+ LValue LHS = EmitLValueForFieldInitialization(LoadOfThis, Field, 0);
+ LValue RHS = EmitLValueForFieldInitialization(LoadOfSrc, Field, 0);
if (!hasAggregateLLVMType(Field->getType())) {
RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType());
@@ -745,8 +762,8 @@ void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD,
if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
- LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
+ LValue LHS = EmitLValueForField(LoadOfThis, *Field, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, *Field, 0);
if (Array) {
const llvm::Type *BasePtr = ConvertType(FieldType);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
@@ -763,8 +780,8 @@ void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD,
continue;
}
// Do a built-in assignment of scalar data members.
- LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
+ LValue LHS = EmitLValueForField(LoadOfThis, *Field, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, *Field, 0);
if (!hasAggregateLLVMType(Field->getType())) {
RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType());
EmitStoreThroughLValue(RVRHS, LHS, Field->getType());
@@ -810,29 +827,21 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
if (CtorType == Ctor_Base && isBaseVirtual)
return;
- // Compute the offset to the base; we do this directly instead of using
- // GetAddressOfBaseClass because the class doesn't have a vtable pointer
- // at this point.
- // FIXME: This could be refactored back into GetAddressOfBaseClass if it took
- // an extra parameter for whether the derived class is the complete object
- // class.
- const ASTRecordLayout &Layout =
- CGF.getContext().getASTRecordLayout(ClassDecl);
- uint64_t Offset;
- if (isBaseVirtual)
- Offset = Layout.getVBaseClassOffset(BaseClassDecl);
- else
- Offset = Layout.getBaseClassOffset(BaseClassDecl);
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- const llvm::Type *BaseClassType = CGF.ConvertType(QualType(BaseType, 0));
- llvm::Value *V = CGF.Builder.CreateBitCast(ThisPtr, Int8PtrTy);
- V = CGF.Builder.CreateConstInBoundsGEP1_64(V, Offset/8);
- V = CGF.Builder.CreateBitCast(V, BaseClassType->getPointerTo());
-
- CGF.EmitCXXConstructorCall(BaseInit->getConstructor(),
- Ctor_Base, V,
- BaseInit->const_arg_begin(),
- BaseInit->const_arg_end());
+ // We can pretend to be a complete class because it only matters for
+ // virtual bases, and we only do virtual bases for complete ctors.
+ llvm::Value *V = ThisPtr;
+ V = CGF.GetAddressOfBaseOfCompleteClass(V, isBaseVirtual,
+ ClassDecl, BaseClassDecl);
+
+ CGF.EmitAggExpr(BaseInit->getInit(), V, false, false, true);
+
+ if (CGF.Exceptions && !BaseClassDecl->hasTrivialDestructor()) {
+ // FIXME: Is this OK for C++0x delegating constructors?
+ CodeGenFunction::EHCleanupBlock Cleanup(CGF);
+
+ CXXDestructorDecl *DD = BaseClassDecl->getDestructor(CGF.getContext());
+ CGF.EmitCXXDestructorCall(DD, Dtor_Base, V);
+ }
}
static void EmitMemberInitializer(CodeGenFunction &CGF,
@@ -846,91 +855,62 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
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);
- }
-
+ LValue LHS = CGF.EmitLValueForFieldInitialization(ThisPtr, Field, 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);
+ LHS = CGF.EmitLValueForField(LHS.getAddress(), Field, 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,
- MemberInit->const_arg_begin(),
- MemberInit->const_arg_end());
- }
- 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();
+ // FIXME: If there's no initializer and the CXXBaseOrMemberInitializer
+ // was implicitly generated, we shouldn't be zeroing memory.
RValue RHS;
if (FieldType->isReferenceType()) {
- RHS = CGF.EmitReferenceBindingToExpr(RhsExpr, FieldType,
- /*IsInitializer=*/true);
+ RHS = CGF.EmitReferenceBindingToExpr(MemberInit->getInit(),
+ /*IsInitializer=*/true);
CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
- } else if (Array) {
+ } else if (FieldType->isArrayType() && !MemberInit->getInit()) {
CGF.EmitMemSetToZero(LHS.getAddress(), Field->getType());
- } else if (!CGF.hasAggregateLLVMType(RhsExpr->getType())) {
- RHS = RValue::get(CGF.EmitScalarExpr(RhsExpr, true));
+ } else if (!CGF.hasAggregateLLVMType(Field->getType())) {
+ RHS = RValue::get(CGF.EmitScalarExpr(MemberInit->getInit(), true));
CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
- } else if (RhsExpr->getType()->isAnyComplexType()) {
- CGF.EmitComplexExprIntoAddr(RhsExpr, LHS.getAddress(),
+ } else if (MemberInit->getInit()->getType()->isAnyComplexType()) {
+ CGF.EmitComplexExprIntoAddr(MemberInit->getInit(), LHS.getAddress(),
LHS.isVolatileQualified());
} else {
- // Handle member function pointers; other aggregates shouldn't get this far.
- CGF.EmitAggExpr(RhsExpr, LHS.getAddress(), LHS.isVolatileQualified());
+ CGF.EmitAggExpr(MemberInit->getInit(), LHS.getAddress(),
+ LHS.isVolatileQualified(), false, true);
+
+ if (!CGF.Exceptions)
+ return;
+
+ const RecordType *RT = FieldType->getAs<RecordType>();
+ if (!RT)
+ return;
+
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD->hasTrivialDestructor()) {
+ // FIXME: Is this OK for C++0x delegating constructors?
+ CodeGenFunction::EHCleanupBlock Cleanup(CGF);
+
+ llvm::Value *ThisPtr = CGF.LoadCXXThis();
+ LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, 0);
+
+ CXXDestructorDecl *DD = RD->getDestructor(CGF.getContext());
+ CGF.EmitCXXDestructorCall(DD, Dtor_Complete, LHS.getAddress());
+ }
}
}
/// 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 = CD->getParent();
+
+ llvm::SmallVector<CXXBaseOrMemberInitializer *, 8> MemberInitializers;
// FIXME: Add vbase initialization
@@ -945,14 +925,17 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
if (Member->isBaseInitializer())
EmitBaseInitializer(*this, ClassDecl, Member, CtorType);
else
- EmitMemberInitializer(*this, ClassDecl, Member);
-
- // Pop any live temporaries that the initializers might have pushed.
- while (!LiveTemporaries.empty())
- PopCXXTemporary();
+ MemberInitializers.push_back(Member);
}
InitializeVtablePtrs(ClassDecl);
+
+ for (unsigned I = 0, E = MemberInitializers.size(); I != E; ++I) {
+ assert(LiveTemporaries.empty() &&
+ "Should not have any live temporaries at initializer start!");
+
+ EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I]);
+ }
}
/// EmitDtorEpilogue - Emit all code that comes at the end of class's
@@ -1002,7 +985,6 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
llvm::Value *ThisPtr = LoadCXXThis();
LValue LHS = EmitLValueForField(ThisPtr, Field,
- /*isUnion=*/false,
// FIXME: Qualifiers?
/*CVRQualifiers=*/0);
if (Array) {
@@ -1050,15 +1032,16 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); I != E; ++I) {
const CXXBaseSpecifier &Base = *I;
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
// Ignore trivial destructors.
if (BaseClassDecl->hasTrivialDestructor())
continue;
const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
- llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(),
- ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
+ llvm::Value *V = GetAddressOfBaseOfCompleteClass(LoadCXXThis(),
+ true,
+ ClassDecl,
+ BaseClassDecl);
EmitCXXDestructorCall(D, Dtor_Base, V);
}
@@ -1080,7 +1063,7 @@ void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor,
StartFunction(GlobalDecl(Dtor, DtorType), Dtor->getResultType(), Fn, Args,
SourceLocation());
-
+ InitializeVtablePtrs(Dtor->getParent());
EmitDtorEpilogue(Dtor, DtorType);
FinishFunction();
}
@@ -1263,7 +1246,8 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
llvm::SmallString<16> Name;
llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount);
QualType R = getContext().VoidTy;
- const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args);
+ const CGFunctionInfo &FI
+ = CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
@@ -1295,20 +1279,21 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
- if (D->isCopyConstructor()) {
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D->getDeclContext());
- if (ClassDecl->hasTrivialCopyConstructor()) {
- assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
- "EmitCXXConstructorCall - user declared copy constructor");
- const Expr *E = (*ArgBeg);
- QualType Ty = E->getType();
- llvm::Value *Src = EmitLValue(E).getAddress();
- EmitAggregateCopy(This, Src, Ty);
+ if (D->isTrivial()) {
+ if (ArgBeg == ArgEnd) {
+ // Trivial default constructor, no codegen required.
+ assert(D->isDefaultConstructor() &&
+ "trivial 0-arg ctor not a default ctor");
return;
}
- } else if (D->isTrivial()) {
- // FIXME: Track down why we're trying to generate calls to the trivial
- // default constructor!
+
+ assert(ArgBeg + 1 == ArgEnd && "unexpected argcount for trivial ctor");
+ assert(D->isCopyConstructor() && "trivial 1-arg ctor not a copy ctor");
+
+ const Expr *E = (*ArgBeg);
+ QualType Ty = E->getType();
+ llvm::Value *Src = EmitLValue(E).getAddress();
+ EmitAggregateCopy(This, Src, Ty);
return;
}
@@ -1328,8 +1313,8 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
}
llvm::Value *
-CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This,
- const CXXRecordDecl *ClassDecl,
+CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This,
+ const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl) {
const llvm::Type *Int8PtrTy =
llvm::Type::getInt8Ty(VMContext)->getPointerTo();
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 1ffad3edcac7..5b9c6b055e0e 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -49,19 +49,21 @@ void CGDebugInfo::setLocation(SourceLocation Loc) {
CurLoc = CGM.getContext().getSourceManager().getInstantiationLoc(Loc);
}
-/// getContext - Get context info for the decl.
-llvm::DIDescriptor CGDebugInfo::getContext(const VarDecl *Decl,
- llvm::DIDescriptor &CompileUnit) {
- if (Decl->isFileVarDecl())
+/// getContextDescriptor - Get context info for the decl.
+llvm::DIDescriptor CGDebugInfo::getContextDescriptor(const Decl *Context,
+ llvm::DIDescriptor &CompileUnit) {
+ if (!Context)
return CompileUnit;
- 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]);
- if (R.isSubprogram())
- return R;
- }
- }
+
+ llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator
+ I = RegionMap.find(Context);
+ if (I != RegionMap.end())
+ return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(I->second));
+
+ // Check namespace.
+ if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context))
+ return llvm::DIDescriptor(getOrCreateNameSpace(NSDecl, CompileUnit));
+
return CompileUnit;
}
@@ -78,10 +80,9 @@ llvm::StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
std::string NS = FD->getNameAsString();
// Copy this name on the side and use its reference.
- unsigned Length = NS.length() + 1;
- char *StrPtr = FunctionNames.Allocate<char>(Length);
- strncpy(StrPtr, NS.c_str(), Length);
- return llvm::StringRef(StrPtr);
+ char *StrPtr = DebugInfoNames.Allocate<char>(NS.length());
+ memcpy(StrPtr, NS.data(), NS.length());
+ return llvm::StringRef(StrPtr, NS.length());
}
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a new
@@ -90,16 +91,15 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
// Get source file information.
const char *FileName = "<unknown>";
SourceManager &SM = CGM.getContext().getSourceManager();
- unsigned FID = 0;
if (Loc.isValid()) {
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
FileName = PLoc.getFilename();
- FID = PLoc.getIncludeLoc().getRawEncoding();
- }
+ unsigned FID = PLoc.getIncludeLoc().getRawEncoding();
- // See if this compile unit has been used before.
- llvm::DICompileUnit &Unit = CompileUnitCache[FID];
- if (!Unit.isNull()) return Unit;
+ // See if this compile unit has been used before for this valid location.
+ llvm::DICompileUnit &Unit = CompileUnitCache[FID];
+ if (!Unit.isNull()) return Unit;
+ }
// Get absolute path name.
llvm::sys::Path AbsFileName(FileName);
@@ -149,9 +149,16 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
RuntimeVers = LO.ObjCNonFragileABI ? 2 : 1;
// Create new compile unit.
- return Unit = DebugFactory.CreateCompileUnit(
+ llvm::DICompileUnit Unit = DebugFactory.CreateCompileUnit(
LangTag, AbsFileName.getLast(), AbsFileName.getDirname(), Producer, isMain,
LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers);
+
+ if (Loc.isValid()) {
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+ unsigned FID = PLoc.getIncludeLoc().getRawEncoding();
+ CompileUnitCache[FID] = Unit;
+ }
+ return Unit;
}
/// CreateType - Get the Basic type from the cache or create a new
@@ -419,17 +426,18 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
// We don't set size information, but do specify where the typedef was
// declared.
- SourceLocation DefLoc = Ty->getDecl()->getLocation();
- llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc);
-
SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(DefLoc);
+ PresumedLoc PLoc = SM.getPresumedLoc(Ty->getDecl()->getLocation());
unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine();
+ llvm::DIDescriptor TyContext
+ = getContextDescriptor(dyn_cast<Decl>(Ty->getDecl()->getDeclContext()),
+ Unit);
llvm::DIType DbgTy =
- DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_typedef, Unit,
- Ty->getDecl()->getName(),
- DefUnit, Line, 0, 0, 0, 0, Src);
+ DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_typedef,
+ TyContext,
+ Ty->getDecl()->getName(), Unit,
+ Line, 0, 0, 0, 0, Src);
return DbgTy;
}
@@ -463,22 +471,21 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
/// CollectRecordFields - A helper function to collect debug info for
/// record fields. This is used while creating debug info entry for a Record.
void CGDebugInfo::
-CollectRecordFields(const RecordDecl *Decl,
- llvm::DICompileUnit Unit,
+CollectRecordFields(const RecordDecl *RD, llvm::DICompileUnit Unit,
llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys) {
unsigned FieldNo = 0;
SourceManager &SM = CGM.getContext().getSourceManager();
- const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(Decl);
- for (RecordDecl::field_iterator I = Decl->field_begin(),
- E = Decl->field_end();
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+ for (RecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end();
I != E; ++I, ++FieldNo) {
FieldDecl *Field = *I;
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
llvm::StringRef FieldName = Field->getName();
- // Ignore unnamed fields.
- if (FieldName.empty())
+ // Ignore unnamed fields. Do not ignore unnamed records.
+ if (FieldName.empty() && !isa<RecordType>(Field->getType()))
continue;
// Get the location for the field.
@@ -519,87 +526,264 @@ CollectRecordFields(const RecordDecl *Decl,
}
}
+/// getOrCreateMethodType - CXXMethodDecl's type is a FunctionType. This
+/// function type is not updated to include implicit "this" pointer. Use this
+/// routine to get a method type which includes "this" pointer.
+llvm::DIType
+CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
+ llvm::DICompileUnit Unit) {
+ llvm::DIType FnTy = getOrCreateType(Method->getType(), Unit);
+
+ // Static methods do not need "this" pointer argument.
+ if (Method->isStatic())
+ return FnTy;
+
+ // Add "this" pointer.
+
+ llvm::DIArray Args = llvm::DICompositeType(FnTy.getNode()).getTypeArray();
+ assert (Args.getNumElements() && "Invalid number of arguments!");
+
+ llvm::SmallVector<llvm::DIDescriptor, 16> Elts;
+
+ // First element is always return type. For 'void' functions it is NULL.
+ Elts.push_back(Args.getElement(0));
+
+ // "this" pointer is always first argument.
+ ASTContext &Context = CGM.getContext();
+ QualType ThisPtr =
+ Context.getPointerType(Context.getTagDeclType(Method->getParent()));
+ llvm::DIType ThisPtrType =
+ DebugFactory.CreateArtificialType(getOrCreateType(ThisPtr, Unit));
+ TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType.getNode();
+ Elts.push_back(ThisPtrType);
+
+ // Copy rest of the arguments.
+ for (unsigned i = 1, e = Args.getNumElements(); i != e; ++i)
+ Elts.push_back(Args.getElement(i));
+
+ llvm::DIArray EltTypeArray =
+ DebugFactory.GetOrCreateArray(Elts.data(), Elts.size());
+
+ return
+ DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_subroutine_type,
+ Unit, "", llvm::DICompileUnit(),
+ 0, 0, 0, 0, 0,
+ llvm::DIType(), EltTypeArray);
+}
+
+/// CreateCXXMemberFunction - A helper function to create a DISubprogram for
+/// a single member function GlobalDecl.
+llvm::DISubprogram
+CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
+ llvm::DICompileUnit Unit,
+ llvm::DICompositeType &RecordTy) {
+ bool IsCtorOrDtor =
+ isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
+
+ llvm::StringRef MethodName = getFunctionName(Method);
+ llvm::StringRef MethodLinkageName;
+ llvm::DIType MethodTy = getOrCreateMethodType(Method, Unit);
+
+ // Since a single ctor/dtor corresponds to multiple functions, it doesn't
+ // make sense to give a single ctor/dtor a linkage name.
+ if (!IsCtorOrDtor)
+ MethodLinkageName = CGM.getMangledName(Method);
+
+ SourceManager &SM = CGM.getContext().getSourceManager();
+
+ // Get the location for the method.
+ SourceLocation MethodDefLoc = Method->getLocation();
+ PresumedLoc PLoc = SM.getPresumedLoc(MethodDefLoc);
+ llvm::DICompileUnit MethodDefUnit;
+ unsigned MethodLine = 0;
+
+ if (!PLoc.isInvalid()) {
+ MethodDefUnit = getOrCreateCompileUnit(MethodDefLoc);
+ MethodLine = PLoc.getLine();
+ }
+
+ // Collect virtual method info.
+ llvm::DIType ContainingType;
+ unsigned Virtuality = 0;
+ unsigned VIndex = 0;
+
+ if (Method->isVirtual()) {
+ if (Method->isPure())
+ Virtuality = llvm::dwarf::DW_VIRTUALITY_pure_virtual;
+ else
+ Virtuality = llvm::dwarf::DW_VIRTUALITY_virtual;
+
+ // It doesn't make sense to give a virtual destructor a vtable index,
+ // since a single destructor has two entries in the vtable.
+ if (!isa<CXXDestructorDecl>(Method))
+ VIndex = CGM.getVtableInfo().getMethodVtableIndex(Method);
+ ContainingType = RecordTy;
+ }
+
+ llvm::DISubprogram SP =
+ DebugFactory.CreateSubprogram(RecordTy , MethodName, MethodName,
+ MethodLinkageName,
+ MethodDefUnit, MethodLine,
+ MethodTy, /*isLocalToUnit=*/false,
+ Method->isThisDeclarationADefinition(),
+ Virtuality, VIndex, ContainingType);
+
+ // Don't cache ctors or dtors since we have to emit multiple functions for
+ // a single ctor or dtor.
+ if (!IsCtorOrDtor && Method->isThisDeclarationADefinition())
+ SPCache[Method] = llvm::WeakVH(SP.getNode());
+
+ return SP;
+}
+
/// CollectCXXMemberFunctions - A helper function to collect debug info for
/// C++ member functions.This is used while creating debug info entry for
/// a Record.
void CGDebugInfo::
-CollectCXXMemberFunctions(const CXXRecordDecl *Decl,
- llvm::DICompileUnit Unit,
+CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DICompileUnit Unit,
llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys,
llvm::DICompositeType &RecordTy) {
- SourceManager &SM = CGM.getContext().getSourceManager();
- for(CXXRecordDecl::method_iterator I = Decl->method_begin(),
- E = Decl->method_end(); I != E; ++I) {
- CXXMethodDecl *Method = *I;
- llvm::StringRef MethodName;
- llvm::StringRef MethodLinkageName;
- llvm::DIType MethodTy = getOrCreateType(Method->getType(), Unit);
- if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(Method)) {
- if (CDecl->isImplicit())
- continue;
- MethodName = Decl->getName();
- // FIXME : Find linkage name.
- } else if (CXXDestructorDecl *DDecl = dyn_cast<CXXDestructorDecl>(Method)) {
- if (DDecl->isImplicit())
- continue;
- MethodName = getFunctionName(Method);
- // FIXME : Find linkage name.
- } else {
- if (Method->isImplicit())
- continue;
- // regular method
- MethodName = getFunctionName(Method);
- MethodLinkageName = CGM.getMangledName(Method);
- }
-
- // Get the location for the method.
- SourceLocation MethodDefLoc = Method->getLocation();
- PresumedLoc PLoc = SM.getPresumedLoc(MethodDefLoc);
- llvm::DICompileUnit MethodDefUnit;
- unsigned MethodLine = 0;
-
- if (!PLoc.isInvalid()) {
- MethodDefUnit = getOrCreateCompileUnit(MethodDefLoc);
- MethodLine = PLoc.getLine();
- }
+ for(CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ const CXXMethodDecl *Method = *I;
+
+ if (Method->isImplicit() && !Method->isUsed())
+ continue;
- llvm::DISubprogram SP =
- DebugFactory.CreateSubprogram(RecordTy , MethodName, MethodName,
- MethodLinkageName,
- MethodDefUnit, MethodLine,
- MethodTy, false,
- Method->isThisDeclarationADefinition(),
- 0 /*Virtuality*/, 0 /*VIndex*/,
- llvm::DIType() /*ContainingType*/);
- if (Method->isThisDeclarationADefinition())
- SPCache[cast<FunctionDecl>(Method)] = llvm::WeakVH(SP.getNode());
- EltTys.push_back(SP);
+ EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy));
}
}
+/// CollectCXXBases - A helper function to collect debug info for
+/// C++ base classes. This is used while creating debug info entry for
+/// a Record.
+void CGDebugInfo::
+CollectCXXBases(const CXXRecordDecl *RD, llvm::DICompileUnit Unit,
+ llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys,
+ llvm::DICompositeType &RecordTy) {
+
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+ for (CXXRecordDecl::base_class_const_iterator BI = RD->bases_begin(),
+ BE = RD->bases_end(); BI != BE; ++BI) {
+ unsigned BFlags = 0;
+ uint64_t BaseOffset;
+
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(BI->getType()->getAs<RecordType>()->getDecl());
+
+ if (BI->isVirtual()) {
+ // virtual base offset index is -ve. The code generator emits dwarf
+ // expression where it expects +ve number.
+ BaseOffset = 0 - CGM.getVtableInfo().getVirtualBaseOffsetIndex(RD, Base);
+ BFlags = llvm::DIType::FlagVirtual;
+ } else
+ BaseOffset = RL.getBaseClassOffset(Base);
+
+ AccessSpecifier Access = BI->getAccessSpecifier();
+ if (Access == clang::AS_private)
+ BFlags |= llvm::DIType::FlagPrivate;
+ else if (Access == clang::AS_protected)
+ BFlags |= llvm::DIType::FlagProtected;
+
+ llvm::DIType DTy =
+ DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_inheritance,
+ RecordTy, llvm::StringRef(),
+ llvm::DICompileUnit(), 0, 0, 0,
+ BaseOffset, BFlags,
+ getOrCreateType(BI->getType(),
+ Unit));
+ EltTys.push_back(DTy);
+ }
+}
+
+/// getOrCreateVTablePtrType - Return debug info descriptor for vtable.
+llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DICompileUnit Unit) {
+ if (!VTablePtrType.isNull())
+ return VTablePtrType;
+
+ ASTContext &Context = CGM.getContext();
+
+ /* Function type */
+ llvm::SmallVector<llvm::DIDescriptor, 16> STys;
+ STys.push_back(getOrCreateType(Context.IntTy, Unit));
+ llvm::DIArray SElements =
+ DebugFactory.GetOrCreateArray(STys.data(), STys.size());
+ llvm::DIType SubTy =
+ DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_subroutine_type,
+ Unit, "", llvm::DICompileUnit(),
+ 0, 0, 0, 0, 0, llvm::DIType(), SElements);
+
+ unsigned Size = Context.getTypeSize(Context.VoidPtrTy);
+ llvm::DIType vtbl_ptr_type
+ = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type,
+ Unit, "__vtbl_ptr_type", llvm::DICompileUnit(),
+ 0, Size, 0, 0, 0, SubTy);
+
+ VTablePtrType = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type,
+ Unit, "", llvm::DICompileUnit(),
+ 0, Size, 0, 0, 0, vtbl_ptr_type);
+ return VTablePtrType;
+}
+
+/// getVtableName - Get vtable name for the given Class.
+llvm::StringRef CGDebugInfo::getVtableName(const CXXRecordDecl *RD) {
+ // Otherwise construct gdb compatible name name.
+ std::string Name = "_vptr$" + RD->getNameAsString();
+
+ // Copy this name on the side and use its reference.
+ char *StrPtr = DebugInfoNames.Allocate<char>(Name.length());
+ memcpy(StrPtr, Name.data(), Name.length());
+ return llvm::StringRef(StrPtr, Name.length());
+}
+
+
+/// CollectVtableInfo - If the C++ class has vtable info then insert appropriate
+/// debug info entry in EltTys vector.
+void CGDebugInfo::
+CollectVtableInfo(const CXXRecordDecl *RD, llvm::DICompileUnit Unit,
+ llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys) {
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+
+ // If there is a primary base then it will hold vtable info.
+ if (RL.getPrimaryBase())
+ return;
+
+ // If this class is not dynamic then there is not any vtable info to collect.
+ if (!RD->isDynamicClass())
+ return;
+
+ unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
+ llvm::DIType VPTR
+ = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ getVtableName(RD), llvm::DICompileUnit(),
+ 0, Size, 0, 0, 0,
+ getOrCreateVTablePtrType(Unit));
+ EltTys.push_back(VPTR);
+}
+
/// CreateType - get structure or union type.
llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
llvm::DICompileUnit Unit) {
- RecordDecl *Decl = Ty->getDecl();
+ RecordDecl *RD = Ty->getDecl();
unsigned Tag;
- if (Decl->isStruct())
+ if (RD->isStruct())
Tag = llvm::dwarf::DW_TAG_structure_type;
- else if (Decl->isUnion())
+ else if (RD->isUnion())
Tag = llvm::dwarf::DW_TAG_union_type;
else {
- assert(Decl->isClass() && "Unknown RecordType!");
+ assert(RD->isClass() && "Unknown RecordType!");
Tag = llvm::dwarf::DW_TAG_class_type;
}
SourceManager &SM = CGM.getContext().getSourceManager();
// Get overall information about the record type for the debug info.
- PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ PresumedLoc PLoc = SM.getPresumedLoc(RD->getLocation());
llvm::DICompileUnit DefUnit;
unsigned Line = 0;
if (!PLoc.isInvalid()) {
- DefUnit = getOrCreateCompileUnit(Decl->getLocation());
+ DefUnit = getOrCreateCompileUnit(RD->getLocation());
Line = PLoc.getLine();
}
@@ -610,19 +794,19 @@ 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.
- // A Decl->getName() is not unique. However, the debug info descriptors
- // are uniqued. The debug info descriptor describing record's context is
- // necessary to keep two Decl's descriptor unique if their name match.
- // FIXME : Use RecordDecl's DeclContext's descriptor. As a temp. step
- // use type's name in FwdDecl.
+ // A RD->getName() is not unique. However, the debug info descriptors
+ // are uniqued so use type name to ensure uniquness.
std::string STy = QualType(Ty, 0).getAsString();
+ llvm::DIDescriptor FDContext =
+ getContextDescriptor(dyn_cast<Decl>(RD->getDeclContext()), Unit);
llvm::DICompositeType FwdDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, STy.c_str(),
+ DebugFactory.CreateCompositeType(Tag, FDContext,
+ STy.c_str(),
DefUnit, Line, 0, 0, 0, 0,
llvm::DIType(), llvm::DIArray());
// If this is just a forward declaration, return it.
- if (!Decl->getDefinition(CGM.getContext()))
+ if (!RD->getDefinition())
return FwdDecl;
llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode();
@@ -633,10 +817,25 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
// Convert all the elements.
llvm::SmallVector<llvm::DIDescriptor, 16> EltTys;
- CollectRecordFields(Decl, Unit, EltTys);
- if (CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(Decl))
+ const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
+ if (CXXDecl) {
+ CollectCXXBases(CXXDecl, Unit, EltTys, FwdDecl);
+ CollectVtableInfo(CXXDecl, Unit, EltTys);
+ }
+ CollectRecordFields(RD, Unit, EltTys);
+ llvm::MDNode *ContainingType = NULL;
+ if (CXXDecl) {
CollectCXXMemberFunctions(CXXDecl, Unit, EltTys, FwdDecl);
+ // A class's primary base or the class itself contains the vtable.
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+ if (const CXXRecordDecl *PBase = RL.getPrimaryBase())
+ ContainingType =
+ getOrCreateType(QualType(PBase->getTypeForDecl(), 0), Unit).getNode();
+ else if (CXXDecl->isDynamicClass())
+ ContainingType = FwdDecl.getNode();
+ }
+
llvm::DIArray Elements =
DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
@@ -644,10 +843,14 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
+ llvm::DIDescriptor RDContext =
+ getContextDescriptor(dyn_cast<Decl>(RD->getDeclContext()), Unit);
llvm::DICompositeType RealDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(),
+ DebugFactory.CreateCompositeType(Tag, RDContext,
+ RD->getName(),
DefUnit, Line, Size, Align, 0, 0,
- llvm::DIType(), Elements);
+ llvm::DIType(), Elements,
+ 0, ContainingType);
// 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.
@@ -659,14 +862,14 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
/// CreateType - get objective-c interface type.
llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
llvm::DICompileUnit Unit) {
- ObjCInterfaceDecl *Decl = Ty->getDecl();
+ ObjCInterfaceDecl *ID = Ty->getDecl();
unsigned Tag = llvm::dwarf::DW_TAG_structure_type;
SourceManager &SM = CGM.getContext().getSourceManager();
// Get overall information about the record type for the debug info.
- llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(Decl->getLocation());
- PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(ID->getLocation());
+ PresumedLoc PLoc = SM.getPresumedLoc(ID->getLocation());
unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine();
@@ -679,13 +882,13 @@ 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, Decl->getName(),
+ DebugFactory.CreateCompositeType(Tag, Unit, ID->getName(),
DefUnit, Line, 0, 0, 0, 0,
llvm::DIType(), llvm::DIArray(),
RuntimeLang);
// If this is just a forward declaration, return it.
- if (Decl->isForwardDecl())
+ if (ID->isForwardDecl())
return FwdDecl;
llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode();
@@ -696,7 +899,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// Convert all the elements.
llvm::SmallVector<llvm::DIDescriptor, 16> EltTys;
- ObjCInterfaceDecl *SClass = Decl->getSuperClass();
+ ObjCInterfaceDecl *SClass = ID->getSuperClass();
if (SClass) {
llvm::DIType SClassTy =
getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit);
@@ -707,11 +910,11 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
EltTys.push_back(InhTag);
}
- const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(Decl);
+ const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(ID);
unsigned FieldNo = 0;
- for (ObjCInterfaceDecl::ivar_iterator I = Decl->ivar_begin(),
- E = Decl->ivar_end(); I != E; ++I, ++FieldNo) {
+ for (ObjCInterfaceDecl::ivar_iterator I = ID->ivar_begin(),
+ E = ID->ivar_end(); I != E; ++I, ++FieldNo) {
ObjCIvarDecl *Field = *I;
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
@@ -769,7 +972,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
llvm::DICompositeType RealDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), DefUnit,
+ DebugFactory.CreateCompositeType(Tag, Unit, ID->getName(), DefUnit,
Line, Size, Align, 0, 0, llvm::DIType(),
Elements, RuntimeLang);
@@ -782,13 +985,13 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
llvm::DICompileUnit Unit) {
- EnumDecl *Decl = Ty->getDecl();
+ EnumDecl *ED = Ty->getDecl();
llvm::SmallVector<llvm::DIDescriptor, 32> Enumerators;
// Create DIEnumerator elements for each enumerator.
for (EnumDecl::enumerator_iterator
- Enum = Decl->enumerator_begin(), EnumEnd = Decl->enumerator_end();
+ Enum = ED->enumerator_begin(), EnumEnd = ED->enumerator_end();
Enum != EnumEnd; ++Enum) {
Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getName(),
Enum->getInitVal().getZExtValue()));
@@ -798,7 +1001,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
llvm::DIArray EltArray =
DebugFactory.GetOrCreateArray(Enumerators.data(), Enumerators.size());
- SourceLocation DefLoc = Decl->getLocation();
+ SourceLocation DefLoc = ED->getLocation();
llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc);
SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(DefLoc);
@@ -815,7 +1018,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
llvm::DIType DbgTy =
DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_enumeration_type,
- Unit, Decl->getName(), DefUnit, Line,
+ Unit, ED->getName(), DefUnit, Line,
Size, Align, 0, 0,
llvm::DIType(), EltArray);
return DbgTy;
@@ -1083,6 +1286,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(FI->second));
if (!SP.isNull() && SP.isSubprogram() && SP.isDefinition()) {
RegionStack.push_back(SP.getNode());
+ RegionMap[D] = llvm::WeakVH(SP.getNode());
return;
}
}
@@ -1113,6 +1317,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
// Push function on region stack.
RegionStack.push_back(SP.getNode());
+ RegionMap[D] = llvm::WeakVH(SP.getNode());
}
@@ -1164,160 +1369,172 @@ void CGDebugInfo::EmitRegionEnd(llvm::Function *Fn, CGBuilderTy &Builder) {
RegionStack.pop_back();
}
-/// EmitDeclare - Emit local variable declaration debug info.
-void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
- llvm::Value *Storage, CGBuilderTy &Builder) {
- assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
-
- // 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 CodeGenOptions &CGO = CGM.getCodeGenOpts();
- if (CGO.OptimizationLevel)
- return;
-
- llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
- QualType Type = Decl->getType();
- llvm::DIType Ty = getOrCreateType(Type, Unit);
- if (Decl->hasAttr<BlocksAttr>()) {
- llvm::DICompileUnit DefUnit;
- unsigned Tag = llvm::dwarf::DW_TAG_structure_type;
+// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
+// See BuildByRefType.
+llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
+ uint64_t *XOffset) {
- llvm::SmallVector<llvm::DIDescriptor, 5> EltTys;
-
- llvm::DIType FieldTy;
+ llvm::SmallVector<llvm::DIDescriptor, 5> EltTys;
- QualType FType;
- uint64_t FieldSize, FieldOffset;
- unsigned FieldAlign;
+ QualType FType;
+ uint64_t FieldSize, FieldOffset;
+ unsigned FieldAlign;
+
+ llvm::DICompileUnit Unit = getOrCreateCompileUnit(VD->getLocation());
+ QualType Type = VD->getType();
- llvm::DIArray Elements;
- llvm::DIType EltTy;
-
- // Build up structure for the byref. See BuildByRefType.
- FieldOffset = 0;
+ FieldOffset = 0;
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
+ llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ "__isa", llvm::DICompileUnit(),
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ "__forwarding", llvm::DICompileUnit(),
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+
+ FType = CGM.getContext().IntTy;
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ "__flags", llvm::DICompileUnit(),
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+
+ FType = CGM.getContext().IntTy;
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ "__size", llvm::DICompileUnit(),
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+
+ bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type);
+ if (HasCopyAndDispose) {
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = CGM.getContext().getTypeSize(FType);
FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__isa", DefUnit,
+ "__copy_helper",
+ llvm::DICompileUnit(),
0, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
-
+
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = CGM.getContext().getTypeSize(FType);
FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__forwarding", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- FType = CGM.getContext().IntTy;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__flags", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- FType = CGM.getContext().IntTy;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__size", DefUnit,
+ "__destroy_helper",
+ llvm::DICompileUnit(),
0, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
+ }
+
+ CharUnits Align = CGM.getContext().getDeclAlign(VD);
+ if (Align > CharUnits::fromQuantity(
+ CGM.getContext().Target.getPointerAlign(0) / 8)) {
+ unsigned AlignedOffsetInBytes
+ = llvm::RoundUpToAlignment(FieldOffset/8, Align.getQuantity());
+ unsigned NumPaddingBytes
+ = AlignedOffsetInBytes - FieldOffset/8;
- bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type);
- if (HasCopyAndDispose) {
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__copy_helper", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
+ if (NumPaddingBytes > 0) {
+ llvm::APInt pad(32, NumPaddingBytes);
+ FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy,
+ pad, ArrayType::Normal, 0);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = CGM.getContext().getTypeSize(FType);
FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__destroy_helper", DefUnit,
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member,
+ Unit, "", llvm::DICompileUnit(),
0, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
}
-
- unsigned Align = CGM.getContext().getDeclAlignInBytes(Decl);
- if (Align > CGM.getContext().Target.getPointerAlign(0) / 8) {
- unsigned AlignedOffsetInBytes
- = llvm::RoundUpToAlignment(FieldOffset/8, Align);
- unsigned NumPaddingBytes
- = AlignedOffsetInBytes - FieldOffset/8;
-
- if (NumPaddingBytes > 0) {
- llvm::APInt pad(32, NumPaddingBytes);
- FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy,
- pad, ArrayType::Normal, 0);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member,
- Unit, "", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
- }
- }
-
- FType = Type;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = Align*8;
-
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- Decl->getName(), DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
-
- unsigned Flags = llvm::DIType::FlagBlockByrefStruct;
+ }
+
+ FType = Type;
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = Align.getQuantity()*8;
- Ty = DebugFactory.CreateCompositeType(Tag, Unit, "",
+ *XOffset = FieldOffset;
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ VD->getName(), llvm::DICompileUnit(),
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+
+ llvm::DIArray Elements =
+ DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
+
+ unsigned Flags = llvm::DIType::FlagBlockByrefStruct;
+
+ return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_structure_type,
+ Unit, "",
llvm::DICompileUnit(),
0, FieldOffset, 0, 0, Flags,
llvm::DIType(), Elements);
- }
+
+}
+/// EmitDeclare - Emit local variable declaration debug info.
+void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
+ llvm::Value *Storage, CGBuilderTy &Builder) {
+ assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
+
+ // 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 CodeGenOptions &CGO = CGM.getCodeGenOpts();
+ if (CGO.OptimizationLevel)
+ return;
+
+ llvm::DICompileUnit Unit = getOrCreateCompileUnit(VD->getLocation());
+ llvm::DIType Ty;
+ uint64_t XOffset = 0;
+ if (VD->hasAttr<BlocksAttr>())
+ Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset);
+ else
+ Ty = getOrCreateType(VD->getType(), Unit);
// Get location information.
SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ PresumedLoc PLoc = SM.getPresumedLoc(VD->getLocation());
unsigned Line = 0;
unsigned Column = 0;
- if (!PLoc.isInvalid()) {
+ if (PLoc.isInvalid())
+ PLoc = SM.getPresumedLoc(CurLoc);
+ if (PLoc.isValid()) {
Line = PLoc.getLine();
Column = PLoc.getColumn();
+ Unit = getOrCreateCompileUnit(CurLoc);
} else {
Unit = llvm::DICompileUnit();
}
@@ -1325,7 +1542,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
// Create the descriptor for the variable.
llvm::DIVariable D =
DebugFactory.CreateVariable(Tag, llvm::DIDescriptor(RegionStack.back()),
- Decl->getName(),
+ VD->getName(),
Unit, Line, Ty);
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
@@ -1342,7 +1559,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
llvm::Value *Storage, CGBuilderTy &Builder,
CodeGenFunction *CGF) {
- const ValueDecl *Decl = BDRE->getDecl();
+ const ValueDecl *VD = BDRE->getDecl();
assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
// Do not emit variable debug information while generating optimized code.
@@ -1353,186 +1570,50 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
return;
uint64_t XOffset = 0;
- llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
- QualType Type = Decl->getType();
- llvm::DIType Ty = getOrCreateType(Type, Unit);
- if (Decl->hasAttr<BlocksAttr>()) {
- llvm::DICompileUnit DefUnit;
- unsigned Tag = llvm::dwarf::DW_TAG_structure_type;
-
- llvm::SmallVector<llvm::DIDescriptor, 5> EltTys;
-
- llvm::DIType FieldTy;
-
- QualType FType;
- uint64_t FieldSize, FieldOffset;
- unsigned FieldAlign;
-
- llvm::DIArray Elements;
- llvm::DIType EltTy;
-
- // Build up structure for the byref. See BuildByRefType.
- FieldOffset = 0;
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__isa", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__forwarding", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- FType = CGM.getContext().IntTy;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__flags", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- FType = CGM.getContext().IntTy;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__size", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type);
- if (HasCopyAndDispose) {
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__copy_helper", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__destroy_helper", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
- }
-
- unsigned Align = CGM.getContext().getDeclAlignInBytes(Decl);
- if (Align > CGM.getContext().Target.getPointerAlign(0) / 8) {
- unsigned AlignedOffsetInBytes
- = llvm::RoundUpToAlignment(FieldOffset/8, Align);
- unsigned NumPaddingBytes
- = AlignedOffsetInBytes - FieldOffset/8;
-
- if (NumPaddingBytes > 0) {
- llvm::APInt pad(32, NumPaddingBytes);
- FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy,
- pad, ArrayType::Normal, 0);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member,
- Unit, "", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
- }
- }
-
- FType = Type;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = Align*8;
-
- XOffset = FieldOffset;
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- Decl->getName(), DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
-
- unsigned Flags = llvm::DIType::FlagBlockByrefStruct;
-
- Ty = DebugFactory.CreateCompositeType(Tag, Unit, "",
- llvm::DICompileUnit(),
- 0, FieldOffset, 0, 0, Flags,
- llvm::DIType(), Elements);
- }
+ llvm::DICompileUnit Unit = getOrCreateCompileUnit(VD->getLocation());
+ llvm::DIType Ty;
+ if (VD->hasAttr<BlocksAttr>())
+ Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset);
+ else
+ Ty = getOrCreateType(VD->getType(), Unit);
// Get location information.
SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ PresumedLoc PLoc = SM.getPresumedLoc(VD->getLocation());
unsigned Line = 0;
if (!PLoc.isInvalid())
Line = PLoc.getLine();
else
Unit = llvm::DICompileUnit();
- CharUnits offset = CGF->BlockDecls[Decl];
+ CharUnits offset = CGF->BlockDecls[VD];
llvm::SmallVector<llvm::Value *, 9> addr;
- llvm::LLVMContext &VMContext = CGM.getLLVMContext();
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- llvm::DIFactory::OpDeref));
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- llvm::DIFactory::OpPlus));
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset.getQuantity()));
+ const llvm::Type *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext());
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpDeref));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpPlus));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
if (BDRE->isByRef()) {
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- llvm::DIFactory::OpDeref));
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- llvm::DIFactory::OpPlus));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpDeref));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpPlus));
// offset of __forwarding field
offset = CharUnits::fromQuantity(CGF->LLVMPointerWidth/8);
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset.getQuantity()));
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- llvm::DIFactory::OpDeref));
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- llvm::DIFactory::OpPlus));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpDeref));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpPlus));
// offset of x field
offset = CharUnits::fromQuantity(XOffset/8);
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset.getQuantity()));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
}
// Create the descriptor for the variable.
llvm::DIVariable D =
- DebugFactory.CreateComplexVariable(Tag, llvm::DIDescriptor(RegionStack.back()),
- Decl->getName(), Unit, Line, Ty,
+ DebugFactory.CreateComplexVariable(Tag,
+ llvm::DIDescriptor(RegionStack.back()),
+ VD->getName(), Unit, Line, Ty,
addr);
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
- DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertPoint());
+ DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock());
llvm::DIScope DS(RegionStack.back());
llvm::DILocation DO(NULL);
@@ -1542,10 +1623,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
Call->setMetadata("dbg", DL.getNode());
}
-void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *Decl,
+void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
llvm::Value *Storage,
CGBuilderTy &Builder) {
- EmitDeclare(Decl, llvm::dwarf::DW_TAG_auto_variable, Storage, Builder);
+ EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, Builder);
}
void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
@@ -1556,24 +1637,24 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
/// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument
/// variable declaration.
-void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI,
+void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
CGBuilderTy &Builder) {
- EmitDeclare(Decl, llvm::dwarf::DW_TAG_arg_variable, AI, Builder);
+ EmitDeclare(VD, llvm::dwarf::DW_TAG_arg_variable, AI, Builder);
}
/// EmitGlobalVariable - Emit information about a global variable.
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
- const VarDecl *Decl) {
-
+ const VarDecl *D) {
+
// Create global variable debug descriptor.
- llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
+ llvm::DICompileUnit Unit = getOrCreateCompileUnit(D->getLocation());
SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ PresumedLoc PLoc = SM.getPresumedLoc(D->getLocation());
unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
- QualType T = Decl->getType();
+ QualType T = D->getType();
if (T->isIncompleteArrayType()) {
// CodeGen turns int[] into int[1] so we'll do the same here.
@@ -1585,9 +1666,11 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
T = CGM.getContext().getConstantArrayType(ET, ConstVal,
ArrayType::Normal, 0);
}
- llvm::StringRef DeclName = Decl->getName();
- DebugFactory.CreateGlobalVariable(getContext(Decl, Unit), DeclName, DeclName,
- llvm::StringRef(), Unit, LineNo,
+ llvm::StringRef DeclName = D->getName();
+ llvm::DIDescriptor DContext =
+ getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()), Unit);
+ DebugFactory.CreateGlobalVariable(DContext, DeclName,
+ DeclName, llvm::StringRef(), Unit, LineNo,
getOrCreateType(T, Unit),
Var->hasInternalLinkage(),
true/*definition*/, Var);
@@ -1595,16 +1678,16 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
/// EmitGlobalVariable - Emit information about an objective-c interface.
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
- ObjCInterfaceDecl *Decl) {
+ ObjCInterfaceDecl *ID) {
// Create global variable debug descriptor.
- llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
+ llvm::DICompileUnit Unit = getOrCreateCompileUnit(ID->getLocation());
SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ PresumedLoc PLoc = SM.getPresumedLoc(ID->getLocation());
unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
- llvm::StringRef Name = Decl->getName();
+ llvm::StringRef Name = ID->getName();
- QualType T = CGM.getContext().getObjCInterfaceType(Decl);
+ QualType T = CGM.getContext().getObjCInterfaceType(ID);
if (T->isIncompleteArrayType()) {
// CodeGen turns int[] into int[1] so we'll do the same here.
@@ -1622,3 +1705,26 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
Var->hasInternalLinkage(),
true/*definition*/, Var);
}
+
+/// getOrCreateNamesSpace - Return namespace descriptor for the given
+/// namespace decl.
+llvm::DINameSpace
+CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl,
+ llvm::DIDescriptor Unit) {
+ llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH>::iterator I =
+ NameSpaceCache.find(NSDecl);
+ if (I != NameSpaceCache.end())
+ return llvm::DINameSpace(cast<llvm::MDNode>(I->second));
+
+ SourceManager &SM = CGM.getContext().getSourceManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(NSDecl->getLocation());
+ unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
+
+ llvm::DIDescriptor Context =
+ getContextDescriptor(dyn_cast<Decl>(NSDecl->getDeclContext()), Unit);
+ llvm::DINameSpace NS =
+ DebugFactory.CreateNameSpace(Context, NSDecl->getName(),
+ llvm::DICompileUnit(Unit.getNode()), LineNo);
+ NameSpaceCache[NSDecl] = llvm::WeakVH(NS.getNode());
+ return NS;
+}
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index fddd23b4e9c3..b2d3a1f1fa53 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -47,6 +47,8 @@ class CGDebugInfo {
llvm::DIFactory DebugFactory;
SourceLocation CurLoc, PrevLoc;
+
+ llvm::DIType VTablePtrType;
/// CompileUnitCache - Cache of previously constructed CompileUnits.
llvm::DenseMap<unsigned, llvm::DICompileUnit> CompileUnitCache;
@@ -59,12 +61,14 @@ class CGDebugInfo {
llvm::DIType BlockLiteralGeneric;
std::vector<llvm::TrackingVH<llvm::MDNode> > RegionStack;
+ llvm::DenseMap<const Decl *, llvm::WeakVH> RegionMap;
- /// FunctionNames - This is a storage for function names that are
+ /// DebugInfoNames - This is a storage for names that are
/// constructed on demand. For example, C++ destructors, C++ operators etc..
- llvm::BumpPtrAllocator FunctionNames;
+ llvm::BumpPtrAllocator DebugInfoNames;
llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache;
+ llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH> NameSpaceCache;
/// Helper functions for getOrCreateType.
llvm::DIType CreateType(const BuiltinType *Ty, llvm::DICompileUnit U);
@@ -83,16 +87,37 @@ class CGDebugInfo {
llvm::DIType CreateType(const ArrayType *Ty, llvm::DICompileUnit U);
llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DICompileUnit U);
llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DICompileUnit U);
-
+ llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method,
+ llvm::DICompileUnit Unit);
+ llvm::DIType getOrCreateVTablePtrType(llvm::DICompileUnit Unit);
+ llvm::DINameSpace getOrCreateNameSpace(const NamespaceDecl *N,
+ llvm::DIDescriptor Unit);
+
llvm::DIType CreatePointerLikeType(unsigned Tag,
const Type *Ty, QualType PointeeTy,
llvm::DICompileUnit U);
+
+ llvm::DISubprogram CreateCXXMemberFunction(const CXXMethodDecl *Method,
+ llvm::DICompileUnit Unit,
+ llvm::DICompositeType &RecordTy);
+
void CollectCXXMemberFunctions(const CXXRecordDecl *Decl,
llvm::DICompileUnit U,
llvm::SmallVectorImpl<llvm::DIDescriptor> &E,
llvm::DICompositeType &T);
+ void CollectCXXBases(const CXXRecordDecl *Decl,
+ llvm::DICompileUnit Unit,
+ llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys,
+ llvm::DICompositeType &RecordTy);
+
+
void CollectRecordFields(const RecordDecl *Decl, llvm::DICompileUnit U,
llvm::SmallVectorImpl<llvm::DIDescriptor> &E);
+
+ void CollectVtableInfo(const CXXRecordDecl *Decl,
+ llvm::DICompileUnit Unit,
+ llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys);
+
public:
CGDebugInfo(CodeGenModule &CGM);
~CGDebugInfo();
@@ -150,8 +175,14 @@ private:
void EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, llvm::Value *AI,
CGBuilderTy &Builder, CodeGenFunction *CGF);
- /// getContext - Get context info for the decl.
- llvm::DIDescriptor getContext(const VarDecl *Decl,llvm::DIDescriptor &CU);
+ // EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
+ // See BuildByRefType.
+ llvm::DIType EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
+ uint64_t *OffSet);
+
+ /// getContextDescriptor - Get context info for the decl.
+ llvm::DIDescriptor getContextDescriptor(const Decl *Decl,
+ llvm::DIDescriptor &CU);
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a
/// new one if necessary.
@@ -168,6 +199,10 @@ private:
/// name is constructred on demand (e.g. C++ destructor) then the name
/// is stored on the side.
llvm::StringRef getFunctionName(const FunctionDecl *FD);
+
+ /// getVtableName - Get vtable name for the given Class.
+ llvm::StringRef getVtableName(const CXXRecordDecl *Decl);
+
};
} // namespace CodeGen
} // namespace clang
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 9606a71527a4..793a22050677 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -76,8 +76,21 @@ void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) {
case VarDecl::Auto:
case VarDecl::Register:
return EmitLocalBlockVarDecl(D);
- case VarDecl::Static:
- return EmitStaticBlockVarDecl(D);
+ case VarDecl::Static: {
+ llvm::GlobalValue::LinkageTypes Linkage =
+ llvm::GlobalValue::InternalLinkage;
+
+ // If this is a static declaration inside an inline function, it must have
+ // weak linkage so that the linker will merge multiple definitions of it.
+ if (getContext().getLangOptions().CPlusPlus) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurFuncDecl)) {
+ if (FD->isInlined())
+ Linkage = llvm::GlobalValue::WeakAnyLinkage;
+ }
+ }
+
+ return EmitStaticBlockVarDecl(D, Linkage);
+ }
case VarDecl::Extern:
case VarDecl::PrivateExtern:
// Don't emit it now, allow it to be emitted lazily on its first use.
@@ -120,7 +133,7 @@ CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D,
Ty.isConstant(getContext()), Linkage,
CGM.EmitNullConstant(D.getType()), Name, 0,
D.isThreadSpecified(), Ty.getAddressSpace());
- GV->setAlignment(getContext().getDeclAlignInBytes(&D));
+ GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
return GV;
}
@@ -138,8 +151,13 @@ CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D,
if (!Init) {
if (!getContext().getLangOptions().CPlusPlus)
CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
- else
+ else {
+ // Since we have a static initializer, this global variable can't
+ // be constant.
+ GV->setConstant(false);
+
EmitStaticCXXBlockVarDeclInit(D, GV);
+ }
return GV;
}
@@ -172,12 +190,12 @@ CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D,
return GV;
}
-void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
+void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D,
+ llvm::GlobalValue::LinkageTypes Linkage) {
llvm::Value *&DMEntry = LocalDeclMap[&D];
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
- llvm::GlobalVariable *GV =
- CreateStaticBlockVarDecl(D, ".", llvm::GlobalValue::InternalLinkage);
+ llvm::GlobalVariable *GV = CreateStaticBlockVarDecl(D, ".", Linkage);
// Store into LocalDeclMap before generating initializer to handle
// circular references.
@@ -281,8 +299,8 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const ValueDecl *D) {
}
bool Packed = false;
- unsigned Align = getContext().getDeclAlignInBytes(D);
- if (Align > Target.getPointerAlign(0) / 8) {
+ CharUnits Align = getContext().getDeclAlign(D);
+ if (Align > CharUnits::fromQuantity(Target.getPointerAlign(0) / 8)) {
// We have to insert padding.
// The struct above has 2 32-bit integers.
@@ -294,7 +312,7 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const ValueDecl *D) {
// Align the offset.
unsigned AlignedOffsetInBytes =
- llvm::RoundUpToAlignment(CurrentOffsetInBytes, Align);
+ llvm::RoundUpToAlignment(CurrentOffsetInBytes, Align.getQuantity());
unsigned NumPaddingBytes = AlignedOffsetInBytes - CurrentOffsetInBytes;
if (NumPaddingBytes > 0) {
@@ -334,7 +352,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
QualType Ty = D.getType();
bool isByRef = D.hasAttr<BlocksAttr>();
bool needsDispose = false;
- unsigned Align = 0;
+ CharUnits Align = CharUnits::Zero();
bool IsSimpleConstantInitializer = false;
llvm::Value *DeclPtr;
@@ -350,7 +368,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
// If this variable is marked 'const', emit the value as a global.
if (CGM.getCodeGenOpts().MergeAllConstants &&
Ty.isConstant(getContext())) {
- EmitStaticBlockVarDecl(D);
+ EmitStaticBlockVarDecl(D, llvm::GlobalValue::InternalLinkage);
return;
}
@@ -364,10 +382,11 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
Alloc->setName(D.getNameAsString());
- Align = getContext().getDeclAlignInBytes(&D);
+ Align = getContext().getDeclAlign(&D);
if (isByRef)
- Align = std::max(Align, unsigned(Target.getPointerAlign(0) / 8));
- Alloc->setAlignment(Align);
+ Align = std::max(Align,
+ CharUnits::fromQuantity(Target.getPointerAlign(0) / 8));
+ Alloc->setAlignment(Align.getQuantity());
DeclPtr = Alloc;
} else {
// Targets that don't support recursion emit locals as globals.
@@ -420,7 +439,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
// Allocate memory for the array.
llvm::AllocaInst *VLA =
Builder.CreateAlloca(llvm::Type::getInt8Ty(VMContext), VLASize, "vla");
- VLA->setAlignment(getContext().getDeclAlignInBytes(&D));
+ VLA->setAlignment(getContext().getDeclAlign(&D).getQuantity());
DeclPtr = Builder.CreateBitCast(VLA, LElemPtrTy, "tmp");
}
@@ -468,7 +487,8 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
assert(Init != 0 && "Wasn't a simple constant init?");
llvm::Value *AlignVal =
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Align);
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+ Align.getQuantity());
const llvm::Type *IntPtr =
llvm::IntegerType::get(VMContext, LLVMPointerWidth);
llvm::Value *SizeVal =
@@ -492,7 +512,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
new llvm::GlobalVariable(CGM.getModule(), Init->getType(), true,
llvm::GlobalValue::InternalLinkage,
Init, Name, 0, false, 0);
- GV->setAlignment(Align);
+ GV->setAlignment(Align.getQuantity());
llvm::Value *SrcPtr = GV;
if (SrcPtr->getType() != BP)
@@ -501,7 +521,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
Builder.CreateCall4(CGM.getMemCpyFn(), Loc, SrcPtr, SizeVal, AlignVal);
}
} else if (Ty->isReferenceType()) {
- RValue RV = EmitReferenceBindingToExpr(Init, Ty, /*IsInitializer=*/true);
+ RValue RV = EmitReferenceBindingToExpr(Init, /*IsInitializer=*/true);
EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Ty);
} else if (!hasAggregateLLVMType(Init->getType())) {
llvm::Value *V = EmitScalarExpr(Init);
@@ -554,19 +574,19 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
const llvm::Type *V1;
V1 = cast<llvm::PointerType>(DeclPtr->getType())->getElementType();
V = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- (CGM.getTargetData().getTypeStoreSizeInBits(V1)
- / 8));
+ CGM.GetTargetTypeStoreSize(V1).getQuantity());
Builder.CreateStore(V, size_field);
if (flags & BLOCK_HAS_COPY_DISPOSE) {
BlockHasCopyDispose = true;
llvm::Value *copy_helper = Builder.CreateStructGEP(DeclPtr, 4);
- Builder.CreateStore(BuildbyrefCopyHelper(DeclPtr->getType(), flag, Align),
+ Builder.CreateStore(BuildbyrefCopyHelper(DeclPtr->getType(), flag,
+ Align.getQuantity()),
copy_helper);
llvm::Value *destroy_helper = Builder.CreateStructGEP(DeclPtr, 5);
Builder.CreateStore(BuildbyrefDestroyHelper(DeclPtr->getType(), flag,
- Align),
+ Align.getQuantity()),
destroy_helper);
}
}
@@ -683,25 +703,18 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) {
CanQualType CTy = getContext().getCanonicalType(Ty);
llvm::Value *DeclPtr;
- if (!Ty->isConstantSizeType()) {
- // Variable sized values always are passed by-reference.
+ // If this is an aggregate or variable sized value, reuse the input pointer.
+ if (!Ty->isConstantSizeType() ||
+ CodeGenFunction::hasAggregateLLVMType(Ty)) {
DeclPtr = Arg;
} else {
- // A fixed sized single-value variable becomes an alloca in the entry block.
- const llvm::Type *LTy = ConvertTypeForMem(Ty);
- if (LTy->isSingleValueType()) {
- // TODO: Alignment
- DeclPtr = CreateTempAlloca(LTy);
- DeclPtr->setName(D.getNameAsString() + llvm::StringRef(".addr"));
-
- // Store the initial value into the alloca.
- EmitStoreOfScalar(Arg, DeclPtr, CTy.isVolatileQualified(), Ty);
- } else {
- // Otherwise, if this is an aggregate, just use the input pointer.
- DeclPtr = Arg;
- }
- Arg->setName(D.getNameAsString());
+ // Otherwise, create a temporary to hold the value.
+ DeclPtr = CreateMemTemp(Ty, D.getName() + ".addr");
+
+ // Store the initial value into the alloca.
+ EmitStoreOfScalar(Arg, DeclPtr, CTy.isVolatileQualified(), Ty);
}
+ Arg->setName(D.getName());
llvm::Value *&DMEntry = LocalDeclMap[&D];
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 47773a0d69e3..0de3b0be4b1a 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -80,8 +80,13 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
EmitDeclInit(*this, D, DeclPtr);
return;
}
-
- ErrorUnsupported(Init, "global variable that binds to a reference");
+ if (Init->isLvalue(getContext()) == Expr::LV_Valid) {
+ RValue RV = EmitReferenceBindingToExpr(Init, /*IsInitializer=*/true);
+ EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, T);
+ return;
+ }
+ ErrorUnsupported(Init,
+ "global variable that binds reference to a non-lvalue");
}
void
@@ -179,57 +184,120 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
FinishFunction();
}
+static llvm::Constant *getGuardAcquireFn(CodeGenFunction &CGF) {
+ // int __cxa_guard_acquire(__int64_t *guard_object);
+
+ const llvm::Type *Int64PtrTy =
+ llvm::Type::getInt64PtrTy(CGF.getLLVMContext());
+
+ std::vector<const llvm::Type*> Args(1, Int64PtrTy);
+
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGF.ConvertType(CGF.getContext().IntTy),
+ Args, /*isVarArg=*/false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire");
+}
+
+static llvm::Constant *getGuardReleaseFn(CodeGenFunction &CGF) {
+ // void __cxa_guard_release(__int64_t *guard_object);
+
+ const llvm::Type *Int64PtrTy =
+ llvm::Type::getInt64PtrTy(CGF.getLLVMContext());
+
+ std::vector<const llvm::Type*> Args(1, Int64PtrTy);
+
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
+ Args, /*isVarArg=*/false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release");
+}
+
+static llvm::Constant *getGuardAbortFn(CodeGenFunction &CGF) {
+ // void __cxa_guard_abort(__int64_t *guard_object);
+
+ const llvm::Type *Int64PtrTy =
+ llvm::Type::getInt64PtrTy(CGF.getLLVMContext());
+
+ std::vector<const llvm::Type*> Args(1, Int64PtrTy);
+
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
+ Args, /*isVarArg=*/false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort");
+}
+
void
CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
llvm::GlobalVariable *GV) {
- // FIXME: This should use __cxa_guard_{acquire,release}?
-
- assert(!getContext().getLangOptions().ThreadsafeStatics &&
- "thread safe statics are currently not supported!");
-
+ bool ThreadsafeStatics = getContext().getLangOptions().ThreadsafeStatics;
+
llvm::SmallString<256> GuardVName;
CGM.getMangleContext().mangleGuardVariable(&D, GuardVName);
// Create the guard variable.
- llvm::GlobalValue *GuardV =
- new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext),
+ const llvm::Type *Int64Ty = llvm::Type::getInt64Ty(VMContext);
+ llvm::GlobalValue *GuardVariable =
+ new llvm::GlobalVariable(CGM.getModule(), Int64Ty,
false, GV->getLinkage(),
- llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)),
+ llvm::Constant::getNullValue(Int64Ty),
GuardVName.str());
// Load the first byte of the guard variable.
const llvm::Type *PtrTy
= llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
- llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy),
- "tmp");
-
- // Compare it against 0.
- llvm::Value *nullValue
- = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext));
- llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool");
+ llvm::Value *V =
+ Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy), "tmp");
- llvm::BasicBlock *InitBlock = createBasicBlock("init");
+ llvm::BasicBlock *InitCheckBlock = createBasicBlock("init.check");
llvm::BasicBlock *EndBlock = createBasicBlock("init.end");
- // If the guard variable is 0, jump to the initializer code.
- Builder.CreateCondBr(ICmp, InitBlock, EndBlock);
+ // Check if the first byte of the guard variable is zero.
+ Builder.CreateCondBr(Builder.CreateIsNull(V, "tobool"),
+ InitCheckBlock, EndBlock);
- EmitBlock(InitBlock);
+ EmitBlock(InitCheckBlock);
+
+ if (ThreadsafeStatics) {
+ // Call __cxa_guard_acquire.
+ V = Builder.CreateCall(getGuardAcquireFn(*this), GuardVariable);
+
+ llvm::BasicBlock *InitBlock = createBasicBlock("init");
+
+ Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"),
+ InitBlock, EndBlock);
+
+ EmitBlock(InitBlock);
+
+ if (Exceptions) {
+ EHCleanupBlock Cleanup(*this);
+
+ // Call __cxa_guard_abort.
+ Builder.CreateCall(getGuardAbortFn(*this), GuardVariable);
+ }
+ }
if (D.getType()->isReferenceType()) {
QualType T = D.getType();
// We don't want to pass true for IsInitializer here, because a static
// reference to a temporary does not extend its lifetime.
- RValue RV = EmitReferenceBindingToExpr(D.getInit(), T,
+ RValue RV = EmitReferenceBindingToExpr(D.getInit(),
/*IsInitializer=*/false);
EmitStoreOfScalar(RV.getScalarVal(), GV, /*Volatile=*/false, T);
} else
EmitDeclInit(*this, D, GV);
- Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext),
- 1),
- Builder.CreateBitCast(GuardV, PtrTy));
+ if (ThreadsafeStatics) {
+ // Call __cxa_guard_release.
+ Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable);
+ } else {
+ llvm::Value *One =
+ llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 1);
+ Builder.CreateStore(One, Builder.CreateBitCast(GuardVariable, PtrTy));
+ }
EmitBlock(EndBlock);
}
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index bd0461fd2808..d956c1c3cd85 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -100,10 +100,6 @@ static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) {
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
}
-// FIXME: Eventually this will all go into the backend. Set from the target for
-// now.
-static int using_sjlj_exceptions = 0;
-
static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) {
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
std::vector<const llvm::Type*> Args(1, Int8PtrTy);
@@ -112,7 +108,7 @@ static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) {
llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args,
false);
- if (using_sjlj_exceptions)
+ if (CGF.CGM.getLangOptions().SjLjExceptions)
return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
}
@@ -194,9 +190,9 @@ static void CopyObject(CodeGenFunction &CGF, const Expr *E,
// Push the Src ptr.
CallArgs.push_back(std::make_pair(RValue::get(Src),
CopyCtor->getParamDecl(0)->getType()));
- QualType ResultType =
- CopyCtor->getType()->getAs<FunctionType>()->getResultType();
- CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ const FunctionProtoType *FPT
+ = CopyCtor->getType()->getAs<FunctionProtoType>();
+ CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
Callee, ReturnValueSlot(), CallArgs, CopyCtor);
CGF.setInvokeDest(PrevLandingPad);
} else
@@ -244,9 +240,10 @@ static void CopyObject(CodeGenFunction &CGF, QualType ObjectType,
// Push the Src ptr.
CallArgs.push_back(std::make_pair(RValue::get(Src),
CopyCtor->getParamDecl(0)->getType()));
- QualType ResultType =
- CopyCtor->getType()->getAs<FunctionType>()->getResultType();
- CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+
+ const FunctionProtoType *FPT
+ = CopyCtor->getType()->getAs<FunctionProtoType>();
+ CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
Callee, ReturnValueSlot(), CallArgs, CopyCtor);
} else
llvm_unreachable("uncopyable object");
@@ -316,6 +313,9 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
}
void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
+ if (!Exceptions)
+ return;
+
const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
if (FD == 0)
return;
@@ -410,6 +410,9 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
}
void CodeGenFunction::EmitEndEHSpec(const Decl *D) {
+ if (!Exceptions)
+ return;
+
const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
if (FD == 0)
return;
@@ -466,6 +469,7 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue");
PushCleanupBlock(DtorEpilogue);
+ InitializeVtablePtrs(DD->getParent());
EmitStmt(S.getTryBlock());
CleanupBlockInfo Info = PopCleanupBlock();
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 2358bb35923a..830954fd10cc 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -36,16 +36,24 @@ llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty,
return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt);
}
+llvm::Value *CodeGenFunction::CreateMemTemp(QualType Ty, const llvm::Twine &Name) {
+ llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty), Name);
+ // FIXME: Should we prefer the preferred type alignment here?
+ CharUnits Align = getContext().getTypeAlignInChars(Ty);
+ Alloc->setAlignment(Align.getQuantity());
+ return Alloc;
+}
+
/// EvaluateExprAsBool - Perform the usual unary conversions on the specified
/// expression and compare the result against zero, returning an Int1Ty value.
llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) {
QualType BoolTy = getContext().BoolTy;
if (E->getType()->isMemberFunctionPointerType()) {
- llvm::Value *Ptr = CreateTempAlloca(ConvertType(E->getType()));
- EmitAggExpr(E, Ptr, /*VolatileDest=*/false);
+ LValue LV = EmitAggExprToLValue(E);
// Get the pointer.
- llvm::Value *FuncPtr = Builder.CreateStructGEP(Ptr, 0, "src.ptr");
+ llvm::Value *FuncPtr = Builder.CreateStructGEP(LV.getAddress(), 0,
+ "src.ptr");
FuncPtr = Builder.CreateLoad(FuncPtr);
llvm::Value *IsNotNull =
@@ -87,13 +95,12 @@ RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E,
if (hasAggregateLLVMType(E->getType()) &&
!E->getType()->isAnyComplexType())
- AggLoc = CreateTempAlloca(ConvertType(E->getType()), "agg.tmp");
+ AggLoc = CreateMemTemp(E->getType(), "agg.tmp");
return EmitAnyExpr(E, AggLoc, IsAggLocVolatile, /*IgnoreResult=*/false,
IsInitializer);
}
RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
- QualType DestType,
bool IsInitializer) {
bool ShouldDestroyTemporaries = false;
unsigned OldNumLiveTemporaries = 0;
@@ -114,8 +121,16 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
if (E->isLvalue(getContext()) == Expr::LV_Valid) {
// Emit the expr as an lvalue.
LValue LV = EmitLValue(E);
- if (LV.isSimple())
+ if (LV.isSimple()) {
+ if (ShouldDestroyTemporaries) {
+ // Pop temporaries.
+ while (LiveTemporaries.size() > OldNumLiveTemporaries)
+ PopCXXTemporary();
+ }
+
return RValue::get(LV.getAddress());
+ }
+
Val = EmitLoadOfLValue(LV, E->getType());
if (ShouldDestroyTemporaries) {
@@ -188,8 +203,7 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
Val = RValue::get(Val.getAggregateAddr());
} else {
// Create a temporary variable that we can bind the reference to.
- llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(E->getType()),
- "reftmp");
+ llvm::Value *Temp = CreateMemTemp(E->getType(), "reftmp");
if (Val.isScalar())
EmitStoreOfScalar(Val.getScalarVal(), Temp, false, E->getType());
else
@@ -546,6 +560,8 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) {
cast<llvm::PointerType>(Ptr->getType())->getElementType();
// Simple scalar l-value.
+ //
+ // FIXME: We shouldn't have to use isSingleValueType here.
if (EltTy->isSingleValueType())
return RValue::get(EmitLoadOfScalar(Ptr, LV.isVolatileQualified(),
ExprType));
@@ -1069,9 +1085,12 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
return EmitFunctionDeclLValue(*this, E, FD);
+ // FIXME: the qualifier check does not seem sufficient here
if (E->getQualifier()) {
- // FIXME: the qualifier check does not seem sufficient here
- return EmitPointerToDataMemberLValue(cast<FieldDecl>(ND));
+ const FieldDecl *FD = cast<FieldDecl>(ND);
+ llvm::Value *V = CGM.EmitPointerToDataMember(FD);
+
+ return LValue::MakeAddr(V, MakeQualifiers(FD->getType()));
}
assert(false && "Unhandled DeclRefExpr");
@@ -1166,8 +1185,7 @@ LValue CodeGenFunction::EmitPredefinedFunctionName(unsigned Type) {
GlobalVarName += FnName;
std::string FunctionName =
- PredefinedExpr::ComputeName(getContext(), (PredefinedExpr::IdentType)Type,
- CurCodeDecl);
+ PredefinedExpr::ComputeName((PredefinedExpr::IdentType)Type, CurCodeDecl);
llvm::Constant *C =
CGM.GetAddrOfConstantCString(FunctionName, GlobalVarName.c_str());
@@ -1350,7 +1368,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
llvm::Value *Vec = EmitScalarExpr(E->getBase());
// Store the vector to memory (because LValue wants an address).
- llvm::Value *VecMem =CreateTempAlloca(ConvertType(E->getBase()->getType()));
+ llvm::Value *VecMem = CreateMemTemp(E->getBase()->getType());
Builder.CreateStore(Vec, VecMem);
Base = LValue::MakeAddr(VecMem, Qualifiers());
}
@@ -1381,7 +1399,6 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
}
LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
- bool isUnion = false;
bool isNonGC = false;
Expr *BaseExpr = E->getBase();
llvm::Value *BaseValue = NULL;
@@ -1392,16 +1409,12 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
BaseValue = EmitScalarExpr(BaseExpr);
const PointerType *PTy =
BaseExpr->getType()->getAs<PointerType>();
- if (PTy->getPointeeType()->isUnionType())
- isUnion = true;
BaseQuals = PTy->getPointeeType().getQualifiers();
} else if (isa<ObjCPropertyRefExpr>(BaseExpr->IgnoreParens()) ||
isa<ObjCImplicitSetterGetterRefExpr>(
BaseExpr->IgnoreParens())) {
RValue RV = EmitObjCPropertyGet(BaseExpr);
BaseValue = RV.getAggregateAddr();
- if (BaseExpr->getType()->isUnionType())
- isUnion = true;
BaseQuals = BaseExpr->getType().getQualifiers();
} else {
LValue BaseLV = EmitLValue(BaseExpr);
@@ -1410,14 +1423,12 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
// FIXME: this isn't right for bitfields.
BaseValue = BaseLV.getAddress();
QualType BaseTy = BaseExpr->getType();
- if (BaseTy->isUnionType())
- isUnion = true;
BaseQuals = BaseTy.getQualifiers();
}
NamedDecl *ND = E->getMemberDecl();
if (FieldDecl *Field = dyn_cast<FieldDecl>(ND)) {
- LValue LV = EmitLValueForField(BaseValue, Field, isUnion,
+ LValue LV = EmitLValueForField(BaseValue, Field,
BaseQuals.getCVRQualifiers());
LValue::SetObjCNonGC(LV, isNonGC);
setObjCGCLValueClass(getContext(), E, LV);
@@ -1461,7 +1472,6 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue,
LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue,
const FieldDecl* Field,
- bool isUnion,
unsigned CVRQualifiers) {
if (Field->isBitField())
return EmitLValueForBitfield(BaseValue, Field, CVRQualifiers);
@@ -1470,7 +1480,7 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue,
llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp");
// Match union field type.
- if (isUnion) {
+ if (Field->getParent()->isUnion()) {
const llvm::Type *FieldTy =
CGM.getTypes().ConvertTypeForMem(Field->getType());
const llvm::PointerType * BaseTy =
@@ -1492,9 +1502,26 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue,
return LValue::MakeAddr(V, Quals);
}
+LValue
+CodeGenFunction::EmitLValueForFieldInitialization(llvm::Value* BaseValue,
+ const FieldDecl* Field,
+ unsigned CVRQualifiers) {
+ QualType FieldType = Field->getType();
+
+ if (!FieldType->isReferenceType())
+ return EmitLValueForField(BaseValue, Field, CVRQualifiers);
+
+ unsigned idx = CGM.getTypes().getLLVMFieldNo(Field);
+ llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp");
+
+ assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs");
+
+ return LValue::MakeAddr(V, MakeQualifiers(FieldType));
+}
+
LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){
- const llvm::Type *LTy = ConvertType(E->getType());
- llvm::Value *DeclPtr = CreateTempAlloca(LTy, ".compoundliteral");
+ llvm::Value *DeclPtr = CreateTempAlloca(ConvertTypeForMem(E->getType()),
+ ".compoundliteral");
const Expr* InitExpr = E->getInitializer();
LValue Result = LValue::MakeAddr(DeclPtr, MakeQualifiers(E->getType()));
@@ -1527,18 +1554,25 @@ CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) {
EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
+ // Any temporaries created here are conditional.
+ BeginConditionalBranch();
EmitBlock(LHSBlock);
-
LValue LHS = EmitLValue(E->getLHS());
+ EndConditionalBranch();
+
if (!LHS.isSimple())
return EmitUnsupportedLValue(E, "conditional operator");
+ // FIXME: We shouldn't need an alloca for this.
llvm::Value *Temp = CreateTempAlloca(LHS.getAddress()->getType(),"condtmp");
Builder.CreateStore(LHS.getAddress(), Temp);
EmitBranch(ContBlock);
+ // Any temporaries created here are conditional.
+ BeginConditionalBranch();
EmitBlock(RHSBlock);
LValue RHS = EmitLValue(E->getRHS());
+ EndConditionalBranch();
if (!RHS.isSimple())
return EmitUnsupportedLValue(E, "conditional operator");
@@ -1556,10 +1590,7 @@ CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) {
!E->getType()->isAnyComplexType()) &&
"Unexpected conditional operator!");
- llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType()));
- EmitAggExpr(E, Temp, false);
-
- return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
+ return EmitAggExprToLValue(E);
}
/// EmitCastLValue - Casts are never lvalues unless that cast is a dynamic_cast.
@@ -1606,12 +1637,8 @@ 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_ToUnion:
+ return EmitAggExprToLValue(E);
case CastExpr::CK_BaseToDerived: {
const RecordType *BaseClassTy =
E->getSubExpr()->getType()->getAs<RecordType>();
@@ -1646,13 +1673,9 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
LValue CodeGenFunction::EmitNullInitializationLValue(
const CXXZeroInitValueExpr *E) {
QualType Ty = E->getType();
- const llvm::Type *LTy = ConvertTypeForMem(Ty);
- llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
- unsigned Align = getContext().getTypeAlign(Ty)/8;
- Alloc->setAlignment(Align);
- LValue lvalue = LValue::MakeAddr(Alloc, Qualifiers());
- EmitMemSetToZero(lvalue.getAddress(), Ty);
- return lvalue;
+ LValue LV = LValue::MakeAddr(CreateMemTemp(Ty), MakeQualifiers(Ty));
+ EmitMemSetToZero(LV.getAddress(), Ty);
+ return LV;
}
//===--------------------------------------------------------------------===//
@@ -1725,10 +1748,7 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
return LV;
}
- llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType()));
- EmitAggExpr(E, Temp, false);
- // FIXME: Are these qualifiers correct?
- return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
+ return EmitAggExprToLValue(E);
}
LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
@@ -1746,13 +1766,11 @@ LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) {
// FIXME: This shouldn't require another copy.
- llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType()));
- EmitAggExpr(E, Temp, false);
- return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
+ return EmitAggExprToLValue(E);
}
LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) {
- llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(E->getType()), "tmp");
+ llvm::Value *Temp = CreateMemTemp(E->getType(), "tmp");
EmitCXXConstructExpr(Temp, E);
return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
}
@@ -1840,21 +1858,6 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) {
return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType()));
}
-
-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, Field, /*isUnion=*/false,
- /*Qualifiers=*/0);
- const llvm::Type *ResultType = ConvertType(getContext().getPointerDiffType());
- V = Builder.CreatePtrToInt(MemExpLV.getAddress(), ResultType, "datamember");
- return LValue::MakeAddr(V, MakeQualifiers(Field->getType()));
-}
-
RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
ReturnValueSlot ReturnValue,
CallExpr::const_arg_iterator ArgBeg,
@@ -1867,20 +1870,14 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
CalleeType = getContext().getCanonicalType(CalleeType);
- QualType FnType = cast<PointerType>(CalleeType)->getPointeeType();
- QualType ResultType = cast<FunctionType>(FnType)->getResultType();
+ const FunctionType *FnType
+ = cast<FunctionType>(cast<PointerType>(CalleeType)->getPointeeType());
+ QualType ResultType = FnType->getResultType();
CallArgList Args;
EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), ArgBeg, ArgEnd);
- // FIXME: We should not need to do this, it should be part of the function
- // type.
- unsigned CallingConvention = 0;
- if (const llvm::Function *F =
- dyn_cast<llvm::Function>(Callee->stripPointerCasts()))
- CallingConvention = F->getCallingConv();
- return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args,
- CallingConvention),
+ return EmitCall(CGM.getTypes().getFunctionInfo(Args, FnType),
Callee, ReturnValue, Args, TargetDecl);
}
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index c852d65b859f..97455c7b13cf 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -118,7 +118,7 @@ public:
void VisitVAArgExpr(VAArgExpr *E);
- void EmitInitializationToLValue(Expr *E, LValue Address);
+ void EmitInitializationToLValue(Expr *E, LValue Address, QualType T);
void EmitNullInitializationToLValue(LValue Address, QualType T);
// case Expr::ChooseExprClass:
void VisitCXXThrowExpr(const CXXThrowExpr *E) { CGF.EmitCXXThrowExpr(E); }
@@ -147,7 +147,7 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) {
return;
// If the source is volatile, we must read from it; to do that, we need
// some place to put it.
- DestPtr = CGF.CreateTempAlloca(CGF.ConvertType(E->getType()), "agg.tmp");
+ DestPtr = CGF.CreateMemTemp(E->getType(), "agg.tmp");
}
if (RequiresGCollection) {
@@ -188,7 +188,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
llvm::Value *CastPtr = Builder.CreateBitCast(DestPtr,
CGF.ConvertType(PtrTy));
EmitInitializationToLValue(E->getSubExpr(),
- LValue::MakeAddr(CastPtr, Qualifiers()));
+ LValue::MakeAddr(CastPtr, Qualifiers()),
+ E->getType());
break;
}
@@ -227,8 +228,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CastExpr::CK_BaseToDerivedMemberPointer: {
QualType SrcType = E->getSubExpr()->getType();
- llvm::Value *Src = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(SrcType),
- "tmp");
+ llvm::Value *Src = CGF.CreateMemTemp(SrcType, "tmp");
CGF.EmitAggExpr(E->getSubExpr(), Src, SrcType.isVolatileQualified());
llvm::Value *SrcPtr = Builder.CreateStructGEP(Src, 0, "src.ptr");
@@ -252,8 +252,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
std::swap(DerivedDecl, BaseDecl);
- llvm::Constant *Adj = CGF.CGM.GetCXXBaseClassOffset(DerivedDecl, BaseDecl);
- if (Adj) {
+ if (llvm::Constant *Adj =
+ CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, BaseDecl)) {
if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj");
else
@@ -326,10 +326,18 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) {
int64_t Index =
CGF.CGM.getVtableInfo().getMethodVtableIndex(MD);
- FuncPtr = llvm::ConstantInt::get(PtrDiffTy, Index + 1);
+ // Itanium C++ ABI 2.3:
+ // For a non-virtual function, this field is a simple function pointer.
+ // For a virtual function, it is 1 plus the virtual table offset
+ // (in bytes) of the function, represented as a ptrdiff_t.
+ FuncPtr = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1);
} else {
- FuncPtr = llvm::ConstantExpr::getPtrToInt(CGF.CGM.GetAddrOfFunction(MD),
- PtrDiffTy);
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const llvm::Type *Ty =
+ CGF.CGM.getTypes().GetFunctionType(CGF.CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+ llvm::Constant *Fn = CGF.CGM.GetAddrOfFunction(MD, Ty);
+ FuncPtr = llvm::ConstantExpr::getPtrToInt(Fn, PtrDiffTy);
}
Builder.CreateStore(FuncPtr, DstPtr, VolatileDest);
@@ -371,14 +379,14 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
if (LHS.isPropertyRef()) {
llvm::Value *AggLoc = DestPtr;
if (!AggLoc)
- AggLoc = CGF.CreateTempAlloca(CGF.ConvertType(E->getRHS()->getType()));
+ AggLoc = CGF.CreateMemTemp(E->getRHS()->getType());
CGF.EmitAggExpr(E->getRHS(), AggLoc, VolatileDest);
CGF.EmitObjCPropertySet(LHS.getPropertyRefExpr(),
RValue::getAggregate(AggLoc, VolatileDest));
} else if (LHS.isKVCRef()) {
llvm::Value *AggLoc = DestPtr;
if (!AggLoc)
- AggLoc = CGF.CreateTempAlloca(CGF.ConvertType(E->getRHS()->getType()));
+ AggLoc = CGF.CreateMemTemp(E->getRHS()->getType());
CGF.EmitAggExpr(E->getRHS(), AggLoc, VolatileDest);
CGF.EmitObjCPropertySet(LHS.getKVCRefExpr(),
RValue::getAggregate(AggLoc, VolatileDest));
@@ -408,21 +416,21 @@ void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) {
CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
- CGF.StartConditionalBranch();
+ CGF.BeginConditionalBranch();
CGF.EmitBlock(LHSBlock);
// Handle the GNU extension for missing LHS.
assert(E->getLHS() && "Must have LHS for aggregate value");
Visit(E->getLHS());
- CGF.FinishConditionalBranch();
+ CGF.EndConditionalBranch();
CGF.EmitBranch(ContBlock);
- CGF.StartConditionalBranch();
+ CGF.BeginConditionalBranch();
CGF.EmitBlock(RHSBlock);
Visit(E->getRHS());
- CGF.FinishConditionalBranch();
+ CGF.EndConditionalBranch();
CGF.EmitBranch(ContBlock);
CGF.EmitBlock(ContBlock);
@@ -449,7 +457,7 @@ void AggExprEmitter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
if (!Val) {
// Create a temporary variable.
- Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
+ Val = CGF.CreateMemTemp(E->getType(), "tmp");
// FIXME: volatile
CGF.EmitAggExpr(E->getSubExpr(), Val, false);
@@ -467,7 +475,7 @@ AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) {
if (!Val) {
// Create a temporary variable.
- Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
+ Val = CGF.CreateMemTemp(E->getType(), "tmp");
}
if (E->requiresZeroInitialization())
@@ -484,7 +492,7 @@ void AggExprEmitter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
if (!Val) {
// Create a temporary variable.
- Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
+ Val = CGF.CreateMemTemp(E->getType(), "tmp");
}
CGF.EmitCXXExprWithTemporaries(E, Val, VolatileDest, IsInitializer);
}
@@ -494,7 +502,7 @@ void AggExprEmitter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
if (!Val) {
// Create a temporary variable.
- Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
+ Val = CGF.CreateMemTemp(E->getType(), "tmp");
}
LValue LV = LValue::MakeAddr(Val, Qualifiers());
EmitNullInitializationToLValue(LV, E->getType());
@@ -505,23 +513,27 @@ void AggExprEmitter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
if (!Val) {
// Create a temporary variable.
- Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
+ Val = CGF.CreateMemTemp(E->getType(), "tmp");
}
LValue LV = LValue::MakeAddr(Val, Qualifiers());
EmitNullInitializationToLValue(LV, E->getType());
}
-void AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
+void
+AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV, QualType T) {
// FIXME: Ignore result?
// FIXME: Are initializers affected by volatile?
if (isa<ImplicitValueInitExpr>(E)) {
- EmitNullInitializationToLValue(LV, E->getType());
- } else if (E->getType()->isComplexType()) {
+ EmitNullInitializationToLValue(LV, T);
+ } else if (T->isReferenceType()) {
+ RValue RV = CGF.EmitReferenceBindingToExpr(E, /*IsInitializer=*/false);
+ CGF.EmitStoreThroughLValue(RV, LV, T);
+ } else if (T->isAnyComplexType()) {
CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false);
- } else if (CGF.hasAggregateLLVMType(E->getType())) {
+ } else if (CGF.hasAggregateLLVMType(T)) {
CGF.EmitAnyExpr(E, LV.getAddress(), false);
} else {
- CGF.EmitStoreThroughLValue(CGF.EmitAnyExpr(E), LV, E->getType());
+ CGF.EmitStoreThroughLValue(CGF.EmitAnyExpr(E), LV, T);
}
}
@@ -590,7 +602,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
llvm::Value *NextVal = Builder.CreateStructGEP(DestPtr, i, ".array");
if (i < NumInitElements)
EmitInitializationToLValue(E->getInit(i),
- LValue::MakeAddr(NextVal, Quals));
+ LValue::MakeAddr(NextVal, Quals),
+ ElementType);
else
EmitNullInitializationToLValue(LValue::MakeAddr(NextVal, Quals),
ElementType);
@@ -627,11 +640,11 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
// FIXME: volatility
FieldDecl *Field = E->getInitializedFieldInUnion();
- LValue FieldLoc = CGF.EmitLValueForField(DestPtr, Field, true, 0);
+ LValue FieldLoc = CGF.EmitLValueForFieldInitialization(DestPtr, Field, 0);
if (NumInitElements) {
// Store the initializer into the field
- EmitInitializationToLValue(E->getInit(0), FieldLoc);
+ EmitInitializationToLValue(E->getInit(0), FieldLoc, Field->getType());
} else {
// Default-initialize to null
EmitNullInitializationToLValue(FieldLoc, Field->getType());
@@ -653,12 +666,13 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
continue;
// FIXME: volatility
- LValue FieldLoc = CGF.EmitLValueForField(DestPtr, *Field, false, 0);
+ LValue FieldLoc = CGF.EmitLValueForFieldInitialization(DestPtr, *Field, 0);
// We never generate write-barries for initialized fields.
LValue::SetObjCNonGC(FieldLoc, true);
if (CurInitVal < NumInitElements) {
// Store the initializer into the field
- EmitInitializationToLValue(E->getInit(CurInitVal++), FieldLoc);
+ EmitInitializationToLValue(E->getInit(CurInitVal++), FieldLoc,
+ Field->getType());
} else {
// We're out of initalizers; default-initialize to null
EmitNullInitializationToLValue(FieldLoc, Field->getType());
@@ -674,6 +688,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
/// type. The result is computed into DestPtr. Note that if DestPtr is null,
/// the value of the aggregate expression is not needed. If VolatileDest is
/// true, DestPtr cannot be 0.
+//
+// FIXME: Take Qualifiers object.
void CodeGenFunction::EmitAggExpr(const Expr *E, llvm::Value *DestPtr,
bool VolatileDest, bool IgnoreResult,
bool IsInitializer,
@@ -688,6 +704,14 @@ void CodeGenFunction::EmitAggExpr(const Expr *E, llvm::Value *DestPtr,
.Visit(const_cast<Expr*>(E));
}
+LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
+ assert(hasAggregateLLVMType(E->getType()) && "Invalid argument!");
+ Qualifiers Q = MakeQualifiers(E->getType());
+ llvm::Value *Temp = CreateMemTemp(E->getType());
+ EmitAggExpr(E, Temp, Q.hasVolatile());
+ return LValue::MakeAddr(Temp, Q);
+}
+
void CodeGenFunction::EmitAggregateClear(llvm::Value *DestPtr, QualType Ty) {
assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex");
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index e264109f02f0..032862160464 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -42,8 +42,10 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
// And the rest of the call args
EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
- QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
- return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
+ QualType ResultType = FPT->getResultType();
+ return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args,
+ FPT->getCallConv(),
+ FPT->getNoReturnAttr()), Callee,
ReturnValue, Args, MD);
}
@@ -60,7 +62,7 @@ static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) {
}
// We can always devirtualize calls on temporary object expressions.
- if (isa<CXXTemporaryObjectExpr>(Base))
+ if (isa<CXXConstructExpr>(Base))
return true;
// And calls on bound temporaries.
@@ -159,12 +161,10 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
FPT->isVariadic());
- const llvm::Type *Int8PtrTy =
- llvm::Type::getInt8Ty(VMContext)->getPointerTo();
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
// Get the member function pointer.
- llvm::Value *MemFnPtr =
- CreateTempAlloca(ConvertType(MemFnExpr->getType()), "mem.fn");
+ llvm::Value *MemFnPtr = CreateMemTemp(MemFnExpr->getType(), "mem.fn");
EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false);
// Emit the 'this' pointer.
@@ -206,19 +206,20 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual);
EmitBlock(FnVirtual);
- const llvm::Type *VTableTy =
- FTy->getPointerTo()->getPointerTo()->getPointerTo();
+ const llvm::Type *VtableTy =
+ FTy->getPointerTo()->getPointerTo();
- llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy);
- VTable = Builder.CreateLoad(VTable);
+ llvm::Value *Vtable = Builder.CreateBitCast(This, VtableTy->getPointerTo());
+ Vtable = Builder.CreateLoad(Vtable);
- VTable = Builder.CreateGEP(VTable, FnAsInt, "fn");
+ Vtable = Builder.CreateBitCast(Vtable, Int8PtrTy);
+ llvm::Value *VtableOffset =
+ Builder.CreateSub(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1));
- // Since the function pointer is 1 plus the virtual table offset, we
- // subtract 1 by using a GEP.
- VTable = Builder.CreateConstGEP1_64(VTable, (uint64_t)-1);
+ Vtable = Builder.CreateGEP(Vtable, VtableOffset, "fn");
+ Vtable = Builder.CreateBitCast(Vtable, VtableTy);
- llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn");
+ llvm::Value *VirtualFn = Builder.CreateLoad(Vtable, "virtualfn");
EmitBranch(FnEnd);
EmitBlock(FnNonVirtual);
@@ -244,8 +245,8 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
// And the rest of the call args
EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end());
- QualType ResultType = BO->getType()->getAs<FunctionType>()->getResultType();
- return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
+ const FunctionType *BO_FPT = BO->getType()->getAs<FunctionProtoType>();
+ return EmitCall(CGM.getTypes().getFunctionInfo(Args, BO_FPT), Callee,
ReturnValue, Args);
}
@@ -339,18 +340,20 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
}
else
// Call the constructor.
- EmitCXXConstructorCall(CD, Ctor_Complete, Dest,
+ EmitCXXConstructorCall(CD,
+ E->isBaseInitialization()? Ctor_Base : Ctor_Complete,
+ Dest,
E->arg_begin(), E->arg_end());
}
-static uint64_t CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) {
+static CharUnits CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) {
const RecordType *RT = ElementType->getAs<RecordType>();
if (!RT)
- return 0;
+ return CharUnits::Zero();
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
if (!RD)
- return 0;
+ return CharUnits::Zero();
// Check if the class has a trivial destructor.
if (RD->hasTrivialDestructor()) {
@@ -372,25 +375,25 @@ static uint64_t CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) {
// No usual deallocation function, we don't need a cookie.
if (!UsualDeallocationFunction)
- return 0;
+ return CharUnits::Zero();
// The usual deallocation function doesn't take a size_t argument, so we
// don't need a cookie.
if (UsualDeallocationFunction->getNumParams() == 1)
- return 0;
+ return CharUnits::Zero();
assert(UsualDeallocationFunction->getNumParams() == 2 &&
"Unexpected deallocation function type!");
}
// Padding is the maximum of sizeof(size_t) and alignof(ElementType)
- return std::max(Ctx.getTypeSize(Ctx.getSizeType()),
- static_cast<uint64_t>(Ctx.getTypeAlign(ElementType))) / 8;
+ return std::max(Ctx.getTypeSizeInChars(Ctx.getSizeType()),
+ Ctx.getTypeAlignInChars(ElementType));
}
-static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) {
+static CharUnits CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) {
if (!E->isArray())
- return 0;
+ return CharUnits::Zero();
// No cookie is required if the new operator being used is
// ::operator new[](size_t, void*).
@@ -401,7 +404,7 @@ static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) {
Ctx.getCanonicalType(OperatorNew->getParamDecl(1)->getType());
if (ParamType == Ctx.VoidPtrTy)
- return 0;
+ return CharUnits::Zero();
}
}
@@ -412,25 +415,25 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
const CXXNewExpr *E,
llvm::Value *& NumElements) {
QualType Type = E->getAllocatedType();
- uint64_t TypeSizeInBytes = CGF.getContext().getTypeSize(Type) / 8;
+ CharUnits TypeSize = CGF.getContext().getTypeSizeInChars(Type);
const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
if (!E->isArray())
- return llvm::ConstantInt::get(SizeTy, TypeSizeInBytes);
+ return llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity());
- uint64_t CookiePadding = CalculateCookiePadding(CGF.getContext(), E);
+ CharUnits CookiePadding = CalculateCookiePadding(CGF.getContext(), E);
Expr::EvalResult Result;
if (E->getArraySize()->Evaluate(Result, CGF.getContext()) &&
!Result.HasSideEffects && Result.Val.isInt()) {
- uint64_t AllocSize =
- Result.Val.getInt().getZExtValue() * TypeSizeInBytes + CookiePadding;
+ CharUnits AllocSize =
+ Result.Val.getInt().getZExtValue() * TypeSize + CookiePadding;
NumElements =
llvm::ConstantInt::get(SizeTy, Result.Val.getInt().getZExtValue());
- return llvm::ConstantInt::get(SizeTy, AllocSize);
+ return llvm::ConstantInt::get(SizeTy, AllocSize.getQuantity());
}
// Emit the array size expression.
@@ -439,11 +442,13 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
// Multiply with the type size.
llvm::Value *V =
CGF.Builder.CreateMul(NumElements,
- llvm::ConstantInt::get(SizeTy, TypeSizeInBytes));
+ llvm::ConstantInt::get(SizeTy,
+ TypeSize.getQuantity()));
// And add the cookie padding if necessary.
- if (CookiePadding)
- V = CGF.Builder.CreateAdd(V, llvm::ConstantInt::get(SizeTy, CookiePadding));
+ if (!CookiePadding.isZero())
+ V = CGF.Builder.CreateAdd(V,
+ llvm::ConstantInt::get(SizeTy, CookiePadding.getQuantity()));
return V;
}
@@ -538,7 +543,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// Emit the call to new.
RValue RV =
- EmitCall(CGM.getTypes().getFunctionInfo(NewFTy->getResultType(), NewArgs),
+ EmitCall(CGM.getTypes().getFunctionInfo(NewArgs, NewFTy),
CGM.GetAddrOfFunction(NewFD), ReturnValueSlot(), NewArgs, NewFD);
// If an allocation function is declared with an empty exception specification
@@ -567,20 +572,22 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
Builder.CreateCondBr(IsNull, NewNull, NewNotNull);
EmitBlock(NewNotNull);
}
-
- if (uint64_t CookiePadding = CalculateCookiePadding(getContext(), E)) {
- uint64_t CookieOffset =
- CookiePadding - getContext().getTypeSize(SizeTy) / 8;
+
+ CharUnits CookiePadding = CalculateCookiePadding(getContext(), E);
+ if (!CookiePadding.isZero()) {
+ CharUnits CookieOffset =
+ CookiePadding - getContext().getTypeSizeInChars(SizeTy);
llvm::Value *NumElementsPtr =
- Builder.CreateConstInBoundsGEP1_64(NewPtr, CookieOffset);
+ Builder.CreateConstInBoundsGEP1_64(NewPtr, CookieOffset.getQuantity());
NumElementsPtr = Builder.CreateBitCast(NumElementsPtr,
ConvertType(SizeTy)->getPointerTo());
Builder.CreateStore(NumElements, NumElementsPtr);
// Now add the padding to the new ptr.
- NewPtr = Builder.CreateConstInBoundsGEP1_64(NewPtr, CookiePadding);
+ NewPtr = Builder.CreateConstInBoundsGEP1_64(NewPtr,
+ CookiePadding.getQuantity());
}
NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType()));
@@ -611,23 +618,24 @@ GetAllocatedObjectPtrAndNumElements(CodeGenFunction &CGF,
QualType SizeTy = CGF.getContext().getSizeType();
const llvm::Type *SizeLTy = CGF.ConvertType(SizeTy);
- uint64_t DeleteTypeAlign = CGF.getContext().getTypeAlign(DeleteTy);
- uint64_t CookiePadding = std::max(CGF.getContext().getTypeSize(SizeTy),
- DeleteTypeAlign) / 8;
- assert(CookiePadding && "CookiePadding should not be 0.");
+ CharUnits DeleteTypeAlign = CGF.getContext().getTypeAlignInChars(DeleteTy);
+ CharUnits CookiePadding =
+ std::max(CGF.getContext().getTypeSizeInChars(SizeTy),
+ DeleteTypeAlign);
+ assert(!CookiePadding.isZero() && "CookiePadding should not be 0.");
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- uint64_t CookieOffset =
- CookiePadding - CGF.getContext().getTypeSize(SizeTy) / 8;
+ CharUnits CookieOffset =
+ CookiePadding - CGF.getContext().getTypeSizeInChars(SizeTy);
llvm::Value *AllocatedObjectPtr = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy);
AllocatedObjectPtr =
CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr,
- -CookiePadding);
+ -CookiePadding.getQuantity());
llvm::Value *NumElementsPtr =
CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr,
- CookieOffset);
+ CookieOffset.getQuantity());
NumElementsPtr =
CGF.Builder.CreateBitCast(NumElementsPtr, SizeLTy->getPointerTo());
@@ -651,13 +659,13 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
QualType SizeTy;
if (DeleteFTy->getNumArgs() == 2) {
SizeTy = DeleteFTy->getArgType(1);
- uint64_t DeleteTypeSize = getContext().getTypeSize(DeleteTy) / 8;
- Size = llvm::ConstantInt::get(ConvertType(SizeTy), DeleteTypeSize);
+ CharUnits DeleteTypeSize = getContext().getTypeSizeInChars(DeleteTy);
+ Size = llvm::ConstantInt::get(ConvertType(SizeTy),
+ DeleteTypeSize.getQuantity());
}
if (DeleteFD->getOverloadedOperator() == OO_Array_Delete &&
-
- CalculateCookiePadding(getContext(), DeleteTy)) {
+ !CalculateCookiePadding(getContext(), DeleteTy).isZero()) {
// We need to get the number of elements in the array from the cookie.
llvm::Value *AllocatedObjectPtr;
llvm::Value *NumElements;
@@ -679,8 +687,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
DeleteArgs.push_back(std::make_pair(RValue::get(Size), SizeTy));
// Emit the call to delete.
- EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(),
- DeleteArgs),
+ EmitCall(CGM.getTypes().getFunctionInfo(DeleteArgs, DeleteFTy),
CGM.GetAddrOfFunction(DeleteFD), ReturnValueSlot(),
DeleteArgs, DeleteFD);
}
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 5ec336ce79e9..591534042f51 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -366,7 +366,7 @@ ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
ComplexPairTy Op = Visit(E->getSubExpr());
llvm::Value *ResR, *ResI;
- if (Op.first->getType()->isFloatingPoint()) {
+ if (Op.first->getType()->isFloatingPointTy()) {
ResR = Builder.CreateFNeg(Op.first, "neg.r");
ResI = Builder.CreateFNeg(Op.second, "neg.i");
} else {
@@ -384,7 +384,7 @@ ComplexPairTy ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
// ~(a+ib) = a + i*-b
ComplexPairTy Op = Visit(E->getSubExpr());
llvm::Value *ResI;
- if (Op.second->getType()->isFloatingPoint())
+ if (Op.second->getType()->isFloatingPointTy())
ResI = Builder.CreateFNeg(Op.second, "conj.i");
else
ResI = Builder.CreateNeg(Op.second, "conj.i");
@@ -395,7 +395,7 @@ ComplexPairTy ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) {
llvm::Value *ResR, *ResI;
- if (Op.LHS.first->getType()->isFloatingPoint()) {
+ if (Op.LHS.first->getType()->isFloatingPointTy()) {
ResR = Builder.CreateFAdd(Op.LHS.first, Op.RHS.first, "add.r");
ResI = Builder.CreateFAdd(Op.LHS.second, Op.RHS.second, "add.i");
} else {
@@ -407,7 +407,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) {
ComplexPairTy ComplexExprEmitter::EmitBinSub(const BinOpInfo &Op) {
llvm::Value *ResR, *ResI;
- if (Op.LHS.first->getType()->isFloatingPoint()) {
+ if (Op.LHS.first->getType()->isFloatingPointTy()) {
ResR = Builder.CreateFSub(Op.LHS.first, Op.RHS.first, "sub.r");
ResI = Builder.CreateFSub(Op.LHS.second, Op.RHS.second, "sub.i");
} else {
@@ -422,7 +422,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
using llvm::Value;
Value *ResR, *ResI;
- if (Op.LHS.first->getType()->isFloatingPoint()) {
+ if (Op.LHS.first->getType()->isFloatingPointTy()) {
Value *ResRl = Builder.CreateFMul(Op.LHS.first, Op.RHS.first, "mul.rl");
Value *ResRr = Builder.CreateFMul(Op.LHS.second, Op.RHS.second,"mul.rr");
ResR = Builder.CreateFSub(ResRl, ResRr, "mul.r");
@@ -448,7 +448,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
llvm::Value *DSTr, *DSTi;
- if (Op.LHS.first->getType()->isFloatingPoint()) {
+ if (Op.LHS.first->getType()->isFloatingPointTy()) {
// (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
llvm::Value *Tmp1 = Builder.CreateFMul(LHSr, RHSr, "tmp"); // a*c
llvm::Value *Tmp2 = Builder.CreateFMul(LHSi, RHSi, "tmp"); // b*d
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 7d5b3da0b6c6..3df552d75bb6 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -418,12 +418,19 @@ public:
// Get the function pointer (or index if this is a virtual function).
if (MD->isVirtual()) {
uint64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD);
-
- // The pointer is 1 + the virtual table offset in bytes.
+
+ // Itanium C++ ABI 2.3:
+ // For a non-virtual function, this field is a simple function pointer.
+ // For a virtual function, it is 1 plus the virtual table offset
+ // (in bytes) of the function, represented as a ptrdiff_t.
Values[0] = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1);
} else {
- llvm::Constant *FuncPtr = CGM.GetAddrOfFunction(MD);
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+ llvm::Constant *FuncPtr = CGM.GetAddrOfFunction(MD, Ty);
Values[0] = llvm::ConstantExpr::getPtrToInt(FuncPtr, PtrDiffTy);
}
@@ -438,16 +445,16 @@ public:
if (const MemberPointerType *MPT =
E->getType()->getAs<MemberPointerType>()) {
QualType T = MPT->getPointeeType();
- if (T->isFunctionProtoType()) {
- DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr());
-
- return EmitMemberFunctionPointer(cast<CXXMethodDecl>(DRE->getDecl()));
- }
+ DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr());
+
+ NamedDecl *ND = DRE->getDecl();
+ if (T->isFunctionProtoType())
+ return EmitMemberFunctionPointer(cast<CXXMethodDecl>(ND));
- // FIXME: Should we handle other member pointer types here too,
- // or should they be handled by Expr::Evaluate?
+ // We have a pointer to data member.
+ return CGM.EmitPointerToDataMember(cast<FieldDecl>(ND));
}
-
+
return 0;
}
@@ -534,8 +541,8 @@ public:
llvm::ConstantStruct *CS = cast<llvm::ConstantStruct>(C);
// Check if we need to update the adjustment.
- if (llvm::Constant *Offset = CGM.GetCXXBaseClassOffset(DerivedClass,
- BaseClass)) {
+ if (llvm::Constant *Offset =
+ CGM.GetNonVirtualBaseClassOffset(DerivedClass, BaseClass)) {
llvm::Constant *Values[2];
Values[0] = CS->getOperand(0);
@@ -668,6 +675,40 @@ public:
return 0;
}
+ llvm::Constant *VisitCXXConstructExpr(CXXConstructExpr *E) {
+ if (!E->getConstructor()->isTrivial())
+ return 0;
+
+ QualType Ty = E->getType();
+
+ // FIXME: We should not have to call getBaseElementType here.
+ const RecordType *RT =
+ CGM.getContext().getBaseElementType(Ty)->getAs<RecordType>();
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ // If the class doesn't have a trivial destructor, we can't emit it as a
+ // constant expr.
+ if (!RD->hasTrivialDestructor())
+ return 0;
+
+ // Only copy and default constructors can be trivial.
+
+
+ if (E->getNumArgs()) {
+ assert(E->getNumArgs() == 1 && "trivial ctor with > 1 argument");
+ assert(E->getConstructor()->isCopyConstructor() &&
+ "trivial ctor has argument but isn't a copy ctor");
+
+ Expr *Arg = E->getArg(0);
+ assert(CGM.getContext().hasSameUnqualifiedType(Ty, Arg->getType()) &&
+ "argument to copy ctor is of wrong type");
+
+ return Visit(Arg);
+ }
+
+ return CGM.EmitNullConstant(Ty);
+ }
+
llvm::Constant *VisitStringLiteral(StringLiteral *E) {
assert(!E->getType()->isPointerType() && "Strings are always arrays");
@@ -911,7 +952,24 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
return C;
}
-static inline bool isDataMemberPointerType(QualType T) {
+static bool containsPointerToDataMember(CodeGenTypes &Types, QualType T) {
+ // No need to check for member pointers when not compiling C++.
+ if (!Types.getContext().getLangOptions().CPlusPlus)
+ return false;
+
+ T = Types.getContext().getBaseElementType(T);
+
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ // FIXME: It would be better if there was a way to explicitly compute the
+ // record layout instead of converting to a type.
+ Types.ConvertTagDeclType(RD);
+
+ const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
+ return Layout.containsPointerToDataMember();
+ }
+
if (const MemberPointerType *MPT = T->getAs<MemberPointerType>())
return !MPT->getPointeeType()->isFunctionType();
@@ -919,43 +977,80 @@ static inline bool isDataMemberPointerType(QualType T) {
}
llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
- // No need to check for member pointers when not compiling C++.
- if (!getContext().getLangOptions().CPlusPlus)
+ if (!containsPointerToDataMember(getTypes(), T))
return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T));
-
+
if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(T)) {
QualType ElementTy = CAT->getElementType();
- // FIXME: Handle arrays of structs that contain member pointers.
- if (isDataMemberPointerType(Context.getBaseElementType(ElementTy))) {
- llvm::Constant *Element = EmitNullConstant(ElementTy);
- uint64_t NumElements = CAT->getSize().getZExtValue();
- std::vector<llvm::Constant *> Array(NumElements);
- for (uint64_t i = 0; i != NumElements; ++i)
- Array[i] = Element;
+ llvm::Constant *Element = EmitNullConstant(ElementTy);
+ unsigned NumElements = CAT->getSize().getZExtValue();
+ std::vector<llvm::Constant *> Array(NumElements);
+ for (unsigned i = 0; i != NumElements; ++i)
+ Array[i] = Element;
- const llvm::ArrayType *ATy =
- cast<llvm::ArrayType>(getTypes().ConvertTypeForMem(T));
- return llvm::ConstantArray::get(ATy, Array);
- }
+ const llvm::ArrayType *ATy =
+ cast<llvm::ArrayType>(getTypes().ConvertTypeForMem(T));
+ return llvm::ConstantArray::get(ATy, Array);
}
if (const RecordType *RT = T->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl();
- // FIXME: It would be better if there was a way to explicitly compute the
- // record layout instead of converting to a type.
- Types.ConvertTagDeclType(RD);
-
- const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
- if (Layout.containsMemberPointer()) {
- assert(0 && "FIXME: No support for structs with member pointers yet!");
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ assert(!RD->getNumBases() &&
+ "FIXME: Handle zero-initializing structs with bases and "
+ "pointers to data members.");
+ const llvm::StructType *STy =
+ cast<llvm::StructType>(getTypes().ConvertTypeForMem(T));
+ unsigned NumElements = STy->getNumElements();
+ std::vector<llvm::Constant *> Elements(NumElements);
+
+ for (RecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I != E; ++I) {
+ const FieldDecl *FD = *I;
+
+ unsigned FieldNo = getTypes().getLLVMFieldNo(FD);
+ Elements[FieldNo] = EmitNullConstant(FD->getType());
+ }
+
+ // Now go through all other fields and zero them out.
+ for (unsigned i = 0; i != NumElements; ++i) {
+ if (!Elements[i])
+ Elements[i] = llvm::Constant::getNullValue(STy->getElementType(i));
}
+
+ return llvm::ConstantStruct::get(STy, Elements);
}
- // FIXME: Handle structs that contain member pointers.
- if (isDataMemberPointerType(T))
- return llvm::Constant::getAllOnesValue(getTypes().ConvertTypeForMem(T));
+ assert(!T->getAs<MemberPointerType>()->getPointeeType()->isFunctionType() &&
+ "Should only see pointers to data members here!");
+
+ // Itanium C++ ABI 2.3:
+ // A NULL pointer is represented as -1.
+ return llvm::ConstantInt::get(getTypes().ConvertTypeForMem(T), -1ULL,
+ /*isSigned=*/true);
+}
+
+llvm::Constant *
+CodeGenModule::EmitPointerToDataMember(const FieldDecl *FD) {
+
+ // Itanium C++ ABI 2.3:
+ // A pointer to data member is an offset from the base address of the class
+ // object containing it, represented as a ptrdiff_t
+
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(FD->getParent());
+ QualType ClassType =
+ getContext().getTypeDeclType(const_cast<CXXRecordDecl *>(ClassDecl));
+
+ const llvm::StructType *ClassLTy =
+ cast<llvm::StructType>(getTypes().ConvertType(ClassType));
+
+ unsigned FieldNo = getTypes().getLLVMFieldNo(FD);
+ uint64_t Offset =
+ getTargetData().getStructLayout(ClassLTy)->getElementOffset(FieldNo);
+
+ const llvm::Type *PtrDiffTy =
+ getTypes().ConvertType(getContext().getPointerDiffType());
- return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T));
+ return llvm::ConstantInt::get(PtrDiffTy, Offset);
}
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 690a7dc2fded..db0998b4dedc 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -290,7 +290,7 @@ public:
if (CGF.getContext().getLangOptions().OverflowChecking
&& Ops.Ty->isSignedIntegerType())
return EmitOverflowCheckedBinOp(Ops);
- if (Ops.LHS->getType()->isFPOrFPVector())
+ if (Ops.LHS->getType()->isFPOrFPVectorTy())
return Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul");
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
}
@@ -388,8 +388,6 @@ Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) {
}
if (SrcType->isMemberPointerType()) {
- // FIXME: This is ABI specific.
-
// Compare against -1.
llvm::Value *NegativeOne = llvm::Constant::getAllOnesValue(Src->getType());
return Builder.CreateICmpNE(Src, NegativeOne, "tobool");
@@ -507,7 +505,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
return Builder.CreateUIToFP(Src, DstTy, "conv");
}
- assert(Src->getType()->isFloatingPoint() && "Unknown real conversion");
+ assert(Src->getType()->isFloatingPointTy() && "Unknown real conversion");
if (isa<llvm::IntegerType>(DstTy)) {
if (DstType->isSignedIntegerType())
return Builder.CreateFPToSI(Src, DstTy, "conv");
@@ -515,7 +513,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
return Builder.CreateFPToUI(Src, DstTy, "conv");
}
- assert(DstTy->isFloatingPoint() && "Unknown real conversion");
+ assert(DstTy->isFloatingPointTy() && "Unknown real conversion");
if (DstTy->getTypeID() < Src->getType()->getTypeID())
return Builder.CreateFPTrunc(Src, DstTy, "conv");
else
@@ -891,8 +889,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
std::swap(DerivedDecl, BaseDecl);
- llvm::Constant *Adj = CGF.CGM.GetCXXBaseClassOffset(DerivedDecl, BaseDecl);
- if (Adj) {
+ if (llvm::Constant *Adj =
+ CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, BaseDecl)) {
if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
Src = Builder.CreateSub(Src, Adj, "adj");
else
@@ -1009,7 +1007,7 @@ Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
TestAndClearIgnoreResultAssign();
Value *Op = Visit(E->getSubExpr());
- if (Op->getType()->isFPOrFPVector())
+ if (Op->getType()->isFPOrFPVectorTy())
return Builder.CreateFNeg(Op, "neg");
return Builder.CreateNeg(Op, "neg");
}
@@ -1154,7 +1152,7 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
- if (Ops.LHS->getType()->isFPOrFPVector())
+ if (Ops.LHS->getType()->isFPOrFPVectorTy())
return Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
else if (Ops.Ty->isUnsignedIntegerType())
return Builder.CreateUDiv(Ops.LHS, Ops.RHS, "div");
@@ -1261,7 +1259,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
Ops.Ty->isSignedIntegerType())
return EmitOverflowCheckedBinOp(Ops);
- if (Ops.LHS->getType()->isFPOrFPVector())
+ if (Ops.LHS->getType()->isFPOrFPVectorTy())
return Builder.CreateFAdd(Ops.LHS, Ops.RHS, "add");
// Signed integer overflow is undefined behavior.
@@ -1337,7 +1335,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
&& Ops.Ty->isSignedIntegerType())
return EmitOverflowCheckedBinOp(Ops);
- if (Ops.LHS->getType()->isFPOrFPVector())
+ if (Ops.LHS->getType()->isFPOrFPVectorTy())
return Builder.CreateFSub(Ops.LHS, Ops.RHS, "sub");
return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub");
}
@@ -1505,7 +1503,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
Value *LHS = Visit(E->getLHS());
Value *RHS = Visit(E->getRHS());
- if (LHS->getType()->isFPOrFPVector()) {
+ if (LHS->getType()->isFPOrFPVectorTy()) {
Result = Builder.CreateFCmp((llvm::CmpInst::Predicate)FCmpOpc,
LHS, RHS, "cmp");
} else if (LHSTy->isSignedIntegerType()) {
@@ -1615,10 +1613,10 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
PI != PE; ++PI)
PN->addIncoming(llvm::ConstantInt::getFalse(VMContext), *PI);
- CGF.StartConditionalBranch();
+ CGF.BeginConditionalBranch();
CGF.EmitBlock(RHSBlock);
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
- CGF.FinishConditionalBranch();
+ CGF.EndConditionalBranch();
// Reaquire the RHS block, as there may be subblocks inserted.
RHSBlock = Builder.GetInsertBlock();
@@ -1665,13 +1663,13 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
PI != PE; ++PI)
PN->addIncoming(llvm::ConstantInt::getTrue(VMContext), *PI);
- CGF.StartConditionalBranch();
+ CGF.BeginConditionalBranch();
// Emit the RHS condition as a bool value.
CGF.EmitBlock(RHSBlock);
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
- CGF.FinishConditionalBranch();
+ CGF.EndConditionalBranch();
// Reaquire the RHS block, as there may be subblocks inserted.
RHSBlock = Builder.GetInsertBlock();
@@ -1785,7 +1783,7 @@ VisitConditionalOperator(const ConditionalOperator *E) {
Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock);
}
- CGF.StartConditionalBranch();
+ CGF.BeginConditionalBranch();
CGF.EmitBlock(LHSBlock);
// Handle the GNU extension for missing LHS.
@@ -1795,15 +1793,15 @@ VisitConditionalOperator(const ConditionalOperator *E) {
else // Perform promotions, to handle cases like "short ?: int"
LHS = EmitScalarConversion(CondVal, E->getCond()->getType(), E->getType());
- CGF.FinishConditionalBranch();
+ CGF.EndConditionalBranch();
LHSBlock = Builder.GetInsertBlock();
CGF.EmitBranch(ContBlock);
- CGF.StartConditionalBranch();
+ CGF.BeginConditionalBranch();
CGF.EmitBlock(RHSBlock);
Value *RHS = Visit(E->getRHS());
- CGF.FinishConditionalBranch();
+ CGF.EndConditionalBranch();
RHSBlock = Builder.GetInsertBlock();
CGF.EmitBranch(ContBlock);
@@ -1882,14 +1880,23 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
llvm::Value *V;
// object->isa or (*object).isa
// Generate code as for: *(Class*)object
+ // build Class* type
+ const llvm::Type *ClassPtrTy = ConvertType(E->getType());
+
Expr *BaseExpr = E->getBase();
- if (E->isArrow())
- V = ScalarExprEmitter(*this).EmitLoadOfLValue(BaseExpr);
- else
- V = EmitLValue(BaseExpr).getAddress();
+ if (BaseExpr->isLvalue(getContext()) != Expr::LV_Valid) {
+ V = CreateTempAlloca(ClassPtrTy, "resval");
+ llvm::Value *Src = EmitScalarExpr(BaseExpr);
+ Builder.CreateStore(Src, V);
+ }
+ else {
+ if (E->isArrow())
+ V = ScalarExprEmitter(*this).EmitLoadOfLValue(BaseExpr);
+ else
+ V = EmitLValue(BaseExpr).getAddress();
+ }
// build Class* type
- const llvm::Type *ClassPtrTy = ConvertType(E->getType());
ClassPtrTy = ClassPtrTy->getPointerTo();
V = Builder.CreateBitCast(V, ClassPtrTy);
LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType()));
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 896d2207ea4b..b62e6ed44366 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -122,7 +122,7 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
E = OMD->param_end(); PI != E; ++PI)
Args.push_back(std::make_pair(*PI, (*PI)->getType()));
- StartFunction(OMD, OMD->getResultType(), Fn, Args, OMD->getLocEnd());
+ StartFunction(OMD, OMD->getResultType(), Fn, Args, OMD->getLocStart());
}
/// Generate an Objective-C method. An Objective-C method is a C function with
@@ -190,7 +190,8 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
Args.push_back(std::make_pair(RValue::get(True), getContext().BoolTy));
// FIXME: We shouldn't need to get the function info here, the
// runtime already should have computed it to build the function.
- RValue RV = EmitCall(Types.getFunctionInfo(PD->getType(), Args),
+ RValue RV = EmitCall(Types.getFunctionInfo(PD->getType(), Args,
+ CC_Default, false),
GetPropertyFn, ReturnValueSlot(), Args);
// We need to fix the type here. Ivars with copy & retain are
// always objects so we don't need to worry about complex or
@@ -278,7 +279,8 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
getContext().BoolTy));
// FIXME: We shouldn't need to get the function info here, the runtime
// already should have computed it to build the function.
- EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args), SetPropertyFn,
+ EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
+ CC_Default, false), SetPropertyFn,
ReturnValueSlot(), Args);
} else {
// FIXME: Find a clean way to avoid AST node creation.
@@ -450,9 +452,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
// Fast enumeration state.
QualType StateTy = getContext().getObjCFastEnumerationStateType();
- llvm::AllocaInst *StatePtr = CreateTempAlloca(ConvertType(StateTy),
- "state.ptr");
- StatePtr->setAlignment(getContext().getTypeAlign(StateTy) >> 3);
+ llvm::Value *StatePtr = CreateMemTemp(StateTy, "state.ptr");
EmitMemSetToZero(StatePtr, StateTy);
// Number of elements in the items array.
@@ -470,7 +470,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
getContext().getConstantArrayType(getContext().getObjCIdType(),
llvm::APInt(32, NumItems),
ArrayType::Normal, 0);
- llvm::Value *ItemsPtr = CreateTempAlloca(ConvertType(ItemsTy), "items.ptr");
+ llvm::Value *ItemsPtr = CreateMemTemp(ItemsTy, "items.ptr");
llvm::Value *Collection = EmitScalarExpr(S.getCollection());
@@ -492,7 +492,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
FastEnumSel,
Collection, false, Args);
- llvm::Value *LimitPtr = CreateTempAlloca(UnsignedLongLTy, "limit.ptr");
+ llvm::Value *LimitPtr = CreateMemTemp(getContext().UnsignedLongTy,
+ "limit.ptr");
Builder.CreateStore(CountRV.getScalarVal(), LimitPtr);
llvm::BasicBlock *NoElements = createBasicBlock("noelements");
@@ -506,8 +507,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
EmitBlock(SetStartMutations);
- llvm::Value *StartMutationsPtr =
- CreateTempAlloca(UnsignedLongLTy);
+ llvm::Value *StartMutationsPtr = CreateMemTemp(getContext().UnsignedLongTy);
llvm::Value *StateMutationsPtrPtr =
Builder.CreateStructGEP(StatePtr, 2, "mutationsptr.ptr");
@@ -522,7 +522,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
llvm::BasicBlock *LoopStart = createBasicBlock("loopstart");
EmitBlock(LoopStart);
- llvm::Value *CounterPtr = CreateTempAlloca(UnsignedLongLTy, "counter.ptr");
+ llvm::Value *CounterPtr = CreateMemTemp(getContext().UnsignedLongTy,
+ "counter.ptr");
Builder.CreateStore(Zero, CounterPtr);
llvm::BasicBlock *LoopBody = createBasicBlock("loopbody");
@@ -553,7 +554,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
getContext().getObjCIdType()));
// FIXME: We shouldn't need to get the function info here, the runtime already
// should have computed it to build the function.
- EmitCall(CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args2),
+ EmitCall(CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args2,
+ CC_Default, false),
EnumerationMutationFn, ReturnValueSlot(), Args2);
EmitBlock(WasNotMutated);
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 77be9fb58231..1d38ef9e2d2f 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -55,6 +55,7 @@ private:
const llvm::PointerType *PtrToInt8Ty;
const llvm::FunctionType *IMPTy;
const llvm::PointerType *IdTy;
+ const llvm::PointerType *PtrToIdTy;
QualType ASTIdTy;
const llvm::IntegerType *IntTy;
const llvm::PointerType *PtrTy;
@@ -65,11 +66,17 @@ private:
std::vector<llvm::Constant*> Classes;
std::vector<llvm::Constant*> Categories;
std::vector<llvm::Constant*> ConstantStrings;
+ llvm::StringMap<llvm::Constant*> ObjCStrings;
llvm::Function *LoadFunction;
llvm::StringMap<llvm::Constant*> ExistingProtocols;
typedef std::pair<std::string, std::string> TypedSelector;
std::map<TypedSelector, llvm::GlobalAlias*> TypedSelectors;
llvm::StringMap<llvm::GlobalAlias*> UntypedSelectors;
+ // Selectors that we don't emit in GC mode
+ Selector RetainSel, ReleaseSel, AutoreleaseSel;
+ // Functions used for GC.
+ llvm::Constant *IvarAssignFn, *StrongCastAssignFn, *MemMoveFn, *WeakReadFn,
+ *WeakAssignFn, *GlobalAssignFn;
// Some zeros used for GEPs in lots of places.
llvm::Constant *Zeros[2];
llvm::Constant *NULLPtr;
@@ -114,14 +121,18 @@ private:
llvm::Constant *ExportUniqueString(const std::string &Str, const std::string
prefix);
llvm::Constant *MakeGlobal(const llvm::StructType *Ty,
- std::vector<llvm::Constant*> &V, const std::string &Name="",
+ std::vector<llvm::Constant*> &V, llvm::StringRef Name="",
llvm::GlobalValue::LinkageTypes linkage=llvm::GlobalValue::InternalLinkage);
llvm::Constant *MakeGlobal(const llvm::ArrayType *Ty,
- std::vector<llvm::Constant*> &V, const std::string &Name="",
+ std::vector<llvm::Constant*> &V, llvm::StringRef Name="",
llvm::GlobalValue::LinkageTypes linkage=llvm::GlobalValue::InternalLinkage);
llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *Ivar);
void EmitClassRef(const std::string &className);
+ llvm::Value* EnforceType(CGBuilderTy B, llvm::Value *V, const llvm::Type *Ty){
+ if (V->getType() == Ty) return V;
+ return B.CreateBitCast(V, Ty);
+ }
public:
CGObjCGNU(CodeGen::CodeGenModule &cgm);
virtual llvm::Constant *GenerateConstantString(const StringLiteral *);
@@ -257,12 +268,54 @@ CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
} else {
IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
}
+ PtrToIdTy = llvm::PointerType::getUnqual(IdTy);
// IMP type
std::vector<const llvm::Type*> IMPArgs;
IMPArgs.push_back(IdTy);
IMPArgs.push_back(SelectorTy);
IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true);
+
+ if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ // Get selectors needed in GC mode
+ RetainSel = GetNullarySelector("retain", CGM.getContext());
+ ReleaseSel = GetNullarySelector("release", CGM.getContext());
+ AutoreleaseSel = GetNullarySelector("autorelease", CGM.getContext());
+
+ // Get functions needed in GC mode
+
+ // id objc_assign_ivar(id, id, ptrdiff_t);
+ std::vector<const llvm::Type*> Args(1, IdTy);
+ Args.push_back(PtrToIdTy);
+ // FIXME: ptrdiff_t
+ Args.push_back(LongTy);
+ llvm::FunctionType *FTy = llvm::FunctionType::get(IdTy, Args, false);
+ IvarAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar");
+ // id objc_assign_strongCast (id, id*)
+ Args.pop_back();
+ FTy = llvm::FunctionType::get(IdTy, Args, false);
+ StrongCastAssignFn =
+ CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast");
+ // id objc_assign_global(id, id*);
+ FTy = llvm::FunctionType::get(IdTy, Args, false);
+ GlobalAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_global");
+ // id objc_assign_weak(id, id*);
+ FTy = llvm::FunctionType::get(IdTy, Args, false);
+ WeakAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_weak");
+ // id objc_read_weak(id*);
+ Args.clear();
+ Args.push_back(PtrToIdTy);
+ FTy = llvm::FunctionType::get(IdTy, Args, false);
+ WeakReadFn = CGM.CreateRuntimeFunction(FTy, "objc_read_weak");
+ // void *objc_memmove_collectable(void*, void *, size_t);
+ Args.clear();
+ Args.push_back(PtrToInt8Ty);
+ Args.push_back(PtrToInt8Ty);
+ // FIXME: size_t
+ Args.push_back(LongTy);
+ FTy = llvm::FunctionType::get(IdTy, Args, false);
+ MemMoveFn = CGM.CreateRuntimeFunction(FTy, "objc_memmove_collectable");
+ }
}
// This has to perform the lookup every time, since posing and related
@@ -340,7 +393,7 @@ llvm::Constant *CGObjCGNU::ExportUniqueString(const std::string &Str,
}
llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::StructType *Ty,
- std::vector<llvm::Constant*> &V, const std::string &Name,
+ std::vector<llvm::Constant*> &V, llvm::StringRef Name,
llvm::GlobalValue::LinkageTypes linkage) {
llvm::Constant *C = llvm::ConstantStruct::get(Ty, V);
return new llvm::GlobalVariable(TheModule, Ty, false,
@@ -348,7 +401,7 @@ llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::StructType *Ty,
}
llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty,
- std::vector<llvm::Constant*> &V, const std::string &Name,
+ std::vector<llvm::Constant*> &V, llvm::StringRef Name,
llvm::GlobalValue::LinkageTypes linkage) {
llvm::Constant *C = llvm::ConstantArray::get(Ty, V);
return new llvm::GlobalVariable(TheModule, Ty, false,
@@ -357,8 +410,14 @@ llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty,
/// Generate an NSConstantString object.
llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) {
+
std::string Str(SL->getStrData(), SL->getByteLength());
+ // Look for an existing one
+ llvm::StringMap<llvm::Constant*>::iterator old = ObjCStrings.find(Str);
+ if (old != ObjCStrings.end())
+ return old->getValue();
+
std::vector<llvm::Constant*> Ivars;
Ivars.push_back(NULLPtr);
Ivars.push_back(MakeConstantString(Str));
@@ -366,8 +425,9 @@ llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) {
llvm::Constant *ObjCStr = MakeGlobal(
llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty, IntTy, NULL),
Ivars, ".objc_str");
- ConstantStrings.push_back(
- llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty));
+ ObjCStr = llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty);
+ ObjCStrings[Str] = ObjCStr;
+ ConstantStrings.push_back(ObjCStr);
return ObjCStr;
}
@@ -384,6 +444,14 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
bool IsClassMessage,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method) {
+ if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ if (Sel == RetainSel || Sel == AutoreleaseSel) {
+ return RValue::get(Receiver);
+ }
+ if (Sel == ReleaseSel) {
+ return RValue::get(0);
+ }
+ }
llvm::Value *cmd = GetSelector(CGF.Builder, Sel);
CallArgList ActualArgs;
@@ -396,7 +464,8 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
CodeGenTypes &Types = CGM.getTypes();
- const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs);
+ const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
+ CC_Default, false);
const llvm::FunctionType *impType =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
@@ -478,6 +547,14 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
bool IsClassMessage,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method) {
+ if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ if (Sel == RetainSel || Sel == AutoreleaseSel) {
+ return RValue::get(Receiver);
+ }
+ if (Sel == ReleaseSel) {
+ return RValue::get(0);
+ }
+ }
CGBuilderTy &Builder = CGF.Builder;
IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
llvm::Value *cmd;
@@ -495,7 +572,8 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
CodeGenTypes &Types = CGM.getTypes();
- const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs);
+ const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
+ CC_Default, false);
const llvm::FunctionType *impType =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
@@ -1517,7 +1595,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion));
}
// sizeof(ModuleTy)
- llvm::TargetData td = llvm::TargetData::TargetData(&TheModule);
+ llvm::TargetData td(&TheModule);
Elements.push_back(llvm::ConstantInt::get(LongTy,
td.getTypeSizeInBits(ModuleTy)/8));
//FIXME: Should be the path to the file where this module was declared
@@ -1610,7 +1688,8 @@ llvm::Constant *CGObjCGNU::EnumerationMutationFunction() {
llvm::SmallVector<QualType,16> Params;
Params.push_back(ASTIdTy);
const llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false);
+ Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
+ CC_Default, false), false);
return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
}
@@ -1668,7 +1747,6 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.EmitBlock(TryHandler);
// Get the correct versions of the exception handling intrinsics
- llvm::TargetData td = llvm::TargetData::TargetData(&TheModule);
llvm::Value *llvm_eh_exception =
CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
llvm::Value *llvm_eh_selector =
@@ -1899,35 +1977,58 @@ void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
llvm::Value *AddrWeakObj) {
- return 0;
+ CGBuilderTy B = CGF.Builder;
+ AddrWeakObj = EnforceType(B, AddrWeakObj, IdTy);
+ return B.CreateCall(WeakReadFn, AddrWeakObj);
}
void CGObjCGNU::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
- return;
+ CGBuilderTy B = CGF.Builder;
+ src = EnforceType(B, src, IdTy);
+ dst = EnforceType(B, dst, PtrToIdTy);
+ B.CreateCall2(WeakAssignFn, src, dst);
}
void CGObjCGNU::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
- return;
+ CGBuilderTy B = CGF.Builder;
+ src = EnforceType(B, src, IdTy);
+ dst = EnforceType(B, dst, PtrToIdTy);
+ B.CreateCall2(GlobalAssignFn, src, dst);
}
void CGObjCGNU::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst,
llvm::Value *ivarOffset) {
- return;
+ CGBuilderTy B = CGF.Builder;
+ src = EnforceType(B, src, IdTy);
+ dst = EnforceType(B, dst, PtrToIdTy);
+ B.CreateCall3(IvarAssignFn, src, dst, ivarOffset);
}
void CGObjCGNU::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
- return;
+ CGBuilderTy B = CGF.Builder;
+ src = EnforceType(B, src, IdTy);
+ dst = EnforceType(B, dst, PtrToIdTy);
+ B.CreateCall2(StrongCastAssignFn, src, dst);
}
void CGObjCGNU::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
llvm::Value *DestPtr,
llvm::Value *SrcPtr,
QualType Ty) {
- return;
+ CGBuilderTy B = CGF.Builder;
+ DestPtr = EnforceType(B, DestPtr, IdTy);
+ SrcPtr = EnforceType(B, SrcPtr, PtrToIdTy);
+
+ std::pair<uint64_t, unsigned> TypeInfo = CGM.getContext().getTypeInfo(Ty);
+ unsigned long size = TypeInfo.first/8;
+ // FIXME: size_t
+ llvm::Value *N = llvm::ConstantInt::get(LongTy, size);
+
+ B.CreateCall3(MemMoveFn, DestPtr, SrcPtr, N);
}
llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 137ea51721c7..b16a510f98f6 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/CodeGen/CodeGenOptions.h"
#include "llvm/Intrinsics.h"
#include "llvm/LLVMContext.h"
@@ -304,7 +305,8 @@ public:
Params.push_back(Ctx.LongTy);
Params.push_back(Ctx.BoolTy);
const llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.getFunctionInfo(IdType, Params), false);
+ Types.GetFunctionType(Types.getFunctionInfo(IdType, Params,
+ CC_Default, false), false);
return CGM.CreateRuntimeFunction(FTy, "objc_getProperty");
}
@@ -322,7 +324,8 @@ public:
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
const llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false);
+ Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
+ CC_Default, false), false);
return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
}
@@ -333,7 +336,8 @@ public:
llvm::SmallVector<QualType,16> Params;
Params.push_back(Ctx.getObjCIdType());
const llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false);
+ Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
+ CC_Default, false), false);
return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
}
@@ -734,7 +738,8 @@ public:
return CGM.CreateRuntimeFunction(
llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
Params, false),
- "_Unwind_Resume_or_Rethrow");
+ (CGM.getLangOptions().SjLjExceptions ? "_Unwind_SjLj_Resume" :
+ "_Unwind_Resume_or_Rethrow"));
}
llvm::Constant *getObjCEndCatchFn() {
@@ -1553,7 +1558,8 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
CodeGenTypes &Types = CGM.getTypes();
- const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs);
+ const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
+ CC_Default, false);
const llvm::FunctionType *FTy =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
@@ -3625,7 +3631,7 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
Ctx.getObjCIdType(), 0, 0, false));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
Ctx.getObjCClassType(), 0, 0, false));
- RD->completeDefinition(Ctx);
+ RD->completeDefinition();
SuperCTy = Ctx.getTagDeclType(RD);
SuperPtrCTy = Ctx.getPointerType(SuperCTy);
@@ -4086,7 +4092,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
Ctx.VoidPtrTy, 0, 0, false));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
Ctx.getObjCSelType(), 0, 0, false));
- RD->completeDefinition(Ctx);
+ RD->completeDefinition();
MessageRefCTy = Ctx.getTagDeclType(RD);
MessageRefCPtrTy = Ctx.getPointerType(MessageRefCTy);
@@ -4224,6 +4230,9 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
/// message dispatch call for all the rest.
///
bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) {
+ if (CGM.getCodeGenOpts().ObjCLegacyDispatch)
+ return true;
+
if (NonLegacyDispatchMethods.empty()) {
NonLegacyDispatchMethods.insert(GetNullarySelector("alloc"));
NonLegacyDispatchMethods.insert(GetNullarySelector("class"));
@@ -5085,7 +5094,8 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
// FIXME. This is too much work to get the ABI-specific result type needed to
// find the message name.
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType,
- llvm::SmallVector<QualType, 16>());
+ llvm::SmallVector<QualType, 16>(),
+ CC_Default, false);
llvm::Constant *Fn = 0;
std::string Name("\01l_");
if (CGM.ReturnTypeUsesSret(FnInfo)) {
@@ -5159,7 +5169,8 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
ActualArgs.push_back(std::make_pair(RValue::get(Arg1),
ObjCTypes.MessageRefCPtrTy));
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
- const CGFunctionInfo &FnInfo1 = Types.getFunctionInfo(ResultType, ActualArgs);
+ const CGFunctionInfo &FnInfo1 = Types.getFunctionInfo(ResultType, ActualArgs,
+ CC_Default, false);
llvm::Value *Callee = CGF.Builder.CreateStructGEP(Arg1, 0);
Callee = CGF.Builder.CreateLoad(Callee);
const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo1, true);
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index 29552ce4441c..5236d2063489 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -256,6 +256,9 @@ bool ShouldUseExternalRTTIDescriptor(QualType Ty) {
if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (!RD->hasDefinition())
+ return false;
+
if (!RD->isDynamicClass())
return false;
@@ -469,7 +472,7 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) {
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
- if (!RD->getNumBases()) {
+ if (!RD->hasDefinition() || !RD->getNumBases()) {
// abi::__class_type_info.
VtableName = "_ZTVN10__cxxabiv117__class_type_infoE";
} else if (CanUseSingleInheritance(RD)) {
@@ -566,7 +569,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) {
case Type::Record: {
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
- if (!RD->getNumBases()) {
+ if (!RD->hasDefinition() || !RD->getNumBases()) {
// We don't need to emit any fields.
break;
}
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 9f90ec5ff6e0..baafd6836c63 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -108,6 +108,9 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
return true;
}
+ // Check if we have a pointer to data member in this field.
+ CheckForPointerToDataMember(D->getType());
+
assert(FieldOffset % 8 == 0 && "FieldOffset is not on a byte boundary!");
uint64_t FieldOffsetInBytes = FieldOffset / 8;
@@ -162,6 +165,8 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
uint64_t Size = 0;
unsigned Align = 0;
+ bool HasOnlyZeroSizedBitFields = true;
+
unsigned FieldNo = 0;
for (RecordDecl::field_iterator Field = D->field_begin(),
FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
@@ -181,6 +186,8 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
} else
Types.addFieldInfo(*Field, 0);
+ HasOnlyZeroSizedBitFields = false;
+
const llvm::Type *FieldTy =
Types.ConvertTypeForMemRecursive(Field->getType());
unsigned FieldAlign = Types.getTargetData().getABITypeAlignment(FieldTy);
@@ -207,7 +214,8 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
}
}
if (!Align) {
- assert((D->field_begin() == D->field_end()) && "LayoutUnion - Align 0");
+ assert(HasOnlyZeroSizedBitFields &&
+ "0-align record did not have all zero-sized bit-fields!");
Align = 1;
}
@@ -333,23 +341,34 @@ uint64_t CGRecordLayoutBuilder::getTypeSizeInBytes(const llvm::Type *Ty) const {
return Types.getTargetData().getTypeAllocSize(Ty);
}
-void CGRecordLayoutBuilder::CheckForMemberPointer(const FieldDecl *FD) {
+void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) {
// This record already contains a member pointer.
- if (ContainsMemberPointer)
+ if (ContainsPointerToDataMember)
return;
// Can only have member pointers if we're compiling C++.
if (!Types.getContext().getLangOptions().CPlusPlus)
return;
- QualType Ty = FD->getType();
-
- if (Ty->isMemberPointerType()) {
- // We have a member pointer!
- ContainsMemberPointer = true;
- return;
- }
+ T = Types.getContext().getBaseElementType(T);
+ if (const MemberPointerType *MPT = T->getAs<MemberPointerType>()) {
+ if (!MPT->getPointeeType()->isFunctionType()) {
+ // We have a pointer to data member.
+ ContainsPointerToDataMember = true;
+ }
+ } else if (const RecordType *RT = T->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ // FIXME: It would be better if there was a way to explicitly compute the
+ // record layout instead of converting to a type.
+ Types.ConvertTagDeclType(RD);
+
+ const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
+
+ if (Layout.containsPointerToDataMember())
+ ContainsPointerToDataMember = true;
+ }
}
CGRecordLayout *
@@ -381,5 +400,5 @@ CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types,
Types.addBitFieldInfo(Info.FD, Info.FieldNo, Info.Start, Info.Size);
}
- return new CGRecordLayout(Ty, Builder.ContainsMemberPointer);
+ return new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember);
}
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.h b/lib/CodeGen/CGRecordLayoutBuilder.h
index cf84053e1907..eb60ed7b5b1d 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.h
+++ b/lib/CodeGen/CGRecordLayoutBuilder.h
@@ -27,6 +27,7 @@ namespace clang {
class CXXRecordDecl;
class FieldDecl;
class RecordDecl;
+ class QualType;
namespace CodeGen {
class CGRecordLayout;
@@ -38,9 +39,10 @@ class CGRecordLayoutBuilder {
/// Packed - Whether the resulting LLVM struct will be packed or not.
bool Packed;
- /// ContainsMemberPointer - Whether one of the fields is a member pointer
- /// or is a struct that contains a member pointer.
- bool ContainsMemberPointer;
+ /// ContainsPointerToDataMember - Whether one of the fields in this record
+ /// layout is a pointer to data member, or a struct that contains pointer to
+ /// data member.
+ bool ContainsPointerToDataMember;
/// Alignment - Contains the alignment of the RecordDecl.
unsigned Alignment;
@@ -78,7 +80,7 @@ class CGRecordLayoutBuilder {
llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields;
CGRecordLayoutBuilder(CodeGenTypes &Types)
- : Types(Types), Packed(false), ContainsMemberPointer(false)
+ : Types(Types), Packed(false), ContainsPointerToDataMember(false)
, Alignment(0), AlignmentAsLLVMStruct(1)
, BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { }
@@ -123,8 +125,9 @@ class CGRecordLayoutBuilder {
unsigned getTypeAlignment(const llvm::Type *Ty) const;
uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const;
- /// CheckForMemberPointer - Check if the field contains a member pointer.
- void CheckForMemberPointer(const FieldDecl *FD);
+ /// CheckForPointerToDataMember - Check if the given type contains a pointer
+ /// to data member.
+ void CheckForPointerToDataMember(QualType T);
public:
/// ComputeLayout - Return the right record layout for a given record decl.
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index bbd546261800..008a480b9c12 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -861,14 +861,13 @@ llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S,
std::string &ConstraintStr) {
llvm::Value *Arg;
if (Info.allowsRegister() || !Info.allowsMemory()) {
- const llvm::Type *Ty = ConvertType(InputExpr->getType());
-
- if (Ty->isSingleValueType()) {
+ if (!CodeGenFunction::hasAggregateLLVMType(InputExpr->getType())) {
Arg = EmitScalarExpr(InputExpr);
} else {
InputExpr = InputExpr->IgnoreParenNoopCasts(getContext());
LValue Dest = EmitLValue(InputExpr);
+ const llvm::Type *Ty = ConvertType(InputExpr->getType());
uint64_t Size = CGM.getTargetData().getTypeSizeInBits(Ty);
if (Size <= 64 && llvm::isPowerOf2_64(Size)) {
Ty = llvm::IntegerType::get(VMContext, Size);
@@ -916,18 +915,18 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) {
TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i),
S.getOutputName(i));
- bool result = Target.validateOutputConstraint(Info);
- assert(result && "Failed to parse output constraint"); result=result;
+ assert(Target.validateOutputConstraint(Info) &&
+ "Failed to parse output constraint");
OutputConstraintInfos.push_back(Info);
}
for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) {
TargetInfo::ConstraintInfo Info(S.getInputConstraint(i),
S.getInputName(i));
- bool result = Target.validateInputConstraint(OutputConstraintInfos.data(),
- S.getNumOutputs(),
- Info); result=result;
- assert(result && "Failed to parse input constraint");
+ assert(Target.validateInputConstraint(OutputConstraintInfos.data(),
+ S.getNumOutputs(),
+ Info) &&
+ "Failed to parse input constraint");
InputConstraintInfos.push_back(Info);
}
@@ -1066,10 +1065,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// Clobbers
for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) {
- std::string Clobber(S.getClobber(i)->getStrData(),
- S.getClobber(i)->getByteLength());
+ llvm::StringRef Clobber = S.getClobber(i)->getString();
- Clobber = Target.getNormalizedGCCRegisterName(Clobber.c_str());
+ Clobber = Target.getNormalizedGCCRegisterName(Clobber);
if (i != 0 || NumConstraints != 0)
Constraints += ',';
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index e5abfc6f8d57..970bbd777f14 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -16,14 +16,1245 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/RecordLayout.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Format.h"
#include <cstdio>
using namespace clang;
using namespace CodeGen;
namespace {
+
+/// FinalOverriders - Contains the final overrider member functions for all
+/// member functions in the base subobjects of a class.
+class FinalOverriders {
+public:
+ /// BaseOffset - Represents an offset from a derived class to a direct or
+ /// indirect base class.
+ struct BaseOffset {
+ /// DerivedClass - The derived class.
+ const CXXRecordDecl *DerivedClass;
+
+ /// VirtualBase - If the path from the derived class to the base class
+ /// involves a virtual base class, this holds its declaration.
+ const CXXRecordDecl *VirtualBase;
+
+ /// NonVirtualOffset - The offset from the derived class to the base class.
+ /// Or the offset from the virtual base class to the base class, if the path
+ /// from the derived class to the base class involves a virtual base class.
+ int64_t NonVirtualOffset;
+
+ BaseOffset() : DerivedClass(0), VirtualBase(0), NonVirtualOffset(0) { }
+ BaseOffset(const CXXRecordDecl *DerivedClass,
+ const CXXRecordDecl *VirtualBase, int64_t NonVirtualOffset)
+ : DerivedClass(DerivedClass), VirtualBase(VirtualBase),
+ NonVirtualOffset(NonVirtualOffset) { }
+
+ bool isEmpty() const { return !NonVirtualOffset && !VirtualBase; }
+ };
+
+ /// OverriderInfo - Information about a final overrider.
+ struct OverriderInfo {
+ /// Method - The method decl of the overrider.
+ const CXXMethodDecl *Method;
+
+ OverriderInfo() : Method(0) { }
+ };
+
+private:
+ /// MostDerivedClass - The most derived class for which the final overriders
+ /// are stored.
+ const CXXRecordDecl *MostDerivedClass;
+
+ ASTContext &Context;
+
+ /// MostDerivedClassLayout - the AST record layout of the most derived class.
+ const ASTRecordLayout &MostDerivedClassLayout;
+
+ /// BaseSubobjectMethodPairTy - Uniquely identifies a member function
+ /// in a base subobject.
+ typedef std::pair<BaseSubobject, const CXXMethodDecl *>
+ BaseSubobjectMethodPairTy;
+
+ typedef llvm::DenseMap<BaseSubobjectMethodPairTy,
+ OverriderInfo> OverridersMapTy;
+
+ /// OverridersMap - The final overriders for all virtual member functions of
+ /// all the base subobjects of the most derived class.
+ OverridersMapTy OverridersMap;
+
+ /// VisitedVirtualBases - A set of all the visited virtual bases, used to
+ /// avoid visiting virtual bases more than once.
+ llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
+
+ typedef llvm::DenseMap<BaseSubobjectMethodPairTy, BaseOffset>
+ AdjustmentOffsetsMapTy;
+
+ /// ReturnAdjustments - Holds return adjustments for all the overriders that
+ /// need to perform return value adjustments.
+ AdjustmentOffsetsMapTy ReturnAdjustments;
+
+ /// ThisAdjustments - Holds 'this' adjustments for all the overriders that
+ /// need them.
+ AdjustmentOffsetsMapTy ThisAdjustments;
+
+ typedef llvm::SmallVector<uint64_t, 1> OffsetVectorTy;
+
+ /// SubobjectOffsetsMapTy - This map is used for keeping track of all the
+ /// base subobject offsets that a single class declaration might refer to.
+ ///
+ /// For example, in:
+ ///
+ /// struct A { virtual void f(); };
+ /// struct B1 : A { };
+ /// struct B2 : A { };
+ /// struct C : B1, B2 { virtual void f(); };
+ ///
+ /// when we determine that C::f() overrides A::f(), we need to update the
+ /// overriders map for both A-in-B1 and A-in-B2 and the subobject offsets map
+ /// will have the subobject offsets for both A copies.
+ typedef llvm::DenseMap<const CXXRecordDecl *, OffsetVectorTy>
+ SubobjectOffsetsMapTy;
+
+ /// ComputeFinalOverriders - Compute the final overriders for a given base
+ /// subobject (and all its direct and indirect bases).
+ void ComputeFinalOverriders(BaseSubobject Base,
+ SubobjectOffsetsMapTy &Offsets);
+
+ /// AddOverriders - Add the final overriders for this base subobject to the
+ /// map of final overriders.
+ void AddOverriders(BaseSubobject Base, SubobjectOffsetsMapTy &Offsets);
+
+ /// PropagateOverrider - Propagate the NewMD overrider to all the functions
+ /// that OldMD overrides. For example, if we have:
+ ///
+ /// struct A { virtual void f(); };
+ /// struct B : A { virtual void f(); };
+ /// struct C : B { virtual void f(); };
+ ///
+ /// and we want to override B::f with C::f, we also need to override A::f with
+ /// C::f.
+ void PropagateOverrider(const CXXMethodDecl *OldMD,
+ BaseSubobject NewBase,
+ const CXXMethodDecl *NewMD,
+ SubobjectOffsetsMapTy &Offsets);
+
+ /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting
+ /// the 'this' pointer from the base subobject to the derived subobject.
+ BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
+ BaseSubobject Derived);
+
+ static void MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets,
+ SubobjectOffsetsMapTy &Offsets);
+
+public:
+ explicit FinalOverriders(const CXXRecordDecl *MostDerivedClass);
+
+ /// getOverrider - Get the final overrider for the given method declaration in
+ /// the given base subobject.
+ OverriderInfo getOverrider(BaseSubobject Base,
+ const CXXMethodDecl *MD) const {
+ assert(OverridersMap.count(std::make_pair(Base, MD)) &&
+ "Did not find overrider!");
+
+ return OverridersMap.lookup(std::make_pair(Base, MD));
+ }
+
+ /// getReturnAdjustmentOffset - Get the return adjustment offset for the
+ /// method decl in the given base subobject. Returns an empty base offset if
+ /// no adjustment is needed.
+ BaseOffset getReturnAdjustmentOffset(BaseSubobject Base,
+ const CXXMethodDecl *MD) const {
+ return ReturnAdjustments.lookup(std::make_pair(Base, MD));
+ }
+
+ /// getThisAdjustmentOffset - Get the 'this' pointer adjustment offset for the
+ /// method decl in the given base subobject. Returns an empty base offset if
+ /// no adjustment is needed.
+ BaseOffset getThisAdjustmentOffset(BaseSubobject Base,
+ const CXXMethodDecl *MD) const {
+ return ThisAdjustments.lookup(std::make_pair(Base, MD));
+ }
+
+ /// dump - dump the final overriders.
+ void dump() {
+ assert(VisitedVirtualBases.empty() &&
+ "Visited virtual bases aren't empty!");
+ dump(llvm::errs(), BaseSubobject(MostDerivedClass, 0));
+ VisitedVirtualBases.clear();
+ }
+
+ /// dump - dump the final overriders for a base subobject, and all its direct
+ /// and indirect base subobjects.
+ void dump(llvm::raw_ostream &Out, BaseSubobject Base);
+};
+
+FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass)
+ : MostDerivedClass(MostDerivedClass),
+ Context(MostDerivedClass->getASTContext()),
+ MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)) {
+
+ // Compute the final overriders.
+ SubobjectOffsetsMapTy Offsets;
+ ComputeFinalOverriders(BaseSubobject(MostDerivedClass, 0), Offsets);
+
+ // And dump them (for now).
+ dump();
+
+ // Also dump the base offsets (for now).
+ for (SubobjectOffsetsMapTy::const_iterator I = Offsets.begin(),
+ E = Offsets.end(); I != E; ++I) {
+ const OffsetVectorTy& OffsetVector = I->second;
+
+ llvm::errs() << "Base offsets for ";
+ llvm::errs() << I->first->getQualifiedNameAsString() << '\n';
+
+ for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I)
+ llvm::errs() << " " << I << " - " << OffsetVector[I] << '\n';
+ }
+}
+
+void FinalOverriders::AddOverriders(BaseSubobject Base,
+ SubobjectOffsetsMapTy &Offsets) {
+ const CXXRecordDecl *RD = Base.getBase();
+
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+
+ if (!MD->isVirtual())
+ continue;
+
+ // First, propagate the overrider.
+ PropagateOverrider(MD, Base, MD, Offsets);
+
+ // Add the overrider as the final overrider of itself.
+ OverriderInfo& Overrider = OverridersMap[std::make_pair(Base, MD)];
+ assert(!Overrider.Method && "Overrider should not exist yet!");
+
+ Overrider.Method = MD;
+ }
+}
+
+static FinalOverriders::BaseOffset
+ComputeBaseOffset(ASTContext &Context, const CXXRecordDecl *DerivedRD,
+ const CXXBasePath &Path) {
+ int64_t NonVirtualOffset = 0;
+
+ unsigned NonVirtualStart = 0;
+ const CXXRecordDecl *VirtualBase = 0;
+
+ // First, look for the virtual base class.
+ for (unsigned I = 0, E = Path.size(); I != E; ++I) {
+ const CXXBasePathElement &Element = Path[I];
+
+ if (Element.Base->isVirtual()) {
+ // FIXME: Can we break when we find the first virtual base?
+ // (If we can't, can't we just iterate over the path in reverse order?)
+ NonVirtualStart = I + 1;
+ QualType VBaseType = Element.Base->getType();
+ VirtualBase =
+ cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
+ }
+ }
+
+ // Now compute the non-virtual offset.
+ for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) {
+ const CXXBasePathElement &Element = Path[I];
+
+ // Check the base class offset.
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class);
+
+ const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>();
+ const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl());
+
+ NonVirtualOffset += Layout.getBaseClassOffset(Base);
+ }
+
+ // FIXME: This should probably use CharUnits or something. Maybe we should
+ // even change the base offsets in ASTRecordLayout to be specified in
+ // CharUnits.
+ return FinalOverriders::BaseOffset(DerivedRD, VirtualBase,
+ NonVirtualOffset / 8);
+
+}
+
+static FinalOverriders::BaseOffset
+ComputeBaseOffset(ASTContext &Context, const CXXRecordDecl *BaseRD,
+ const CXXRecordDecl *DerivedRD) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/false,
+ /*RecordPaths=*/true, /*DetectVirtual=*/false);
+
+ if (!const_cast<CXXRecordDecl *>(DerivedRD)->
+ isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) {
+ assert(false && "Class must be derived from the passed in base class!");
+ return FinalOverriders::BaseOffset();
+ }
+
+ return ComputeBaseOffset(Context, DerivedRD, Paths.front());
+}
+
+static FinalOverriders::BaseOffset
+ComputeReturnAdjustmentBaseOffset(ASTContext &Context,
+ const CXXMethodDecl *DerivedMD,
+ const CXXMethodDecl *BaseMD) {
+ const FunctionType *BaseFT = BaseMD->getType()->getAs<FunctionType>();
+ const FunctionType *DerivedFT = DerivedMD->getType()->getAs<FunctionType>();
+
+ // Canonicalize the return types.
+ CanQualType CanDerivedReturnType =
+ Context.getCanonicalType(DerivedFT->getResultType());
+ CanQualType CanBaseReturnType =
+ Context.getCanonicalType(BaseFT->getResultType());
+
+ assert(CanDerivedReturnType->getTypeClass() ==
+ CanBaseReturnType->getTypeClass() &&
+ "Types must have same type class!");
+
+ if (CanDerivedReturnType == CanBaseReturnType) {
+ // No adjustment needed.
+ return FinalOverriders::BaseOffset();
+ }
+
+ if (isa<ReferenceType>(CanDerivedReturnType)) {
+ CanDerivedReturnType =
+ CanDerivedReturnType->getAs<ReferenceType>()->getPointeeType();
+ CanBaseReturnType =
+ CanBaseReturnType->getAs<ReferenceType>()->getPointeeType();
+ } else if (isa<PointerType>(CanDerivedReturnType)) {
+ CanDerivedReturnType =
+ CanDerivedReturnType->getAs<PointerType>()->getPointeeType();
+ CanBaseReturnType =
+ CanBaseReturnType->getAs<PointerType>()->getPointeeType();
+ } else {
+ assert(false && "Unexpected return type!");
+ }
+
+ // We need to compare unqualified types here; consider
+ // const T *Base::foo();
+ // T *Derived::foo();
+ if (CanDerivedReturnType.getUnqualifiedType() ==
+ CanBaseReturnType.getUnqualifiedType()) {
+ // No adjustment needed.
+ return FinalOverriders::BaseOffset();
+ }
+
+ const CXXRecordDecl *DerivedRD =
+ cast<CXXRecordDecl>(cast<RecordType>(CanDerivedReturnType)->getDecl());
+
+ const CXXRecordDecl *BaseRD =
+ cast<CXXRecordDecl>(cast<RecordType>(CanBaseReturnType)->getDecl());
+
+ return ComputeBaseOffset(Context, BaseRD, DerivedRD);
+}
+
+FinalOverriders::BaseOffset
+FinalOverriders::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
+ BaseSubobject Derived) {
+ const CXXRecordDecl *BaseRD = Base.getBase();
+ const CXXRecordDecl *DerivedRD = Derived.getBase();
+
+ CXXBasePaths Paths(/*FindAmbiguities=*/true,
+ /*RecordPaths=*/true, /*DetectVirtual=*/true);
+
+ if (!const_cast<CXXRecordDecl *>(DerivedRD)->
+ isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) {
+ assert(false && "Class must be derived from the passed in base class!");
+ return FinalOverriders::BaseOffset();
+ }
+
+ assert(!Paths.getDetectedVirtual() && "FIXME: Handle virtual bases!");
+
+ BaseOffset Offset;
+
+ // FIXME: This is not going to be enough with virtual bases.
+ // FIXME: We should not use / 8 here.
+ int64_t DerivedToBaseOffset =
+ (Base.getBaseOffset() - Derived.getBaseOffset()) / 8;
+
+ Offset.NonVirtualOffset = -DerivedToBaseOffset;
+
+ return Offset;
+}
+
+void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD,
+ BaseSubobject NewBase,
+ const CXXMethodDecl *NewMD,
+ SubobjectOffsetsMapTy &Offsets) {
+ for (CXXMethodDecl::method_iterator I = OldMD->begin_overridden_methods(),
+ E = OldMD->end_overridden_methods(); I != E; ++I) {
+ const CXXMethodDecl *OverriddenMD = *I;
+ const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent();
+
+ // We want to override OverriddenMD in all subobjects, for example:
+ //
+ /// struct A { virtual void f(); };
+ /// struct B1 : A { };
+ /// struct B2 : A { };
+ /// struct C : B1, B2 { virtual void f(); };
+ ///
+ /// When overriding A::f with C::f we need to do so in both A subobjects.
+ const OffsetVectorTy &OffsetVector = Offsets[OverriddenRD];
+
+ // Go through all the subobjects.
+ for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I) {
+ uint64_t Offset = OffsetVector[I];
+
+ BaseSubobject OverriddenSubobject = BaseSubobject(OverriddenRD, Offset);
+ BaseSubobjectMethodPairTy SubobjectAndMethod =
+ std::make_pair(OverriddenSubobject, OverriddenMD);
+
+ OverriderInfo &Overrider = OverridersMap[SubobjectAndMethod];
+
+ assert(Overrider.Method && "Did not find existing overrider!");
+
+ // Check if we need return adjustments or base adjustments.
+ // (We don't want to do this for pure virtual member functions).
+ if (!NewMD->isPure()) {
+ // Get the return adjustment base offset.
+ BaseOffset ReturnBaseOffset =
+ ComputeReturnAdjustmentBaseOffset(Context, NewMD, OverriddenMD);
+
+ if (!ReturnBaseOffset.isEmpty()) {
+ // Store the return adjustment base offset.
+ ReturnAdjustments[SubobjectAndMethod] = ReturnBaseOffset;
+ }
+
+ // Check if we need a 'this' adjustment base offset as well.
+ if (Offset != NewBase.getBaseOffset()) {
+ BaseOffset ThisBaseOffset =
+ ComputeThisAdjustmentBaseOffset(OverriddenSubobject,
+ NewBase);
+ assert(!ThisBaseOffset.isEmpty() &&
+ "Should not get an empty 'this' adjustment!");
+
+ ThisAdjustments[SubobjectAndMethod] = ThisBaseOffset;
+ }
+ }
+
+ // Set the new overrider.
+ Overrider.Method = NewMD;
+
+ // And propagate it further.
+ PropagateOverrider(OverriddenMD, NewBase, NewMD, Offsets);
+ }
+ }
+}
+
+void
+FinalOverriders::MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets,
+ SubobjectOffsetsMapTy &Offsets) {
+ // Iterate over the new offsets.
+ for (SubobjectOffsetsMapTy::const_iterator I = NewOffsets.begin(),
+ E = NewOffsets.end(); I != E; ++I) {
+ const CXXRecordDecl *NewRD = I->first;
+ const OffsetVectorTy& NewOffsetVector = I->second;
+
+ OffsetVectorTy &OffsetVector = Offsets[NewRD];
+ if (OffsetVector.empty()) {
+ // There were no previous offsets in this vector, just insert all entries
+ // from the new offset vector.
+ OffsetVector.append(NewOffsetVector.begin(), NewOffsetVector.end());
+ continue;
+ }
+
+ // We need to merge the new offsets vector into the old, but we don't want
+ // to have duplicate entries. Do this by inserting the old offsets in a set
+ // so they'll be unique. After this, we iterate over the new offset vector
+ // and only append elements that aren't in the set.
+
+ // First, add the existing offsets to the set.
+ llvm::SmallSet<uint64_t, 4> OffsetSet;
+ for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I) {
+ bool Inserted = OffsetSet.insert(OffsetVector[I]);
+ if (!Inserted)
+ assert(false && "Set of offsets should be unique!");
+ }
+
+ // Next, only add the new offsets if they are not already in the set.
+ for (unsigned I = 0, E = NewOffsetVector.size(); I != E; ++I) {
+ uint64_t Offset = NewOffsetVector[I];
+
+ if (OffsetSet.count(Offset)) {
+ // Ignore the offset.
+ continue;
+ }
+
+ // Otherwise, add it to the offsets vector.
+ OffsetVector.push_back(Offset);
+ }
+ }
+}
+
+void FinalOverriders::ComputeFinalOverriders(BaseSubobject Base,
+ SubobjectOffsetsMapTy &Offsets) {
+ const CXXRecordDecl *RD = Base.getBase();
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ SubobjectOffsetsMapTy NewOffsets;
+
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore bases that don't have any virtual member functions.
+ if (!BaseDecl->isPolymorphic())
+ continue;
+
+ uint64_t BaseOffset;
+ if (I->isVirtual()) {
+ BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
+ } else {
+ BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset();
+ }
+
+ // Compute the final overriders for this base.
+ ComputeFinalOverriders(BaseSubobject(BaseDecl, BaseOffset), NewOffsets);
+ }
+
+ /// Now add the overriders for this particular subobject.
+ AddOverriders(Base, NewOffsets);
+
+ // And merge the newly discovered subobject offsets.
+ MergeSubobjectOffsets(NewOffsets, Offsets);
+
+ /// Finally, add the offset for our own subobject.
+ Offsets[RD].push_back(Base.getBaseOffset());
+}
+
+void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) {
+ const CXXRecordDecl *RD = Base.getBase();
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore bases that don't have any virtual member functions.
+ if (!BaseDecl->isPolymorphic())
+ continue;
+
+ uint64_t BaseOffset;
+ if (I->isVirtual()) {
+ if (!VisitedVirtualBases.insert(BaseDecl)) {
+ // We've visited this base before.
+ continue;
+ }
+
+ BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
+ } else {
+ BaseOffset = Layout.getBaseClassOffset(BaseDecl) +
+ Base.getBaseOffset();
+ }
+
+ dump(Out, BaseSubobject(BaseDecl, BaseOffset));
+ }
+
+ Out << "Final overriders for (" << RD->getQualifiedNameAsString() << ", ";
+ Out << Base.getBaseOffset() << ")\n";
+
+ // Now dump the overriders for this base subobject.
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+
+ if (!MD->isVirtual())
+ continue;
+
+ OverriderInfo Overrider = getOverrider(Base, MD);
+
+ Out << " " << MD->getQualifiedNameAsString() << " - ";
+ Out << Overrider.Method->getQualifiedNameAsString();
+
+ AdjustmentOffsetsMapTy::const_iterator AI =
+ ReturnAdjustments.find(std::make_pair(Base, MD));
+ if (AI != ReturnAdjustments.end()) {
+ const BaseOffset &Offset = AI->second;
+
+ Out << " [ret-adj: ";
+ if (Offset.VirtualBase)
+ Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, ";
+
+ Out << Offset.NonVirtualOffset << " nv]";
+ }
+
+ AI = ThisAdjustments.find(std::make_pair(Base, MD));
+ if (AI != ThisAdjustments.end()) {
+ const BaseOffset &Offset = AI->second;
+
+ Out << " [this-adj: ";
+ if (Offset.VirtualBase)
+ Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, ";
+
+ Out << Offset.NonVirtualOffset << " nv]";
+ }
+
+ Out << "\n";
+ }
+}
+
+/// VtableComponent - Represents a single component in a vtable.
+class VtableComponent {
+public:
+ enum Kind {
+ CK_VCallOffset,
+ CK_VBaseOffset,
+ CK_OffsetToTop,
+ CK_RTTI,
+ CK_FunctionPointer,
+
+ /// CK_CompleteDtorPointer - A pointer to the complete destructor.
+ CK_CompleteDtorPointer,
+
+ /// CK_DeletingDtorPointer - A pointer to the deleting destructor.
+ CK_DeletingDtorPointer
+ };
+
+ static VtableComponent MakeVBaseOffset(int64_t Offset) {
+ return VtableComponent(CK_VBaseOffset, Offset);
+ }
+
+ static VtableComponent MakeOffsetToTop(int64_t Offset) {
+ return VtableComponent(CK_OffsetToTop, Offset);
+ }
+
+ static VtableComponent MakeRTTI(const CXXRecordDecl *RD) {
+ return VtableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD));
+ }
+
+ static VtableComponent MakeFunction(const CXXMethodDecl *MD) {
+ assert(!isa<CXXDestructorDecl>(MD) &&
+ "Don't use MakeFunction with destructors!");
+
+ return VtableComponent(CK_FunctionPointer,
+ reinterpret_cast<uintptr_t>(MD));
+ }
+
+ static VtableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) {
+ return VtableComponent(CK_CompleteDtorPointer,
+ reinterpret_cast<uintptr_t>(DD));
+ }
+
+ static VtableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) {
+ return VtableComponent(CK_DeletingDtorPointer,
+ reinterpret_cast<uintptr_t>(DD));
+ }
+
+ /// getKind - Get the kind of this vtable component.
+ Kind getKind() const {
+ return (Kind)(Value & 0x7);
+ }
+
+ int64_t getVBaseOffset() const {
+ assert(getKind() == CK_VBaseOffset && "Invalid component kind!");
+
+ return getOffset();
+ }
+
+ int64_t getOffsetToTop() const {
+ assert(getKind() == CK_OffsetToTop && "Invalid component kind!");
+
+ return getOffset();
+ }
+
+ const CXXRecordDecl *getRTTIDecl() const {
+ assert(getKind() == CK_RTTI && "Invalid component kind!");
+
+ return reinterpret_cast<CXXRecordDecl *>(getPointer());
+ }
+
+ const CXXMethodDecl *getFunctionDecl() const {
+ assert(getKind() == CK_FunctionPointer);
+
+ return reinterpret_cast<CXXMethodDecl *>(getPointer());
+ }
+
+ const CXXDestructorDecl *getDestructorDecl() const {
+ assert((getKind() == CK_CompleteDtorPointer ||
+ getKind() == CK_DeletingDtorPointer) && "Invalid component kind!");
+
+ return reinterpret_cast<CXXDestructorDecl *>(getPointer());
+ }
+
+private:
+ VtableComponent(Kind ComponentKind, int64_t Offset) {
+ assert((ComponentKind == CK_VCallOffset ||
+ ComponentKind == CK_VBaseOffset ||
+ ComponentKind == CK_OffsetToTop) && "Invalid component kind!");
+ assert(Offset <= ((1LL << 56) - 1) && "Offset is too big!");
+
+ Value = ((Offset << 3) | ComponentKind);
+ }
+
+ VtableComponent(Kind ComponentKind, uintptr_t Ptr) {
+ assert((ComponentKind == CK_RTTI ||
+ ComponentKind == CK_FunctionPointer ||
+ ComponentKind == CK_CompleteDtorPointer ||
+ ComponentKind == CK_DeletingDtorPointer) &&
+ "Invalid component kind!");
+
+ assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!");
+
+ Value = Ptr | ComponentKind;
+ }
+
+ int64_t getOffset() const {
+ assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset ||
+ getKind() == CK_OffsetToTop) && "Invalid component kind!");
+
+ return Value >> 3;
+ }
+
+ uintptr_t getPointer() const {
+ assert((getKind() == CK_RTTI ||
+ getKind() == CK_FunctionPointer ||
+ getKind() == CK_CompleteDtorPointer ||
+ getKind() == CK_DeletingDtorPointer) &&
+ "Invalid component kind!");
+
+ return static_cast<uintptr_t>(Value & ~7ULL);
+ }
+
+ /// The kind is stored in the lower 3 bits of the value. For offsets, we
+ /// make use of the facts that classes can't be larger than 2^55 bytes,
+ /// so we store the offset in the lower part of the 61 bytes that remain.
+ /// (The reason that we're not simply using a PointerIntPair here is that we
+ /// need the offsets to be 64-bit, even when on a 32-bit machine).
+ int64_t Value;
+};
+
+/// VtableBuilder - Class for building vtable layout information.
class VtableBuilder {
public:
+ /// PrimaryBasesSetTy - A set of direct and indirect primary bases.
+ typedef llvm::SmallPtrSet<const CXXRecordDecl *, 8> PrimaryBasesSetTy;
+
+private:
+ /// VtableInfo - Global vtable information.
+ CGVtableInfo &VtableInfo;
+
+ /// MostDerivedClass - The most derived class for which we're building this
+ /// vtable.
+ const CXXRecordDecl *MostDerivedClass;
+
+ /// Context - The ASTContext which we will use for layout information.
+ ASTContext &Context;
+
+ /// FinalOverriders - The final overriders of the most derived class.
+ FinalOverriders Overriders;
+
+ /// VCallAndVBaseOffsets - The vcall and vbase offset, of the vtable we're
+ // building (in reverse order).
+ llvm::SmallVector<VtableComponent, 64> VCallAndVBaseOffsets;
+
+ /// Components - The components of the vtable being built.
+ llvm::SmallVector<VtableComponent, 64> Components;
+
+ /// AddressPoints - Address points for the vtable being built.
+ CGVtableInfo::AddressPointsMapTy AddressPoints;
+
+ /// ReturnAdjustment - A return adjustment.
+ struct ReturnAdjustment {
+ /// NonVirtual - The non-virtual adjustment from the derived object to its
+ /// nearest virtual base.
+ int64_t NonVirtual;
+
+ /// VBaseOffsetOffset - The offset, in bytes, relative to the address point
+ /// of the virtual base class offset.
+ int64_t VBaseOffsetOffset;
+
+ ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { }
+
+ bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; }
+ };
+
+ /// ReturnAdjustments - The return adjustments needed in this vtable.
+ llvm::SmallVector<std::pair<uint64_t, ReturnAdjustment>, 16>
+ ReturnAdjustments;
+
+ /// ThisAdjustment - A 'this' pointer adjustment thunk.
+ struct ThisAdjustment {
+ /// NonVirtual - The non-virtual adjustment from the derived object to its
+ /// nearest virtual base.
+ int64_t NonVirtual;
+
+ /// FIXME: Add VCallOffsetOffset here.
+
+ ThisAdjustment() : NonVirtual(0) { }
+
+ bool isEmpty() const { return !NonVirtual; }
+ };
+
+ /// ThisAdjustments - The 'this' pointer adjustments needed in this vtable.
+ llvm::SmallVector<std::pair<uint64_t, ThisAdjustment>, 16>
+ ThisAdjustments;
+
+ typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
+
+ /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the
+ /// given class.
+ void AddVCallAndVBaseOffsets(const CXXRecordDecl *RD, int64_t OffsetToTop,
+ VisitedVirtualBasesSetTy &VBases);
+
+ /// AddVBaseOffsets - Add vbase offsets for the given class.
+ void AddVBaseOffsets(const CXXRecordDecl *RD, int64_t OffsetToTop,
+ VisitedVirtualBasesSetTy &VBases);
+
+ /// ComputeReturnAdjustment - Compute the return adjustment given a return
+ /// adjustment base offset.
+ ReturnAdjustment ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset);
+
+ /// ComputeThisAdjustment - Compute the 'this' pointer adjustment given a
+ /// 'this' pointer adjustment base offset.
+ ThisAdjustment ComputeThisAdjustment(FinalOverriders::BaseOffset Offset);
+
+ /// AddMethod - Add a single virtual member function to the vtable
+ /// components vector.
+ void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment,
+ ThisAdjustment ThisAdjustment);
+
+ /// AddMethods - Add the methods of this base subobject and all its
+ /// primary bases to the vtable components vector.
+ void AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases);
+
+ /// LayoutVtable - Layout a vtable and all its secondary vtables.
+ void LayoutVtable(BaseSubobject Base);
+
+public:
+ VtableBuilder(CGVtableInfo &VtableInfo, const CXXRecordDecl *MostDerivedClass)
+ : VtableInfo(VtableInfo), MostDerivedClass(MostDerivedClass),
+ Context(MostDerivedClass->getASTContext()), Overriders(MostDerivedClass) {
+
+ LayoutVtable(BaseSubobject(MostDerivedClass, 0));
+ }
+
+ /// dumpLayout - Dump the vtable layout.
+ void dumpLayout(llvm::raw_ostream&);
+};
+
+/// OverridesMethodInPrimaryBase - Checks whether whether this virtual member
+/// function overrides a member function in a direct or indirect primary base.
+/// Returns the overridden member function, or null if none was found.
+static const CXXMethodDecl *
+OverridesMethodInPrimaryBase(const CXXMethodDecl *MD,
+ VtableBuilder::PrimaryBasesSetTy &PrimaryBases) {
+ for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
+ E = MD->end_overridden_methods(); I != E; ++I) {
+ const CXXMethodDecl *OverriddenMD = *I;
+ const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent();
+ assert(OverriddenMD->isCanonicalDecl() &&
+ "Should have the canonical decl of the overridden RD!");
+
+ if (PrimaryBases.count(OverriddenRD))
+ return OverriddenMD;
+ }
+
+ return 0;
+}
+
+VtableBuilder::ReturnAdjustment
+VtableBuilder::ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset) {
+ ReturnAdjustment Adjustment;
+
+ if (!Offset.isEmpty()) {
+ if (Offset.VirtualBase) {
+ // Get the virtual base offset offset.
+ Adjustment.VBaseOffsetOffset =
+ VtableInfo.getVirtualBaseOffsetIndex(Offset.DerivedClass,
+ Offset.VirtualBase);
+ // FIXME: Once the assert in getVirtualBaseOffsetIndex is back again,
+ // we can get rid of this assert.
+ assert(Adjustment.VBaseOffsetOffset != 0 &&
+ "Invalid base offset offset!");
+ }
+
+ Adjustment.NonVirtual = Offset.NonVirtualOffset;
+ }
+
+ return Adjustment;
+}
+
+VtableBuilder::ThisAdjustment
+VtableBuilder::ComputeThisAdjustment(FinalOverriders::BaseOffset Offset) {
+ ThisAdjustment Adjustment;
+
+ if (!Offset.isEmpty()) {
+ assert(!Offset.VirtualBase && "FIXME: Handle virtual bases!");
+ Adjustment.NonVirtual = Offset.NonVirtualOffset;
+ }
+
+ return Adjustment;
+}
+
+void
+VtableBuilder::AddVCallAndVBaseOffsets(const CXXRecordDecl *RD,
+ int64_t OffsetToTop,
+ VisitedVirtualBasesSetTy &VBases) {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ // Itanium C++ ABI 2.5.2:
+ // ..in classes sharing a virtual table with a primary base class, the vcall
+ // and vbase offsets added by the derived class all come before the vcall
+ // and vbase offsets required by the base class, so that the latter may be
+ // laid out as required by the base class without regard to additions from
+ // the derived class(es).
+
+ // (Since we're emitting the vcall and vbase offsets in reverse order, we'll
+ // emit them for the primary base first).
+ if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase())
+ AddVCallAndVBaseOffsets(PrimaryBase, OffsetToTop, VBases);
+
+ AddVBaseOffsets(RD, OffsetToTop, VBases);
+}
+
+void VtableBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
+ int64_t OffsetToTop,
+ VisitedVirtualBasesSetTy &VBases) {
+ const ASTRecordLayout &MostDerivedClassLayout =
+ Context.getASTRecordLayout(MostDerivedClass);
+
+ // Add vbase offsets.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Check if this is a virtual base that we haven't visited before.
+ if (I->isVirtual() && VBases.insert(BaseDecl)) {
+ // FIXME: We shouldn't use / 8 here.
+ uint64_t Offset =
+ OffsetToTop + MostDerivedClassLayout.getVBaseClassOffset(BaseDecl) / 8;
+
+ VCallAndVBaseOffsets.push_back(VtableComponent::MakeVBaseOffset(Offset));
+ }
+
+ // Check the base class looking for more vbase offsets.
+ AddVBaseOffsets(BaseDecl, OffsetToTop, VBases);
+ }
+}
+
+void
+VtableBuilder::AddMethod(const CXXMethodDecl *MD,
+ ReturnAdjustment ReturnAdjustment,
+ ThisAdjustment ThisAdjustment) {
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ assert(ReturnAdjustment.isEmpty() &&
+ "Destructor can't have return adjustment!");
+ // Add the 'this' pointer adjustments if necessary.
+ if (!ThisAdjustment.isEmpty()) {
+ ThisAdjustments.push_back(std::make_pair(Components.size(),
+ ThisAdjustment));
+ ThisAdjustments.push_back(std::make_pair(Components.size() + 1,
+ ThisAdjustment));
+ }
+
+ // Add both the complete destructor and the deleting destructor.
+ Components.push_back(VtableComponent::MakeCompleteDtor(DD));
+ Components.push_back(VtableComponent::MakeDeletingDtor(DD));
+ } else {
+ // Add the return adjustment if necessary.
+ if (!ReturnAdjustment.isEmpty())
+ ReturnAdjustments.push_back(std::make_pair(Components.size(),
+ ReturnAdjustment));
+
+ // Add the 'this' pointer adjustment if necessary.
+ if (!ThisAdjustment.isEmpty())
+ ThisAdjustments.push_back(std::make_pair(Components.size(),
+ ThisAdjustment));
+
+ // Add the function.
+ Components.push_back(VtableComponent::MakeFunction(MD));
+ }
+}
+
+void
+VtableBuilder::AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases) {
+ const CXXRecordDecl *RD = Base.getBase();
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
+ if (Layout.getPrimaryBaseWasVirtual())
+ assert(false && "FIXME: Handle vbases here.");
+ else
+ assert(Layout.getBaseClassOffset(PrimaryBase) == 0 &&
+ "Primary base should have a zero offset!");
+
+ AddMethods(BaseSubobject(PrimaryBase, Base.getBaseOffset()), PrimaryBases);
+
+ if (!PrimaryBases.insert(PrimaryBase))
+ assert(false && "Found a duplicate primary base!");
+ }
+
+ // Now go through all virtual member functions and add them.
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+
+ if (!MD->isVirtual())
+ continue;
+
+ // Get the final overrider.
+ FinalOverriders::OverriderInfo Overrider =
+ Overriders.getOverrider(Base, MD);
+
+ // Check if this virtual member function overrides a method in a primary
+ // base. If this is the case, and the return type doesn't require adjustment
+ // then we can just use the member function from the primary base.
+ if (const CXXMethodDecl *OverriddenMD =
+ OverridesMethodInPrimaryBase(MD, PrimaryBases)) {
+ if (ComputeReturnAdjustmentBaseOffset(Context, MD,
+ OverriddenMD).isEmpty())
+ continue;
+ }
+
+ // Check if this overrider needs a return adjustment.
+ FinalOverriders::BaseOffset ReturnAdjustmentOffset =
+ Overriders.getReturnAdjustmentOffset(Base, MD);
+
+ ReturnAdjustment ReturnAdjustment =
+ ComputeReturnAdjustment(ReturnAdjustmentOffset);
+
+ // Check if this overrider needs a 'this' pointer adjustment.
+ FinalOverriders::BaseOffset ThisAdjustmentOffset =
+ Overriders.getThisAdjustmentOffset(Base, MD);
+
+ ThisAdjustment ThisAdjustment = ComputeThisAdjustment(ThisAdjustmentOffset);
+
+ AddMethod(Overrider.Method, ReturnAdjustment, ThisAdjustment);
+ }
+}
+
+void VtableBuilder::LayoutVtable(BaseSubobject Base) {
+ const CXXRecordDecl *RD = Base.getBase();
+ assert(RD->isDynamicClass() && "class does not have a vtable!");
+
+ int64_t OffsetToTop = -(int64_t)Base.getBaseOffset() / 8;
+
+ // Add vcall and vbase offsets for this vtable.
+ VisitedVirtualBasesSetTy VBases;
+ AddVCallAndVBaseOffsets(RD, OffsetToTop, VBases);
+
+ // Reverse them and add them to the vtable components.
+ std::reverse(VCallAndVBaseOffsets.begin(), VCallAndVBaseOffsets.end());
+ Components.append(VCallAndVBaseOffsets.begin(), VCallAndVBaseOffsets.end());
+ VCallAndVBaseOffsets.clear();
+
+ // Add the offset to top.
+ // FIXME: This is not going to be right for construction vtables.
+ // FIXME: We should not use / 8 here.
+ Components.push_back(VtableComponent::MakeOffsetToTop(OffsetToTop));
+
+ // Next, add the RTTI.
+ Components.push_back(VtableComponent::MakeRTTI(MostDerivedClass));
+
+ uint64_t AddressPoint = Components.size();
+
+ // Now go through all virtual member functions and add them.
+ PrimaryBasesSetTy PrimaryBases;
+ AddMethods(Base, PrimaryBases);
+
+ // Record the address point.
+ AddressPoints.insert(std::make_pair(Base, AddressPoint));
+
+ // Record the address points for all primary bases.
+ for (PrimaryBasesSetTy::const_iterator I = PrimaryBases.begin(),
+ E = PrimaryBases.end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl = *I;
+
+ // We know that all the primary bases have the same offset as the base
+ // subobject.
+ BaseSubobject PrimaryBase(BaseDecl, Base.getBaseOffset());
+ AddressPoints.insert(std::make_pair(PrimaryBase, AddressPoint));
+ }
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+ // Layout secondary vtables.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore bases that don't have a vtable.
+ if (!BaseDecl->isDynamicClass())
+ continue;
+
+ // Ignore the primary base.
+ if (BaseDecl == PrimaryBase)
+ continue;
+
+ // Ignore virtual bases, we'll emit them later.
+ if (I->isVirtual())
+ continue;
+
+ // Get the base offset of this base.
+ uint64_t BaseOffset = Base.getBaseOffset() +
+ Layout.getBaseClassOffset(BaseDecl);
+
+ // Layout this secondary vtable.
+ LayoutVtable(BaseSubobject(BaseDecl, BaseOffset));
+ }
+
+ // FIXME: Emit vtables for virtual bases here.
+}
+
+/// dumpLayout - Dump the vtable layout.
+void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
+
+ Out << "Vtable for '" << MostDerivedClass->getQualifiedNameAsString();
+ Out << "' (" << Components.size() << " entries).\n";
+
+ // Iterate through the address points and insert them into a new map where
+ // they are keyed by the index and not the base object.
+ // Since an address point can be shared by multiple subobjects, we use an
+ // STL multimap.
+ std::multimap<uint64_t, BaseSubobject> AddressPointsByIndex;
+ for (CGVtableInfo::AddressPointsMapTy::const_iterator I =
+ AddressPoints.begin(), E = AddressPoints.end(); I != E; ++I) {
+ const BaseSubobject& Base = I->first;
+ uint64_t Index = I->second;
+
+ AddressPointsByIndex.insert(std::make_pair(Index, Base));
+ }
+
+ unsigned NextReturnAdjustmentIndex = 0;
+ unsigned NextThisAdjustmentIndex = 0;
+ for (unsigned I = 0, E = Components.size(); I != E; ++I) {
+ uint64_t Index = I;
+
+ if (AddressPointsByIndex.count(I)) {
+ if (AddressPointsByIndex.count(Index) == 1) {
+ const BaseSubobject &Base = AddressPointsByIndex.find(Index)->second;
+
+ // FIXME: Instead of dividing by 8, we should be using CharUnits.
+ Out << " -- (" << Base.getBase()->getQualifiedNameAsString();
+ Out << ", " << Base.getBaseOffset() / 8 << ") vtable address --\n";
+ } else {
+ uint64_t BaseOffset =
+ AddressPointsByIndex.lower_bound(Index)->second.getBaseOffset();
+
+ // We store the class names in a set to get a stable order.
+ std::set<std::string> ClassNames;
+ for (std::multimap<uint64_t, BaseSubobject>::const_iterator I =
+ AddressPointsByIndex.lower_bound(Index), E =
+ AddressPointsByIndex.upper_bound(Index); I != E; ++I) {
+ assert(I->second.getBaseOffset() == BaseOffset &&
+ "Invalid base offset!");
+ const CXXRecordDecl *RD = I->second.getBase();
+ ClassNames.insert(RD->getQualifiedNameAsString());
+ }
+
+ for (std::set<std::string>::const_iterator I = ClassNames.begin(),
+ E = ClassNames.end(); I != E; ++I) {
+ // FIXME: Instead of dividing by 8, we should be using CharUnits.
+ Out << " -- (" << *I;
+ Out << ", " << BaseOffset / 8 << ") vtable address --\n";
+ }
+ }
+ }
+
+ Out << llvm::format("%4d | ", I);
+
+ const VtableComponent &Component = Components[I];
+
+ // Dump the component.
+ switch (Component.getKind()) {
+ // FIXME: Remove this default case.
+ default:
+ assert(false && "Unhandled component kind!");
+ break;
+
+ case VtableComponent::CK_VBaseOffset:
+ Out << "vbase_offset (" << Component.getVBaseOffset() << ")";
+ break;
+
+ case VtableComponent::CK_OffsetToTop:
+ Out << "offset_to_top (" << Component.getOffsetToTop() << ")";
+ break;
+
+ case VtableComponent::CK_RTTI:
+ Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI";
+ break;
+
+ case VtableComponent::CK_FunctionPointer: {
+ const CXXMethodDecl *MD = Component.getFunctionDecl();
+
+ std::string Str =
+ PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
+ MD);
+ Out << Str;
+ if (MD->isPure())
+ Out << " [pure]";
+
+ // If this function pointer has a return adjustment, dump it.
+ if (NextReturnAdjustmentIndex < ReturnAdjustments.size() &&
+ ReturnAdjustments[NextReturnAdjustmentIndex].first == I) {
+ const ReturnAdjustment Adjustment =
+ ReturnAdjustments[NextReturnAdjustmentIndex].second;
+
+ Out << "\n [return adjustment: ";
+ Out << Adjustment.NonVirtual << " non-virtual";
+
+ if (Adjustment.VBaseOffsetOffset)
+ Out << ", " << Adjustment.VBaseOffsetOffset << " vbase offset offset";
+ Out << ']';
+
+ NextReturnAdjustmentIndex++;
+ }
+
+ // If this function pointer has a 'this' pointer adjustment, dump it.
+ if (NextThisAdjustmentIndex < ThisAdjustments.size() &&
+ ThisAdjustments[NextThisAdjustmentIndex].first == I) {
+ const ThisAdjustment Adjustment =
+ ThisAdjustments[NextThisAdjustmentIndex].second;
+
+ Out << "\n [this adjustment: ";
+ Out << Adjustment.NonVirtual << " non-virtual";
+
+ Out << ']';
+
+ NextThisAdjustmentIndex++;
+ }
+
+ break;
+ }
+
+ case VtableComponent::CK_CompleteDtorPointer: {
+ const CXXDestructorDecl *DD = Component.getDestructorDecl();
+
+ Out << DD->getQualifiedNameAsString() << "() [complete]";
+ if (DD->isPure())
+ Out << " [pure]";
+
+ break;
+ }
+
+ case VtableComponent::CK_DeletingDtorPointer: {
+ const CXXDestructorDecl *DD = Component.getDestructorDecl();
+
+ Out << DD->getQualifiedNameAsString() << "() [deleting]";
+ if (DD->isPure())
+ Out << " [pure]";
+
+ break;
+ }
+
+ }
+
+ Out << '\n';
+ }
+
+}
+
+}
+
+namespace {
+class OldVtableBuilder {
+public:
/// Index_t - Vtable index type.
typedef uint64_t Index_t;
typedef std::vector<std::pair<GlobalDecl,
@@ -57,10 +1288,11 @@ private:
llvm::LLVMContext &VMContext;
CodeGenModule &CGM; // Per-module state.
- llvm::DenseMap<GlobalDecl, Index_t> VCall;
+ llvm::DenseMap<const CXXMethodDecl *, Index_t> VCall;
llvm::DenseMap<GlobalDecl, Index_t> VCallOffset;
+ llvm::DenseMap<GlobalDecl, Index_t> VCallOffsetForVCall;
// This is the offset to the nearest virtual base
- llvm::DenseMap<GlobalDecl, Index_t> NonVirtualOffset;
+ llvm::DenseMap<const CXXMethodDecl *, Index_t> NonVirtualOffset;
llvm::DenseMap<const CXXRecordDecl *, Index_t> VBIndex;
/// PureVirtualFunction - Points to __cxa_pure_virtual.
@@ -180,6 +1412,196 @@ private:
return *ref;
}
+ bool DclIsSame(const FunctionDecl *New, const FunctionDecl *Old) {
+ FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
+ FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
+
+ // C++ [temp.fct]p2:
+ // A function template can be overloaded with other function templates
+ // and with normal (non-template) functions.
+ if ((OldTemplate == 0) != (NewTemplate == 0))
+ return false;
+
+ // Is the function New an overload of the function Old?
+ QualType OldQType = CGM.getContext().getCanonicalType(Old->getType());
+ QualType NewQType = CGM.getContext().getCanonicalType(New->getType());
+
+ // Compare the signatures (C++ 1.3.10) of the two functions to
+ // determine whether they are overloads. If we find any mismatch
+ // in the signature, they are overloads.
+
+ // If either of these functions is a K&R-style function (no
+ // prototype), then we consider them to have matching signatures.
+ if (isa<FunctionNoProtoType>(OldQType.getTypePtr()) ||
+ isa<FunctionNoProtoType>(NewQType.getTypePtr()))
+ return true;
+
+ FunctionProtoType* OldType = cast<FunctionProtoType>(OldQType);
+ FunctionProtoType* NewType = cast<FunctionProtoType>(NewQType);
+
+ // The signature of a function includes the types of its
+ // parameters (C++ 1.3.10), which includes the presence or absence
+ // of the ellipsis; see C++ DR 357).
+ if (OldQType != NewQType &&
+ (OldType->getNumArgs() != NewType->getNumArgs() ||
+ OldType->isVariadic() != NewType->isVariadic() ||
+ !std::equal(OldType->arg_type_begin(), OldType->arg_type_end(),
+ NewType->arg_type_begin())))
+ return false;
+
+#if 0
+ // C++ [temp.over.link]p4:
+ // The signature of a function template consists of its function
+ // signature, its return type and its template parameter list. The names
+ // of the template parameters are significant only for establishing the
+ // relationship between the template parameters and the rest of the
+ // signature.
+ //
+ // We check the return type and template parameter lists for function
+ // templates first; the remaining checks follow.
+ if (NewTemplate &&
+ (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
+ OldTemplate->getTemplateParameters(),
+ TPL_TemplateMatch) ||
+ OldType->getResultType() != NewType->getResultType()))
+ return false;
+#endif
+
+ // If the function is a class member, its signature includes the
+ // cv-qualifiers (if any) on the function itself.
+ //
+ // As part of this, also check whether one of the member functions
+ // is static, in which case they are not overloads (C++
+ // 13.1p2). While not part of the definition of the signature,
+ // this check is important to determine whether these functions
+ // can be overloaded.
+ const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
+ const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
+ if (OldMethod && NewMethod &&
+ !OldMethod->isStatic() && !NewMethod->isStatic() &&
+ OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers())
+ return false;
+
+ // The signatures match; this is not an overload.
+ return true;
+ }
+
+ typedef llvm::DenseMap<const CXXMethodDecl *, const CXXMethodDecl*>
+ ForwardUnique_t;
+ ForwardUnique_t ForwardUnique;
+ llvm::DenseMap<const CXXMethodDecl*, const CXXMethodDecl*> UniqueOverrider;
+
+ void BuildUniqueOverrider(const CXXMethodDecl *U, const CXXMethodDecl *MD) {
+ const CXXMethodDecl *PrevU = UniqueOverrider[MD];
+ assert(U && "no unique overrider");
+ if (PrevU == U)
+ return;
+ if (PrevU != U && PrevU != 0) {
+ // If already set, note the two sets as the same
+ if (0)
+ printf("%s::%s same as %s::%s\n",
+ PrevU->getParent()->getNameAsCString(),
+ PrevU->getNameAsCString(),
+ U->getParent()->getNameAsCString(),
+ U->getNameAsCString());
+ ForwardUnique[PrevU] = U;
+ return;
+ }
+
+ // Not set, set it now
+ if (0)
+ printf("marking %s::%s %p override as %s::%s\n",
+ MD->getParent()->getNameAsCString(),
+ MD->getNameAsCString(),
+ (void*)MD,
+ U->getParent()->getNameAsCString(),
+ U->getNameAsCString());
+ UniqueOverrider[MD] = U;
+
+ for (CXXMethodDecl::method_iterator mi = MD->begin_overridden_methods(),
+ me = MD->end_overridden_methods(); mi != me; ++mi) {
+ BuildUniqueOverrider(U, *mi);
+ }
+ }
+
+ void BuildUniqueOverriders(const CXXRecordDecl *RD) {
+ if (0) printf("walking %s\n", RD->getNameAsCString());
+ for (CXXRecordDecl::method_iterator i = RD->method_begin(),
+ e = RD->method_end(); i != e; ++i) {
+ const CXXMethodDecl *MD = *i;
+ if (!MD->isVirtual())
+ continue;
+
+ if (UniqueOverrider[MD] == 0) {
+ // Only set this, if it hasn't been set yet.
+ BuildUniqueOverrider(MD, MD);
+ if (0)
+ printf("top set is %s::%s %p\n",
+ MD->getParent()->getNameAsCString(),
+ MD->getNameAsCString(),
+ (void*)MD);
+ ForwardUnique[MD] = MD;
+ }
+ }
+ 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());
+ BuildUniqueOverriders(Base);
+ }
+ }
+
+ static int DclCmp(const void *p1, const void *p2) {
+ const CXXMethodDecl *MD1 = *(const CXXMethodDecl *const *)p1;
+ const CXXMethodDecl *MD2 = *(const CXXMethodDecl *const *)p2;
+
+ return (DeclarationName::compare(MD1->getDeclName(), MD2->getDeclName()));
+ }
+
+ void MergeForwarding() {
+ typedef llvm::SmallVector<const CXXMethodDecl *, 100> A_t;
+ A_t A;
+ for (ForwardUnique_t::iterator I = ForwardUnique.begin(),
+ E = ForwardUnique.end(); I != E; ++I) {
+ if (I->first == I->second)
+ // Only add the roots of all trees
+ A.push_back(I->first);
+ }
+ llvm::array_pod_sort(A.begin(), A.end(), DclCmp);
+ for (A_t::iterator I = A.begin(),
+ E = A.end(); I != E; ++I) {
+ A_t::iterator J = I;
+ while (++J != E && DclCmp(I, J) == 0)
+ if (DclIsSame(*I, *J)) {
+ if (0) printf("connecting %s\n", (*I)->getNameAsCString());
+ ForwardUnique[*J] = *I;
+ }
+ }
+ }
+
+ const CXXMethodDecl *getUnique(const CXXMethodDecl *MD) {
+ const CXXMethodDecl *U = UniqueOverrider[MD];
+ assert(U && "unique overrider not found");
+ while (ForwardUnique.count(U)) {
+ const CXXMethodDecl *NU = ForwardUnique[U];
+ if (NU == U) break;
+ U = NU;
+ }
+ return U;
+ }
+
+ GlobalDecl getUnique(GlobalDecl GD) {
+ const CXXMethodDecl *Unique = getUnique(cast<CXXMethodDecl>(GD.getDecl()));
+
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Unique))
+ return GlobalDecl(CD, GD.getCtorType());
+
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(Unique))
+ return GlobalDecl(DD, GD.getDtorType());
+
+ return Unique;
+ }
+
/// getPureVirtualFn - Return the __cxa_pure_virtual function.
llvm::Constant* getPureVirtualFn() {
if (!PureVirtualFn) {
@@ -193,7 +1615,7 @@ private:
}
public:
- VtableBuilder(const CXXRecordDecl *MostDerivedClass,
+ OldVtableBuilder(const CXXRecordDecl *MostDerivedClass,
const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm,
bool build, CGVtableInfo::AddressPointsMapTy& AddressPoints)
: BuildVtable(build), MostDerivedClass(MostDerivedClass), LayoutClass(l),
@@ -209,6 +1631,8 @@ public:
QualType ClassType = CGM.getContext().getTagDeclType(MostDerivedClass);
rtti = CGM.GetAddrOfRTTIDescriptor(ClassType);
}
+ BuildUniqueOverriders(MostDerivedClass);
+ MergeForwarding();
}
// getVtableComponents - Returns a reference to the vtable components.
@@ -384,17 +1808,24 @@ public:
// entry.
Methods.AddMethod(GD);
- VCallOffset[GD] = Offset/8;
+ VCallOffset[GD] = Offset/8 - CurrentVBaseOffset/8;
+
if (MorallyVirtual) {
- Index_t &idx = VCall[GD];
+ GlobalDecl UGD = getUnique(GD);
+ const CXXMethodDecl *UMD = cast<CXXMethodDecl>(UGD.getDecl());
+
+ assert(UMD && "final overrider not found");
+
+ Index_t &idx = VCall[UMD];
// Allocate the first one, after that, we reuse the previous one.
if (idx == 0) {
- NonVirtualOffset[GD] = CurrentVBaseOffset/8 - Offset/8;
+ VCallOffsetForVCall[UGD] = Offset/8;
+ NonVirtualOffset[UMD] = Offset/8 - CurrentVBaseOffset/8;
idx = VCalls.size()+1;
- VCalls.push_back(0);
+ VCalls.push_back(Offset/8 - CurrentVBaseOffset/8);
D1(printf(" vcall for %s at %d with delta %d\n",
dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsCString(),
- (int)-VCalls.size()-3, 0));
+ (int)-VCalls.size()-3, (int)VCalls[idx-1]));
}
}
}
@@ -459,6 +1890,9 @@ public:
}
VCalls.clear();
VCall.clear();
+ VCallOffsetForVCall.clear();
+ VCallOffset.clear();
+ NonVirtualOffset.clear();
}
void AddAddressPoints(const CXXRecordDecl *RD, uint64_t Offset,
@@ -699,84 +2133,7 @@ public:
};
} // end anonymous namespace
-/// TypeConversionRequiresAdjustment - Returns whether conversion from a
-/// derived type to a base type requires adjustment.
-static bool
-TypeConversionRequiresAdjustment(ASTContext &Ctx,
- const CXXRecordDecl *DerivedDecl,
- const CXXRecordDecl *BaseDecl) {
- CXXBasePaths Paths(/*FindAmbiguities=*/false,
- /*RecordPaths=*/true, /*DetectVirtual=*/true);
- if (!const_cast<CXXRecordDecl *>(DerivedDecl)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseDecl), Paths)) {
- assert(false && "Class must be derived from the passed in base class!");
- return false;
- }
-
- // If we found a virtual base we always want to require adjustment.
- if (Paths.getDetectedVirtual())
- return true;
-
- const CXXBasePath &Path = Paths.front();
-
- for (size_t Start = 0, End = Path.size(); Start != End; ++Start) {
- const CXXBasePathElement &Element = Path[Start];
-
- // Check the base class offset.
- const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Element.Class);
-
- const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>();
- const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl());
-
- if (Layout.getBaseClassOffset(Base) != 0) {
- // This requires an adjustment.
- return true;
- }
- }
-
- return false;
-}
-
-static bool
-TypeConversionRequiresAdjustment(ASTContext &Ctx,
- QualType DerivedType, QualType BaseType) {
- // Canonicalize the types.
- QualType CanDerivedType = Ctx.getCanonicalType(DerivedType);
- QualType CanBaseType = Ctx.getCanonicalType(BaseType);
-
- assert(CanDerivedType->getTypeClass() == CanBaseType->getTypeClass() &&
- "Types must have same type class!");
-
- if (CanDerivedType == CanBaseType) {
- // No adjustment needed.
- return false;
- }
-
- if (const ReferenceType *RT = dyn_cast<ReferenceType>(CanDerivedType)) {
- CanDerivedType = RT->getPointeeType();
- CanBaseType = cast<ReferenceType>(CanBaseType)->getPointeeType();
- } else if (const PointerType *PT = dyn_cast<PointerType>(CanDerivedType)) {
- CanDerivedType = PT->getPointeeType();
- CanBaseType = cast<PointerType>(CanBaseType)->getPointeeType();
- } else {
- assert(false && "Unexpected return type!");
- }
-
- if (CanDerivedType == CanBaseType) {
- // No adjustment needed.
- return false;
- }
-
- const CXXRecordDecl *DerivedDecl =
- cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl());
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl());
-
- return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl);
-}
-
-bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
+bool OldVtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
Index_t OverrideOffset, Index_t Offset,
int64_t CurrentVBaseOffset) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
@@ -788,6 +2145,7 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
for (CXXMethodDecl::method_iterator mi = MD->begin_overridden_methods(),
e = MD->end_overridden_methods(); mi != e; ++mi) {
GlobalDecl OGD;
+ GlobalDecl OGD2;
const CXXMethodDecl *OMD = *mi;
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(OMD))
@@ -801,6 +2159,8 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
if (!Methods.getIndex(OGD, Index))
continue;
+ OGD2 = OGD;
+
// Get the original method, which we should be computing thunks, etc,
// against.
OGD = Methods.getOrigMethod(Index);
@@ -812,8 +2172,8 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
OMD->getType()->getAs<FunctionType>()->getResultType();
// Check if we need a return type adjustment.
- if (TypeConversionRequiresAdjustment(CGM.getContext(), ReturnType,
- OverriddenReturnType)) {
+ if (!ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD,
+ OMD).isEmpty()) {
CanQualType &BaseReturnType = BaseReturnTypes[Index];
// Insert the base return type.
@@ -824,26 +2184,39 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
Methods.OverrideMethod(OGD, GD);
+ GlobalDecl UGD = getUnique(GD);
+ const CXXMethodDecl *UMD = cast<CXXMethodDecl>(UGD.getDecl());
+ assert(UGD.getDecl() && "unique overrider not found");
+ assert(UGD == getUnique(OGD) && "unique overrider not unique");
+
ThisAdjustments.erase(Index);
- if (MorallyVirtual || VCall.count(OGD)) {
- Index_t &idx = VCall[OGD];
+ if (MorallyVirtual || VCall.count(UMD)) {
+
+ Index_t &idx = VCall[UMD];
if (idx == 0) {
- NonVirtualOffset[GD] = -OverrideOffset/8 + CurrentVBaseOffset/8;
- VCallOffset[GD] = OverrideOffset/8;
+ VCallOffset[GD] = VCallOffset[OGD];
+ // NonVirtualOffset[UMD] = CurrentVBaseOffset/8 - OverrideOffset/8;
+ NonVirtualOffset[UMD] = VCallOffset[OGD];
+ VCallOffsetForVCall[UMD] = OverrideOffset/8;
idx = VCalls.size()+1;
- VCalls.push_back(0);
+ VCalls.push_back(OverrideOffset/8 - CurrentVBaseOffset/8);
D1(printf(" vcall for %s at %d with delta %d most derived %s\n",
MD->getNameAsString().c_str(), (int)-idx-3,
(int)VCalls[idx-1], MostDerivedClass->getNameAsCString()));
} else {
- NonVirtualOffset[GD] = NonVirtualOffset[OGD];
- VCallOffset[GD] = VCallOffset[OGD];
- VCalls[idx-1] = -VCallOffset[OGD] + OverrideOffset/8;
+ VCallOffset[GD] = NonVirtualOffset[UMD];
+ VCalls[idx-1] = -VCallOffsetForVCall[UGD] + OverrideOffset/8;
D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n",
MD->getNameAsString().c_str(), (int)-idx-3,
(int)VCalls[idx-1], MostDerivedClass->getNameAsCString()));
}
- int64_t NonVirtualAdjustment = NonVirtualOffset[GD];
+ int64_t NonVirtualAdjustment = -VCallOffset[OGD];
+ QualType DerivedType = MD->getThisType(CGM.getContext());
+ QualType BaseType = cast<const CXXMethodDecl>(OGD.getDecl())->getThisType(CGM.getContext());
+ int64_t NonVirtualAdjustment2 = -(getNVOffset(BaseType, DerivedType)/8);
+ if (NonVirtualAdjustment2 != NonVirtualAdjustment) {
+ NonVirtualAdjustment = NonVirtualAdjustment2;
+ }
int64_t VirtualAdjustment =
-((idx + extra + 2) * LLVMPointerWidth / 8);
@@ -859,12 +2232,19 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
SavedAdjustments.push_back(
std::make_pair(GD, std::make_pair(OGD, ThisAdjustment)));
}
- VCall[GD] = idx;
return true;
}
- int64_t NonVirtualAdjustment = -VCallOffset[OGD] + OverrideOffset/8;
+ VCallOffset[GD] = VCallOffset[OGD2] - OverrideOffset/8;
+ int64_t NonVirtualAdjustment = -VCallOffset[GD];
+ QualType DerivedType = MD->getThisType(CGM.getContext());
+ QualType BaseType = cast<const CXXMethodDecl>(OGD.getDecl())->getThisType(CGM.getContext());
+ int64_t NonVirtualAdjustment2 = -(getNVOffset(BaseType, DerivedType)/8);
+ if (NonVirtualAdjustment2 != NonVirtualAdjustment) {
+ NonVirtualAdjustment = NonVirtualAdjustment2;
+ }
+
if (NonVirtualAdjustment) {
ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, 0);
@@ -880,7 +2260,7 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
return false;
}
-void VtableBuilder::AppendMethodsToVtable() {
+void OldVtableBuilder::AppendMethodsToVtable() {
if (!BuildVtable) {
VtableComponents.insert(VtableComponents.end(), Methods.size(),
(llvm::Constant *)0);
@@ -948,13 +2328,13 @@ void VtableBuilder::AppendMethodsToVtable() {
void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
// Itanium C++ ABI 2.5.2:
- // The order of the virtual function pointers in a virtual table is the
- // order of declaration of the corresponding member functions in the class.
+ // The order of the virtual function pointers in a virtual table is the
+ // order of declaration of the corresponding member functions in the class.
//
- // There is an entry for any virtual function declared in a class,
- // whether it is a new function or overrides a base class function,
- // unless it overrides a function from the primary base, and conversion
- // between their return types does not require an adjustment.
+ // There is an entry for any virtual function declared in a class,
+ // whether it is a new function or overrides a base class function,
+ // unless it overrides a function from the primary base, and conversion
+ // between their return types does not require an adjustment.
int64_t CurrentIndex = 0;
@@ -972,7 +2352,7 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
// Collect all the primary bases, so we can check whether methods override
// a method from the base.
- llvm::SmallPtrSet<const CXXRecordDecl *, 5> PrimaryBases;
+ VtableBuilder::PrimaryBasesSetTy PrimaryBases;
for (ASTRecordLayout::primary_base_info_iterator
I = Layout.primary_base_begin(), E = Layout.primary_base_end();
I != E; ++I)
@@ -988,51 +2368,33 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
if (!MD->isVirtual())
continue;
- bool ShouldAddEntryForMethod = true;
-
// Check if this method overrides a method in the primary base.
- for (CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(),
- e = MD->end_overridden_methods(); i != e; ++i) {
- const CXXMethodDecl *OverriddenMD = *i;
- const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent();
- assert(OverriddenMD->isCanonicalDecl() &&
- "Should have the canonical decl of the overridden RD!");
-
- if (PrimaryBases.count(OverriddenRD)) {
- // Check if converting from the return type of the method to the
- // return type of the overridden method requires conversion.
- QualType ReturnType =
- MD->getType()->getAs<FunctionType>()->getResultType();
- QualType OverriddenReturnType =
- OverriddenMD->getType()->getAs<FunctionType>()->getResultType();
-
- if (!TypeConversionRequiresAdjustment(CGM.getContext(),
- ReturnType, OverriddenReturnType)) {
- // This index is shared between the index in the vtable of the primary
- // base class.
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- const CXXDestructorDecl *OverriddenDD =
- cast<CXXDestructorDecl>(OverriddenMD);
-
- // Add both the complete and deleting entries.
- MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] =
- getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
- MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] =
- getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
- } else {
- MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD);
- }
+ if (const CXXMethodDecl *OverriddenMD =
+ OverridesMethodInPrimaryBase(MD, PrimaryBases)) {
+ // Check if converting from the return type of the method to the
+ // return type of the overridden method requires conversion.
+ if (ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD,
+ OverriddenMD).isEmpty()) {
+ // This index is shared between the index in the vtable of the primary
+ // base class.
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ const CXXDestructorDecl *OverriddenDD =
+ cast<CXXDestructorDecl>(OverriddenMD);
- // We don't need to add an entry for this method.
- ShouldAddEntryForMethod = false;
- break;
- }
+ // Add both the complete and deleting entries.
+ MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] =
+ getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
+ MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] =
+ getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+ } else {
+ MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD);
+ }
+
+ // We don't need to add an entry for this method.
+ continue;
}
}
- if (!ShouldAddEntryForMethod)
- continue;
-
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
if (MD->isImplicit()) {
assert(!ImplicitVirtualDtor &&
@@ -1054,8 +2416,8 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
if (ImplicitVirtualDtor) {
// Itanium C++ ABI 2.5.2:
- // If a class has an implicitly-defined virtual destructor,
- // its entries come after the declared virtual function pointers.
+ // If a class has an implicitly-defined virtual destructor,
+ // its entries come after the declared virtual function pointers.
// Add the complete dtor.
MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
@@ -1107,12 +2469,12 @@ CGVtableInfo::getAdjustments(GlobalDecl GD) {
return 0;
AddressPointsMapTy AddressPoints;
- VtableBuilder b(RD, RD, 0, CGM, false, AddressPoints);
+ OldVtableBuilder b(RD, RD, 0, CGM, false, AddressPoints);
D1(printf("vtable %s\n", RD->getNameAsCString()));
b.GenerateVtableForBase(RD);
b.GenerateVtableForVBases(RD);
- for (VtableBuilder::SavedAdjustmentsVectorTy::iterator
+ for (OldVtableBuilder::SavedAdjustmentsVectorTy::iterator
i = b.getSavedAdjustments().begin(),
e = b.getSavedAdjustments().end(); i != e; i++)
SavedAdjustments[i->first].push_back(i->second);
@@ -1136,7 +2498,7 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
// FIXME: This seems expensive. Can we do a partial job to get
// just this data.
AddressPointsMapTy AddressPoints;
- VtableBuilder b(RD, RD, 0, CGM, false, AddressPoints);
+ OldVtableBuilder b(RD, RD, 0, CGM, false, AddressPoints);
D1(printf("vtable %s\n", RD->getNameAsCString()));
b.GenerateVtableForBase(RD);
b.GenerateVtableForVBases(RD);
@@ -1150,6 +2512,12 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
}
I = VirtualBaseClassIndicies.find(ClassPair);
+ // FIXME: The assertion below assertion currently fails with the old vtable
+ /// layout code if there is a non-virtual thunk adjustment in a vtable.
+ // Once the new layout is in place, this return should be removed.
+ if (I == VirtualBaseClassIndicies.end())
+ return 0;
+
assert(I != VirtualBaseClassIndicies.end() && "Did not find index!");
return I->second;
@@ -1168,6 +2536,13 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
const CXXRecordDecl *LayoutClass,
const CXXRecordDecl *RD, uint64_t Offset,
AddressPointsMapTy& AddressPoints) {
+ if (GenerateDefinition && CGM.getLangOptions().DumpVtableLayouts &&
+ LayoutClass == RD) {
+ VtableBuilder Builder(*this, RD);
+
+ Builder.dumpLayout(llvm::errs());
+ }
+
llvm::SmallString<256> OutName;
if (LayoutClass != RD)
CGM.getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset / 8,
@@ -1179,8 +2554,8 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
if (GV == 0 || CGM.getVtableInfo().AddressPoints[LayoutClass] == 0 ||
GV->isDeclaration()) {
- VtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition,
- AddressPoints);
+ OldVtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition,
+ AddressPoints);
D1(printf("vtable %s\n", RD->getNameAsCString()));
// First comes the vtables for all the non-virtual bases...
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index f0a5c64d2fdf..5a4f94e3e092 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -171,6 +171,16 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
CurFn = Fn;
assert(CurFn->isDeclaration() && "Function already has body?");
+ // Pass inline keyword to optimizer if it appears explicitly on any
+ // declaration.
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
+ for (FunctionDecl::redecl_iterator RI = FD->redecls_begin(),
+ RE = FD->redecls_end(); RI != RE; ++RI)
+ if (RI->isInlineSpecified()) {
+ Fn->addFnAttr(llvm::Attribute::InlineHint);
+ break;
+ }
+
llvm::BasicBlock *EntryBB = createBasicBlock("entry", CurFn);
// Create a marker to make it easy to insert allocas into the entryblock
@@ -196,7 +206,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
}
// FIXME: Leaked.
- CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args);
+ // CC info is ignored, hopefully?
+ CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args,
+ CC_Default, false);
if (RetTy->isVoidType()) {
// Void type; nothing to return.
@@ -281,6 +293,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) {
llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue");
PushCleanupBlock(DtorEpilogue);
+ InitializeVtablePtrs(DD->getParent());
+
EmitStmt(S);
CleanupBlockInfo Info = PopCleanupBlock();
@@ -431,7 +445,11 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
EmitBranchOnBoolExpr(CondBOp->getLHS(), LHSTrue, FalseBlock);
EmitBlock(LHSTrue);
+ // Any temporaries created here are conditional.
+ BeginConditionalBranch();
EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock);
+ EndConditionalBranch();
+
return;
} else if (CondBOp->getOpcode() == BinaryOperator::LOr) {
// If we have "0 || X", simplify the code. "1 || X" would have constant
@@ -454,7 +472,11 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, LHSFalse);
EmitBlock(LHSFalse);
+ // Any temporaries created here are conditional.
+ BeginConditionalBranch();
EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock);
+ EndConditionalBranch();
+
return;
}
}
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 30ad663771be..fb2e5fee7309 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -268,7 +268,7 @@ public:
/// this behavior for branches?
void EmitBranchThroughCleanup(llvm::BasicBlock *Dest);
- /// StartConditionalBranch - Should be called before a conditional part of an
+ /// BeginConditionalBranch - Should be called before a conditional part of an
/// expression is emitted. For example, before the RHS of the expression below
/// is emitted:
///
@@ -276,13 +276,16 @@ public:
///
/// This is used to make sure that any temporaries created in the conditional
/// branch are only destroyed if the branch is taken.
- void StartConditionalBranch() {
+ void BeginConditionalBranch() {
++ConditionalBranchLevel;
}
- /// FinishConditionalBranch - Should be called after a conditional part of an
+ /// EndConditionalBranch - Should be called after a conditional part of an
/// expression has been emitted.
- void FinishConditionalBranch() {
+ void EndConditionalBranch() {
+ assert(ConditionalBranchLevel != 0 &&
+ "Conditional branch mismatch!");
+
--ConditionalBranchLevel;
}
@@ -472,7 +475,7 @@ public:
const BlockInfo& Info,
const Decl *OuterFuncDecl,
llvm::DenseMap<const Decl*, llvm::Value*> ldm,
- CharUnits &Size, uint64_t &Align,
+ CharUnits &Size, CharUnits &Align,
llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls,
bool &subBlockHasCopyDispose);
@@ -569,6 +572,9 @@ public:
const llvm::Type *ConvertTypeForMem(QualType T);
const llvm::Type *ConvertType(QualType T);
+ const llvm::Type *ConvertType(const TypeDecl *T) {
+ return ConvertType(getContext().getTypeDeclType(T));
+ }
/// LoadObjCSelf - Load the value of self. This function is only valid while
/// generating code for an Objective-C method.
@@ -652,10 +658,15 @@ public:
}
/// CreateTempAlloca - This creates a alloca and inserts it into the entry
- /// block.
+ /// block. The caller is responsible for setting an appropriate alignment on
+ /// the alloca.
llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty,
const llvm::Twine &Name = "tmp");
+ /// CreateMemTemp - Create a temporary memory object of the given type, with
+ /// appropriate alignment.
+ llvm::Value *CreateMemTemp(QualType T, const llvm::Twine &Name = "tmp");
+
/// EvaluateExprAsBool - Perform the usual unary conversions on the specified
/// expression and compare the result against zero, returning an Int1Ty value.
llvm::Value *EvaluateExprAsBool(const Expr *E);
@@ -732,11 +743,16 @@ public:
/// LoadCXXVTT - Load the VTT parameter to base constructors/destructors have
/// virtual bases.
llvm::Value *LoadCXXVTT();
+
+ /// GetAddressOfBaseOfCompleteClass - Convert the given pointer to a
+ /// complete class down to one of its virtual bases.
+ llvm::Value *GetAddressOfBaseOfCompleteClass(llvm::Value *Value,
+ bool IsVirtual,
+ const CXXRecordDecl *Derived,
+ const CXXRecordDecl *Base);
/// GetAddressOfBaseClass - This function will add the necessary delta to the
/// load of 'this' and returns address of the base class.
- // FIXME. This currently only does a derived to non-virtual base conversion.
- // Other kinds of conversions will come later.
llvm::Value *GetAddressOfBaseClass(llvm::Value *Value,
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl,
@@ -747,10 +763,9 @@ public:
const CXXRecordDecl *DerivedClassDecl,
bool NullCheckValue);
- llvm::Value *
- GetVirtualCXXBaseClassOffset(llvm::Value *This,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl);
+ llvm::Value *GetVirtualBaseClassOffset(llvm::Value *This,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl);
void EmitClassAggrMemberwiseCopy(llvm::Value *DestValue,
llvm::Value *SrcValue,
@@ -843,7 +858,8 @@ public:
/// This function can be called with a null (unreachable) insert point.
void EmitLocalBlockVarDecl(const VarDecl &D);
- void EmitStaticBlockVarDecl(const VarDecl &D);
+ void EmitStaticBlockVarDecl(const VarDecl &D,
+ llvm::GlobalValue::LinkageTypes Linkage);
/// EmitParmDecl - Emit a ParmVarDecl or an ImplicitParamDecl.
void EmitParmDecl(const VarDecl &D, llvm::Value *Arg);
@@ -1005,12 +1021,18 @@ public:
LValue EmitCastLValue(const CastExpr *E);
LValue EmitNullInitializationLValue(const CXXZeroInitValueExpr *E);
- LValue EmitPointerToDataMemberLValue(const FieldDecl *Field);
-
llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
LValue EmitLValueForField(llvm::Value* Base, const FieldDecl* Field,
- bool isUnion, unsigned CVRQualifiers);
+ unsigned CVRQualifiers);
+
+ /// EmitLValueForFieldInitialization - Like EmitLValueForField, except that
+ /// if the Field is a reference, this will return the address of the reference
+ /// and not the address of the value stored in the reference.
+ LValue EmitLValueForFieldInitialization(llvm::Value* Base,
+ const FieldDecl* Field,
+ unsigned CVRQualifiers);
+
LValue EmitLValueForIvar(QualType ObjectTy,
llvm::Value* Base, const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers);
@@ -1103,8 +1125,7 @@ public:
/// EmitReferenceBindingToExpr - Emits a reference binding to the passed in
/// expression. Will emit a temporary variable if E is not an LValue.
- RValue EmitReferenceBindingToExpr(const Expr* E, QualType DestType,
- bool IsInitializer = false);
+ RValue EmitReferenceBindingToExpr(const Expr* E, bool IsInitializer = false);
//===--------------------------------------------------------------------===//
// Expression Emission
@@ -1135,6 +1156,10 @@ public:
bool IgnoreResult = false, bool IsInitializer = false,
bool RequiresGCollection = false);
+ /// EmitAggExprToLValue - Emit the computation of the specified expression of
+ /// aggregate type into a temporary LValue.
+ LValue EmitAggExprToLValue(const Expr *E);
+
/// EmitGCMemmoveCollectable - Emit special API for structs with object
/// pointers.
void EmitGCMemmoveCollectable(llvm::Value *DestPtr, llvm::Value *SrcPtr,
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index cf504a7c2a0c..5a552c490ac6 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -20,6 +20,7 @@
#include "TargetInfo.h"
#include "clang/CodeGen/CodeGenOptions.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/RecordLayout.h"
@@ -131,6 +132,10 @@ CodeGenModule::getDeclVisibilityMode(const Decl *D) const {
}
}
+ // This decl should have the same visibility as its parent.
+ if (const DeclContext *DC = D->getDeclContext())
+ return getDeclVisibilityMode(cast<Decl>(DC));
+
return getLangOptions().getVisibilityMode();
}
@@ -254,34 +259,40 @@ void CodeGenModule::EmitAnnotations() {
static CodeGenModule::GVALinkage
GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
const LangOptions &Features) {
- // Everything located semantically within an anonymous namespace is
- // always internal.
- if (FD->isInAnonymousNamespace())
- return CodeGenModule::GVA_Internal;
+ CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal;
- // "static" functions get internal linkage.
- if (FD->getStorageClass() == FunctionDecl::Static && !isa<CXXMethodDecl>(FD))
- return CodeGenModule::GVA_Internal;
+ Linkage L = FD->getLinkage();
+ if (L == ExternalLinkage && Context.getLangOptions().CPlusPlus &&
+ FD->getType()->getLinkage() == UniqueExternalLinkage)
+ L = UniqueExternalLinkage;
- // The kind of external linkage this function will have, if it is not
- // inline or static.
- CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal;
- if (Context.getLangOptions().CPlusPlus) {
- TemplateSpecializationKind TSK = FD->getTemplateSpecializationKind();
+ switch (L) {
+ case NoLinkage:
+ case InternalLinkage:
+ case UniqueExternalLinkage:
+ return CodeGenModule::GVA_Internal;
- if (TSK == TSK_ExplicitInstantiationDefinition) {
- // If a function has been explicitly instantiated, then it should
- // always have strong external linkage.
+ case ExternalLinkage:
+ switch (FD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ External = CodeGenModule::GVA_StrongExternal;
+ break;
+
+ case TSK_ExplicitInstantiationDefinition:
+ // FIXME: explicit instantiation definitions should use weak linkage
return CodeGenModule::GVA_StrongExternal;
- }
-
- if (TSK == TSK_ImplicitInstantiation)
+
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ImplicitInstantiation:
External = CodeGenModule::GVA_TemplateInstantiation;
+ break;
+ }
}
if (!FD->isInlined())
return External;
-
+
if (!Features.CPlusPlus || FD->hasAttr<GNUInlineAttr>()) {
// GNU or C99 inline semantics. Determine whether this symbol should be
// externally visible.
@@ -402,11 +413,13 @@ void CodeGenModule::SetInternalFunctionAttributes(const Decl *D,
SetCommonAttributes(D, F);
}
-void CodeGenModule::SetFunctionAttributes(const FunctionDecl *FD,
+void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
llvm::Function *F,
bool IsIncompleteFunction) {
+ const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
+
if (!IsIncompleteFunction)
- SetLLVMFunctionAttributes(FD, getTypes().getFunctionInfo(FD), F);
+ SetLLVMFunctionAttributes(FD, getTypes().getFunctionInfo(GD), F);
// Only a few attributes are set on declarations; these may later be
// overridden by a definition.
@@ -580,14 +593,24 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
// Static data may be deferred, but out-of-line static data members
// cannot be.
- if (VD->isInAnonymousNamespace())
- return true;
- if (VD->getLinkage() == VarDecl::InternalLinkage) {
+ Linkage L = VD->getLinkage();
+ if (L == ExternalLinkage && getContext().getLangOptions().CPlusPlus &&
+ VD->getType()->getLinkage() == UniqueExternalLinkage)
+ L = UniqueExternalLinkage;
+
+ switch (L) {
+ case NoLinkage:
+ case InternalLinkage:
+ case UniqueExternalLinkage:
// Initializer has side effects?
if (VD->getInit() && VD->getInit()->HasSideEffects(Context))
return false;
return !(VD->isStaticDataMember() && VD->isOutOfLine());
+
+ case ExternalLinkage:
+ break;
}
+
return false;
}
@@ -608,20 +631,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
const VarDecl *VD = cast<VarDecl>(Global);
assert(VD->isFileVarDecl() && "Cannot emit local var decl as global.");
- if (getLangOptions().CPlusPlus && !VD->getInit()) {
- // In C++, if this is marked "extern", defer code generation.
- if (VD->getStorageClass() == VarDecl::Extern || VD->isExternC())
- return;
-
- // If this is a declaration of an explicit specialization of a static
- // data member in a class template, don't emit it.
- if (VD->isStaticDataMember() &&
- VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
- return;
- }
-
- // In C, if this isn't a definition, defer code generation.
- if (!getLangOptions().CPlusPlus && !VD->getInit())
+ if (VD->isThisDeclarationADefinition() != VarDecl::Definition)
return;
}
@@ -715,8 +725,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
"", &getModule());
F->setName(MangledName);
if (D.getDecl())
- SetFunctionAttributes(cast<FunctionDecl>(D.getDecl()), F,
- IsIncompleteFunction);
+ SetFunctionAttributes(D, F, IsIncompleteFunction);
Entry = F;
// This is the first use or definition of a mangled name. If there is a
@@ -774,7 +783,7 @@ CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy,
}
static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D) {
- if (!D->getType().isConstant(Context))
+ if (!D->getType().isConstant(Context) && !D->getType()->isReferenceType())
return false;
if (Context.getLangOptions().CPlusPlus &&
Context.getBaseElementType(D->getType())->getAs<RecordType>()) {
@@ -941,16 +950,30 @@ CodeGenModule::getVtableLinkage(const CXXRecordDecl *RD) {
static CodeGenModule::GVALinkage
GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
- // Everything located semantically within an anonymous namespace is
- // always internal.
- if (VD->isInAnonymousNamespace())
+ // If this is a static data member, compute the kind of template
+ // specialization. Otherwise, this variable is not part of a
+ // template.
+ TemplateSpecializationKind TSK = TSK_Undeclared;
+ if (VD->isStaticDataMember())
+ TSK = VD->getTemplateSpecializationKind();
+
+ Linkage L = VD->getLinkage();
+ if (L == ExternalLinkage && Context.getLangOptions().CPlusPlus &&
+ VD->getType()->getLinkage() == UniqueExternalLinkage)
+ L = UniqueExternalLinkage;
+
+ switch (L) {
+ case NoLinkage:
+ case InternalLinkage:
+ case UniqueExternalLinkage:
return CodeGenModule::GVA_Internal;
- // Handle linkage for static data members.
- if (VD->isStaticDataMember()) {
- switch (VD->getTemplateSpecializationKind()) {
+ case ExternalLinkage:
+ switch (TSK) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
+
+ // FIXME: ExplicitInstantiationDefinition should be weak!
case TSK_ExplicitInstantiationDefinition:
return CodeGenModule::GVA_StrongExternal;
@@ -959,22 +982,26 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
// Fall through to treat this like any other instantiation.
case TSK_ImplicitInstantiation:
- return CodeGenModule::GVA_TemplateInstantiation;
+ return CodeGenModule::GVA_TemplateInstantiation;
}
}
- if (VD->getLinkage() == VarDecl::InternalLinkage)
- return CodeGenModule::GVA_Internal;
-
return CodeGenModule::GVA_StrongExternal;
}
+CharUnits CodeGenModule::GetTargetTypeStoreSize(const llvm::Type *Ty) const {
+ return CharUnits::fromQuantity(
+ TheTargetData.getTypeStoreSizeInBits(Ty) / Context.getCharWidth());
+}
+
void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
llvm::Constant *Init = 0;
QualType ASTTy = D->getType();
bool NonConstInit = false;
- if (D->getInit() == 0) {
+ const Expr *InitExpr = D->getAnyInitializer();
+
+ if (!InitExpr) {
// This is a tentative definition; tentative definitions are
// implicitly initialized with { 0 }.
//
@@ -987,10 +1014,10 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
assert(!ASTTy->isIncompleteType() && "Unexpected incomplete type");
Init = EmitNullConstant(D->getType());
} else {
- Init = EmitConstantExpr(D->getInit(), D->getType());
+ Init = EmitConstantExpr(InitExpr, D->getType());
if (!Init) {
- QualType T = D->getInit()->getType();
+ QualType T = InitExpr->getType();
if (getLangOptions().CPlusPlus) {
EmitCXXGlobalVarDeclInitFunc(D);
Init = EmitNullConstant(T);
@@ -1058,7 +1085,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
if (!NonConstInit && DeclIsConstantGlobal(Context, D))
GV->setConstant(true);
- GV->setAlignment(getContext().getDeclAlignInBytes(D));
+ GV->setAlignment(getContext().getDeclAlign(D).getQuantity());
// Set the llvm linkage type as appropriate.
GVALinkage Linkage = GetLinkageForVariable(getContext(), D);
@@ -1256,8 +1283,8 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) {
const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType());
// Unique the name through the identifier table.
- const char *AliaseeName = AA->getAliasee().c_str();
- AliaseeName = getContext().Idents.get(AliaseeName).getNameStart();
+ const char *AliaseeName =
+ getContext().Idents.get(AA->getAliasee()).getNameStart();
// Create a reference to the named value. This ensures that it is emitted
// if a deferred decl.
@@ -1473,11 +1500,9 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
// String pointer.
llvm::Constant *C = llvm::ConstantArray::get(VMContext, Entry.getKey().str());
- const char *Sect = 0;
llvm::GlobalValue::LinkageTypes Linkage;
bool isConstant;
if (isUTF16) {
- Sect = getContext().Target.getUnicodeStringSection();
// FIXME: why do utf strings get "_" labels instead of "L" labels?
Linkage = llvm::GlobalValue::InternalLinkage;
// Note: -fwritable-strings doesn't make unicode CFStrings writable, but
@@ -1491,11 +1516,9 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C,
".str");
- if (Sect)
- GV->setSection(Sect);
if (isUTF16) {
- unsigned Align = getContext().getTypeAlign(getContext().ShortTy)/8;
- GV->setAlignment(Align);
+ CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy);
+ GV->setAlignment(Align.getQuantity());
}
Fields[2] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 81f39791fcd0..8280766c7035 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -53,6 +53,7 @@ namespace clang {
class ObjCProtocolDecl;
class ObjCEncodeExpr;
class BlockExpr;
+ class CharUnits;
class Decl;
class Expr;
class Stmt;
@@ -238,10 +239,11 @@ public:
BuildCovariantThunk(const GlobalDecl &GD, bool Extern,
const CovariantThunkAdjustment &Adjustment);
- /// 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,
- const CXXRecordDecl *BaseClassDecl);
+ /// GetNonVirtualBaseClassOffset - Returns the offset from a derived class to
+ /// its base class. Returns null if the offset is 0.
+ llvm::Constant *
+ GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl);
/// ComputeThunkAdjustment - Returns the two parts required to compute the
/// offset for an object.
@@ -346,6 +348,8 @@ public:
llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV,
const AnnotateAttr *AA, unsigned LineNo);
+ llvm::Constant *EmitPointerToDataMember(const FieldDecl *FD);
+
/// ErrorUnsupported - Print out an error that codegen doesn't support the
/// specified stmt yet.
/// \param OmitOnError - If true, then this error should only be emitted if no
@@ -417,6 +421,10 @@ public:
/// and type information of the given class.
static llvm::GlobalVariable::LinkageTypes
getVtableLinkage(const CXXRecordDecl *RD);
+
+ /// GetTargetTypeStoreSize - Return the store size, in character units, of
+ /// the given LLVM type.
+ CharUnits GetTargetTypeStoreSize(const llvm::Type *Ty) const;
private:
/// UniqueMangledName - Unique a name by (if necessary) inserting it into the
@@ -443,7 +451,7 @@ private:
/// SetFunctionAttributes - Set function attributes for a function
/// declaration.
- void SetFunctionAttributes(const FunctionDecl *FD,
+ void SetFunctionAttributes(GlobalDecl GD,
llvm::Function *F,
bool IsIncompleteFunction);
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 838f62a5cb1d..3c20934baf25 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -84,7 +84,7 @@ const llvm::Type *CodeGenTypes::ConvertTypeRecursive(QualType T) {
const llvm::Type *CodeGenTypes::ConvertTypeForMemRecursive(QualType T) {
const llvm::Type *ResultType = ConvertTypeRecursive(T);
- if (ResultType->isInteger(1))
+ if (ResultType->isIntegerTy(1))
return llvm::IntegerType::get(getLLVMContext(),
(unsigned)Context.getTypeSize(T));
// FIXME: Should assert that the llvm type and AST type has the same size.
@@ -99,7 +99,7 @@ const llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) {
const llvm::Type *R = ConvertType(T);
// If this is a non-bool type, don't map it.
- if (!R->isInteger(1))
+ if (!R->isIntegerTy(1))
return R;
// Otherwise, return an integer of the target-specified size.
@@ -399,18 +399,6 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
/// enum.
const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
- // FIXME. This may have to move to a better place.
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) {
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- if (!i->isVirtual()) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- ConvertTagDeclType(Base);
- }
- }
- }
-
// TagDecl's are not necessarily unique, instead use the (clang)
// type connected to the decl.
const Type *Key =
@@ -422,8 +410,8 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
if (TDTI != TagDeclTypes.end())
return TDTI->second;
- // If this is still a forward definition, just define an opaque type to use
- // for this tagged decl.
+ // If this is still a forward declaration, just define an opaque
+ // type to use for this tagged decl.
if (!TD->isDefinition()) {
llvm::Type *ResultType = llvm::OpaqueType::get(getLLVMContext());
TagDeclTypes.insert(std::make_pair(Key, ResultType));
@@ -446,6 +434,18 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
const RecordDecl *RD = cast<const RecordDecl>(TD);
+ // Force conversion of non-virtual base classes recursively.
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) {
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ if (!i->isVirtual()) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ ConvertTagDeclType(Base);
+ }
+ }
+ }
+
// Layout fields.
CGRecordLayout *Layout = CGRecordLayoutBuilder::ComputeLayout(*this, RD);
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 7e342526e84b..87ba0bcfba1d 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -20,7 +20,7 @@
#include <vector>
#include "CGCall.h"
-#include "CGCXX.h"
+#include "GlobalDecl.h"
namespace llvm {
class FunctionType;
@@ -60,21 +60,24 @@ namespace CodeGen {
/// LLVMType - The LLVMType corresponding to this record layout.
const llvm::Type *LLVMType;
- /// ContainsMemberPointer - Whether one of the fields in this record layout
- /// is a member pointer, or a struct that contains a member pointer.
- bool ContainsMemberPointer;
+ /// ContainsPointerToDataMember - Whether one of the fields in this record
+ /// layout is a pointer to data member, or a struct that contains pointer to
+ /// data member.
+ bool ContainsPointerToDataMember;
public:
- CGRecordLayout(const llvm::Type *T, bool ContainsMemberPointer)
- : LLVMType(T), ContainsMemberPointer(ContainsMemberPointer) { }
+ CGRecordLayout(const llvm::Type *T, bool ContainsPointerToDataMember)
+ : LLVMType(T), ContainsPointerToDataMember(ContainsPointerToDataMember) { }
/// getLLVMType - Return llvm type associated with this record.
const llvm::Type *getLLVMType() const {
return LLVMType;
}
- bool containsMemberPointer() const {
- return ContainsMemberPointer;
+ /// containsPointerToDataMember - Whether this struct contains pointers to
+ /// data members.
+ bool containsPointerToDataMember() const {
+ return ContainsPointerToDataMember;
}
};
@@ -187,6 +190,8 @@ private:
public:
/// getFunctionInfo - Get the function info for the specified function decl.
+ const CGFunctionInfo &getFunctionInfo(GlobalDecl GD);
+
const CGFunctionInfo &getFunctionInfo(const FunctionDecl *FD);
const CGFunctionInfo &getFunctionInfo(const CXXMethodDecl *MD);
const CGFunctionInfo &getFunctionInfo(const ObjCMethodDecl *MD);
@@ -195,6 +200,12 @@ public:
const CGFunctionInfo &getFunctionInfo(const CXXDestructorDecl *D,
CXXDtorType Type);
+ const CGFunctionInfo &getFunctionInfo(const CallArgList &Args,
+ const FunctionType *Ty) {
+ return getFunctionInfo(Ty->getResultType(), Args,
+ Ty->getCallConv(), Ty->getNoReturnAttr());
+ }
+
// getFunctionInfo - Get the function info for a member function.
const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD,
const FunctionProtoType *FTP);
@@ -204,13 +215,16 @@ public:
/// specified, the "C" calling convention will be used.
const CGFunctionInfo &getFunctionInfo(QualType ResTy,
const CallArgList &Args,
- unsigned CallingConvention = 0);
+ CallingConv CC,
+ bool NoReturn);
const CGFunctionInfo &getFunctionInfo(QualType ResTy,
const FunctionArgList &Args,
- unsigned CallingConvention = 0);
+ CallingConv CC,
+ bool NoReturn);
const CGFunctionInfo &getFunctionInfo(QualType RetTy,
const llvm::SmallVector<QualType, 16> &ArgTys,
- unsigned CallingConvention = 0);
+ CallingConv CC,
+ bool NoReturn);
public: // These are internal details of CGT that shouldn't be used externally.
/// addFieldInfo - Assign field number to field FD.
diff --git a/lib/CodeGen/GlobalDecl.h b/lib/CodeGen/GlobalDecl.h
index b054312a0185..b8a98d7c03b6 100644
--- a/lib/CodeGen/GlobalDecl.h
+++ b/lib/CodeGen/GlobalDecl.h
@@ -15,6 +15,10 @@
#ifndef CLANG_CODEGEN_GLOBALDECL_H
#define CLANG_CODEGEN_GLOBALDECL_H
+#include "CGCXX.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+
namespace clang {
namespace CodeGen {
diff --git a/lib/CodeGen/Makefile b/lib/CodeGen/Makefile
index 108490b71d48..83cb36738709 100644
--- a/lib/CodeGen/Makefile
+++ b/lib/CodeGen/Makefile
@@ -15,7 +15,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangCodeGen
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
ifdef CLANG_VENDOR
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index d873cfec1bd7..a302225c7f77 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -26,6 +26,13 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include "CGVtable.h"
+
+#define MANGLE_CHECKER 0
+
+#if MANGLE_CHECKER
+#include <cxxabi.h>
+#endif
+
using namespace clang;
using namespace CodeGen;
@@ -44,6 +51,8 @@ static const CXXMethodDecl *getStructor(const CXXMethodDecl *MD) {
return MD;
}
+
+static const unsigned UnknownArity = ~0U;
/// CXXNameMangler - Manage the mangling of a single name.
class CXXNameMangler {
@@ -55,6 +64,8 @@ class CXXNameMangler {
llvm::DenseMap<uintptr_t, unsigned> Substitutions;
+ ASTContext &getASTContext() const { return Context.getASTContext(); }
+
public:
CXXNameMangler(MangleContext &C, llvm::SmallVectorImpl<char> &Res)
: Context(C), Out(Res), Structor(0), StructorType(0) { }
@@ -65,6 +76,17 @@ public:
const CXXDestructorDecl *D, CXXDtorType Type)
: Context(C), Out(Res), Structor(getStructor(D)), StructorType(Type) { }
+#if MANGLE_CHECKER
+ ~CXXNameMangler() {
+ if (Out.str()[0] == '\01')
+ return;
+
+ int status = 0;
+ char *result = abi::__cxa_demangle(Out.str().str().c_str(), 0, 0, &status);
+ assert(status == 0 && "Could not demangle mangled name!");
+ free(result);
+ }
+#endif
llvm::raw_svector_ostream &getStream() { return Out; }
void mangle(const NamedDecl *D, llvm::StringRef Prefix = "_Z");
@@ -89,10 +111,19 @@ private:
void addSubstitution(QualType T);
void addSubstitution(uintptr_t Ptr);
+ void mangleUnresolvedScope(NestedNameSpecifier *Qualifier);
+ void mangleUnresolvedName(NestedNameSpecifier *Qualifier,
+ DeclarationName Name,
+ unsigned KnownArity = UnknownArity);
+
void mangleName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
- void mangleUnqualifiedName(const NamedDecl *ND);
+ void mangleUnqualifiedName(const NamedDecl *ND) {
+ mangleUnqualifiedName(ND, ND->getDeclName(), UnknownArity);
+ }
+ void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name,
+ unsigned KnownArity);
void mangleUnscopedName(const NamedDecl *ND);
void mangleUnscopedTemplateName(const TemplateDecl *ND);
void mangleSourceName(const IdentifierInfo *II);
@@ -119,6 +150,11 @@ private:
bool MangleReturnType);
void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value);
+ void mangleMemberExpr(const Expr *Base, bool IsArrow,
+ NestedNameSpecifier *Qualifier,
+ DeclarationName Name,
+ unsigned KnownArity);
+ void mangleCalledExpression(const Expr *E, unsigned KnownArity);
void mangleExpression(const Expr *E);
void mangleCXXCtorType(CXXCtorType T);
void mangleCXXDtorType(CXXDtorType T);
@@ -171,14 +207,14 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
isInExternCSystemHeader(D->getLocation()))
return false;
- // Variables at global scope are not mangled.
+ // Variables at global scope with non-internal linkage are not mangled
if (!FD) {
const DeclContext *DC = D->getDeclContext();
// Check for extern variable declared locally.
if (isa<FunctionDecl>(DC) && D->hasLinkage())
while (!DC->isNamespace() && !DC->isTranslationUnit())
DC = DC->getParent();
- if (DC->isTranslationUnit())
+ if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage)
return false;
}
@@ -199,13 +235,10 @@ void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) {
return;
}
- // <mangled-name> ::= _Z [L] <encoding>
+ // <mangled-name> ::= _Z <encoding>
// ::= <data name>
// ::= <special-name>
Out << Prefix;
- if (D->getLinkage() == NamedDecl::InternalLinkage) // match gcc behavior
- Out << 'L';
-
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
mangleFunctionEncoding(FD);
else
@@ -367,6 +400,13 @@ void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) {
if (mangleSubstitution(ND))
return;
+ // <template-template-param> ::= <template-param>
+ if (const TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(ND)) {
+ mangleTemplateParameter(TTP->getIndex());
+ return;
+ }
+
mangleUnscopedName(ND->getTemplatedDecl());
addSubstitution(ND);
}
@@ -401,28 +441,69 @@ void CXXNameMangler::mangleCallOffset(const ThunkAdjustment &Adjustment) {
Out << '_';
}
-void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
+void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) {
+ Qualifier = getASTContext().getCanonicalNestedNameSpecifier(Qualifier);
+ switch (Qualifier->getKind()) {
+ case NestedNameSpecifier::Global:
+ // nothing
+ break;
+ case NestedNameSpecifier::Namespace:
+ mangleName(Qualifier->getAsNamespace());
+ break;
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ mangleType(QualType(Qualifier->getAsType(), 0));
+ break;
+ case NestedNameSpecifier::Identifier:
+ mangleUnresolvedScope(Qualifier->getPrefix());
+ mangleSourceName(Qualifier->getAsIdentifier());
+ break;
+ }
+}
+
+/// Mangles a name which was not resolved to a specific entity.
+void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *Qualifier,
+ DeclarationName Name,
+ unsigned KnownArity) {
+ if (Qualifier)
+ mangleUnresolvedScope(Qualifier);
+ // FIXME: ambiguity of unqualified lookup with ::
+
+ mangleUnqualifiedName(0, Name, KnownArity);
+}
+
+void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
+ DeclarationName Name,
+ unsigned KnownArity) {
// <unqualified-name> ::= <operator-name>
// ::= <ctor-dtor-name>
// ::= <source-name>
- DeclarationName Name = ND->getDeclName();
switch (Name.getNameKind()) {
case DeclarationName::Identifier: {
+ if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
+ // We must avoid conflicts between internally- and externally-
+ // linked variable declaration names in the same TU.
+ // This naming convention is the same as that followed by GCC, though it
+ // shouldn't actually matter.
+ if (ND && isa<VarDecl>(ND) && ND->getLinkage() == InternalLinkage &&
+ ND->getDeclContext()->isFileContext())
+ Out << 'L';
+
+ mangleSourceName(II);
+ break;
+ }
+
+ // Otherwise, an anonymous entity. We must have a declaration.
+ assert(ND && "mangling empty name without declaration");
+
if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
if (NS->isAnonymousNamespace()) {
- // This is how gcc mangles these names. It's apparently
- // always '1', no matter how many different anonymous
- // namespaces appear in a context.
+ // This is how gcc mangles these names.
Out << "12_GLOBAL__N_1";
break;
}
}
- if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
- mangleSourceName(II);
- break;
- }
-
// We must have an anonymous struct.
const TagDecl *TD = cast<TagDecl>(ND);
if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) {
@@ -484,13 +565,18 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
break;
case DeclarationName::CXXOperatorName: {
- unsigned Arity = cast<FunctionDecl>(ND)->getNumParams();
+ unsigned Arity;
+ if (ND) {
+ Arity = cast<FunctionDecl>(ND)->getNumParams();
- // If we have a C++ member function, we need to include the 'this' pointer.
- // FIXME: This does not make sense for operators that are static, but their
- // names stay the same regardless of the arity (operator new for instance).
- if (isa<CXXMethodDecl>(ND))
- Arity++;
+ // If we have a C++ member function, we need to include the 'this' pointer.
+ // FIXME: This does not make sense for operators that are static, but their
+ // names stay the same regardless of the arity (operator new for instance).
+ if (isa<CXXMethodDecl>(ND))
+ Arity++;
+ } else
+ Arity = KnownArity;
+
mangleOperatorName(Name.getCXXOverloadedOperator(), Arity);
break;
}
@@ -596,15 +682,21 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
// <template-prefix> ::= <prefix> <template unqualified-name>
// ::= <template-param>
// ::= <substitution>
+ // <template-template-param> ::= <template-param>
+ // <substitution>
if (mangleSubstitution(ND))
return;
- // FIXME: <template-param>
+ // <template-template-param> ::= <template-param>
+ if (const TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(ND)) {
+ mangleTemplateParameter(TTP->getIndex());
+ return;
+ }
manglePrefix(ND->getDeclContext());
mangleUnqualifiedName(ND->getTemplatedDecl());
-
addSubstitution(ND);
}
@@ -1013,7 +1105,7 @@ void CXXNameMangler::mangleType(const TypenameType *T) {
dyn_cast<TemplateSpecializationType>(QTy)) {
if (!mangleSubstitution(QualType(TST, 0))) {
TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
-
+ assert(TD && "FIXME: Support dependent template names");
mangleTemplatePrefix(TD);
mangleTemplateArgs(TST->getArgs(), TST->getNumArgs());
addSubstitution(QualType(TST, 0));
@@ -1049,23 +1141,151 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T,
}
+void CXXNameMangler::mangleCalledExpression(const Expr *E, unsigned Arity) {
+ if (E->getType() != getASTContext().OverloadTy)
+ mangleExpression(E);
+ // propagate arity to dependent overloads?
+
+ llvm::PointerIntPair<OverloadExpr*,1> R
+ = OverloadExpr::find(const_cast<Expr*>(E));
+ if (R.getInt())
+ Out << "an"; // &
+ const OverloadExpr *Ovl = R.getPointer();
+ if (const UnresolvedMemberExpr *ME = dyn_cast<UnresolvedMemberExpr>(Ovl)) {
+ mangleMemberExpr(ME->getBase(), ME->isArrow(), ME->getQualifier(),
+ ME->getMemberName(), Arity);
+ return;
+ }
+
+ mangleUnresolvedName(Ovl->getQualifier(), Ovl->getName(), Arity);
+}
+
+/// Mangles a member expression. Implicit accesses are not handled,
+/// but that should be okay, because you shouldn't be able to
+/// make an implicit access in a function template declaration.
+///
+/// The standard ABI does not describe how member expressions should
+/// be mangled, so this is very unstandardized. We mangle as if it
+/// were a binary operator, except that the RHS is mangled as an
+/// abstract name.
+///
+/// The standard ABI also does not assign a mangling to the dot
+/// operator, so we arbitrarily select 'me'.
+void CXXNameMangler::mangleMemberExpr(const Expr *Base,
+ bool IsArrow,
+ NestedNameSpecifier *Qualifier,
+ DeclarationName Member,
+ unsigned Arity) {
+ Out << (IsArrow ? "pt" : "me");
+ mangleExpression(Base);
+ mangleUnresolvedName(Qualifier, Member, Arity);
+}
+
void CXXNameMangler::mangleExpression(const Expr *E) {
// <expression> ::= <unary operator-name> <expression>
- // ::= <binary operator-name> <expression> <expression>
- // ::= <trinary operator-name> <expression> <expression> <expression>
- // ::= cl <expression>* E # call
+ // ::= <binary operator-name> <expression> <expression>
+ // ::= <trinary operator-name> <expression> <expression> <expression>
+ // ::= cl <expression>* E # call
// ::= cv <type> expression # conversion with one argument
// ::= cv <type> _ <expression>* E # conversion with a different number of arguments
- // ::= st <type> # sizeof (a type)
+ // ::= st <type> # sizeof (a type)
// ::= at <type> # alignof (a type)
// ::= <template-param>
// ::= <function-param>
// ::= sr <type> <unqualified-name> # dependent name
// ::= sr <type> <unqualified-name> <template-args> # dependent template-id
// ::= sZ <template-param> # size of a parameter pack
- // ::= <expr-primary>
+ // ::= <expr-primary>
+ // <expr-primary> ::= L <type> <value number> E # integer literal
+ // ::= L <type <value float> E # floating literal
+ // ::= L <mangled-name> E # external name
switch (E->getStmtClass()) {
- default: assert(false && "Unhandled expression kind!");
+ default:
+ llvm_unreachable("unexpected statement kind");
+ break;
+
+ case Expr::CallExprClass: {
+ const CallExpr *CE = cast<CallExpr>(E);
+ Out << "cl";
+ mangleCalledExpression(CE->getCallee(), CE->getNumArgs());
+ for (unsigned I = 0, N = CE->getNumArgs(); I != N; ++I)
+ mangleExpression(CE->getArg(I));
+ Out << "E";
+ break;
+ }
+
+ case Expr::MemberExprClass: {
+ const MemberExpr *ME = cast<MemberExpr>(E);
+ mangleMemberExpr(ME->getBase(), ME->isArrow(),
+ ME->getQualifier(), ME->getMemberDecl()->getDeclName(),
+ UnknownArity);
+ break;
+ }
+
+ case Expr::UnresolvedMemberExprClass: {
+ const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E);
+ mangleMemberExpr(ME->getBase(), ME->isArrow(),
+ ME->getQualifier(), ME->getMemberName(),
+ UnknownArity);
+ break;
+ }
+
+ case Expr::CXXDependentScopeMemberExprClass: {
+ const CXXDependentScopeMemberExpr *ME
+ = cast<CXXDependentScopeMemberExpr>(E);
+ mangleMemberExpr(ME->getBase(), ME->isArrow(),
+ ME->getQualifier(), ME->getMember(),
+ UnknownArity);
+ break;
+ }
+
+ case Expr::UnresolvedLookupExprClass: {
+ // The ABI doesn't cover how to mangle overload sets, so we mangle
+ // using something as close as possible to the original lookup
+ // expression.
+ const UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(E);
+ mangleUnresolvedName(ULE->getQualifier(), ULE->getName(), UnknownArity);
+ break;
+ }
+
+ case Expr::CXXUnresolvedConstructExprClass: {
+ const CXXUnresolvedConstructExpr *CE = cast<CXXUnresolvedConstructExpr>(E);
+ unsigned N = CE->arg_size();
+
+ Out << "cv";
+ mangleType(CE->getType());
+ if (N != 1) Out << "_";
+ for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I));
+ if (N != 1) Out << "E";
+ break;
+ }
+
+ case Expr::CXXTemporaryObjectExprClass:
+ case Expr::CXXConstructExprClass: {
+ const CXXConstructExpr *CE = cast<CXXConstructExpr>(E);
+ unsigned N = CE->getNumArgs();
+
+ Out << "cv";
+ mangleType(CE->getType());
+ if (N != 1) Out << "_";
+ for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I));
+ if (N != 1) Out << "E";
+ break;
+ }
+
+ case Expr::SizeOfAlignOfExprClass: {
+ const SizeOfAlignOfExpr *SAE = cast<SizeOfAlignOfExpr>(E);
+ if (SAE->isSizeOf()) Out << "s";
+ else Out << "a";
+ if (SAE->isArgumentType()) {
+ Out << "t";
+ mangleType(SAE->getArgumentType());
+ } else {
+ Out << "z";
+ mangleExpression(SAE->getArgumentExpr());
+ }
+ break;
+ }
case Expr::UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(E);
@@ -1082,7 +1302,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
mangleExpression(BO->getLHS());
mangleExpression(BO->getRHS());
break;
- }
+ }
case Expr::ConditionalOperatorClass: {
const ConditionalOperator *CO = cast<ConditionalOperator>(E);
@@ -1093,6 +1313,24 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
break;
}
+ case Expr::ImplicitCastExprClass: {
+ mangleExpression(cast<ImplicitCastExpr>(E)->getSubExpr());
+ break;
+ }
+
+ case Expr::CStyleCastExprClass:
+ case Expr::CXXStaticCastExprClass:
+ case Expr::CXXDynamicCastExprClass:
+ case Expr::CXXReinterpretCastExprClass:
+ case Expr::CXXConstCastExprClass:
+ case Expr::CXXFunctionalCastExprClass: {
+ const ExplicitCastExpr *ECE = cast<ExplicitCastExpr>(E);
+ Out << "cv";
+ mangleType(ECE->getType());
+ mangleExpression(ECE->getSubExpr());
+ break;
+ }
+
case Expr::CXXOperatorCallExprClass: {
const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E);
unsigned NumArgs = CE->getNumArgs();
@@ -1139,6 +1377,20 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
break;
}
+ case Expr::FloatingLiteralClass: {
+ const FloatingLiteral *FL = cast<FloatingLiteral>(E);
+ Out << "L";
+ mangleType(FL->getType());
+
+ // TODO: avoid this copy with careful stream management.
+ llvm::SmallVector<char,20> Buffer;
+ FL->getValue().bitcastToAPInt().toString(Buffer, 16, false);
+ Out.write(Buffer.data(), Buffer.size());
+
+ Out << "E";
+ break;
+ }
+
case Expr::IntegerLiteralClass:
mangleIntegerLiteral(E->getType(),
llvm::APSInt(cast<IntegerLiteral>(E)->getValue()));
@@ -1216,6 +1468,8 @@ void CXXNameMangler::mangleTemplateArg(const TemplateArgument &A) {
mangleType(A.getAsType());
break;
case TemplateArgument::Template:
+ assert(A.getAsTemplate().getAsTemplateDecl() &&
+ "FIXME: Support dependent template names");
mangleName(A.getAsTemplate().getAsTemplateDecl());
break;
case TemplateArgument::Expression:
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 4454662a9304..a7c0caa299e7 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -271,6 +271,10 @@ ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty,
if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
return ABIArgInfo::getIndirect(0);
} else {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
return (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
@@ -321,6 +325,9 @@ class X86_32TargetCodeGenInfo : public TargetCodeGenInfo {
public:
X86_32TargetCodeGenInfo(ASTContext &Context, bool d, bool p)
:TargetCodeGenInfo(new X86_32ABIInfo(Context, d, p)) {}
+
+ void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &CGM) const;
};
}
@@ -358,6 +365,8 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
const RecordType *RT = Ty->getAs<RecordType>();
if (!RT) return false;
+ // FIXME: Traverse bases here too.
+
// Structure types are passed in register if all fields would be
// passed in a register.
for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(),
@@ -404,7 +413,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
return ABIArgInfo::getDirect();
} else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
- if (const RecordType *RT = RetTy->getAsStructureType()) {
+ if (const RecordType *RT = RetTy->getAs<RecordType>()) {
// Structures with either a non-trivial destructor or a non-trivial
// copy constructor are always indirect.
if (hasNonTrivialDestructorOrCopyConstructor(RT))
@@ -463,6 +472,10 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
return ABIArgInfo::getIndirect(0);
} else {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
+ RetTy = EnumTy->getDecl()->getIntegerType();
+
return (RetTy->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
@@ -484,10 +497,16 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
// FIXME: Set alignment on indirect arguments.
if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
// Structures with flexible arrays are always indirect.
- if (const RecordType *RT = Ty->getAsStructureType())
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ // Structures with either a non-trivial destructor or a non-trivial
+ // copy constructor are always indirect.
+ if (hasNonTrivialDestructorOrCopyConstructor(RT))
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+
if (RT->getDecl()->hasFlexibleArrayMember())
return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty,
Context));
+ }
// Ignore empty structs.
if (Ty->isStructureType() && Context.getTypeSize(Ty) == 0)
@@ -503,6 +522,9 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, Context));
} else {
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
return (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
@@ -532,6 +554,20 @@ llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
return AddrTyped;
}
+void X86_32TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
+ llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &CGM) const {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->hasAttr<X86ForceAlignArgPointerAttr>()) {
+ // Get the LLVM function.
+ llvm::Function *Fn = cast<llvm::Function>(GV);
+
+ // Now add the 'alignstack' attribute with a value of 16.
+ Fn->addFnAttr(llvm::Attribute::constructStackAlignmentFromInt(16));
+ }
+ }
+}
+
namespace {
/// X86_64ABIInfo - The X86_64 ABI information.
class X86_64ABIInfo : public ABIInfo {
@@ -927,6 +963,11 @@ ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty,
if (CoerceTo == llvm::Type::getInt64Ty(CoerceTo->getContext())) {
// Integer and pointer types will end up in a general purpose
// register.
+
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
if (Ty->isIntegralType() || Ty->hasPointerRepresentation())
return (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
@@ -948,9 +989,14 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty,
ASTContext &Context) const {
// If this is a scalar LLVM value then assume LLVM will pass it in the right
// place naturally.
- if (!CodeGenFunction::hasAggregateLLVMType(Ty))
+ if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
return (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
bool ByVal = !isRecordWithNonTrivialDestructorOrCopyConstructor(Ty);
@@ -1319,14 +1365,14 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs");
const llvm::Type *TyLo = ST->getElementType(0);
const llvm::Type *TyHi = ST->getElementType(1);
- assert((TyLo->isFloatingPoint() ^ TyHi->isFloatingPoint()) &&
+ assert((TyLo->isFloatingPointTy() ^ TyHi->isFloatingPointTy()) &&
"Unexpected ABI info for mixed regs");
const llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo);
const llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi);
llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset);
llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset);
- llvm::Value *RegLoAddr = TyLo->isFloatingPoint() ? FPAddr : GPAddr;
- llvm::Value *RegHiAddr = TyLo->isFloatingPoint() ? GPAddr : FPAddr;
+ llvm::Value *RegLoAddr = TyLo->isFloatingPointTy() ? FPAddr : GPAddr;
+ llvm::Value *RegHiAddr = TyLo->isFloatingPointTy() ? GPAddr : FPAddr;
llvm::Value *V =
CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegLoAddr, PTyLo));
CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0));
@@ -1526,9 +1572,14 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context,
ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty,
ASTContext &Context,
llvm::LLVMContext &VMContext) const {
- if (!CodeGenFunction::hasAggregateLLVMType(Ty))
+ if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
return (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
// Ignore empty records.
if (isEmptyRecord(Context, Ty, true))
@@ -1577,9 +1628,9 @@ static bool isIntegerLikeType(QualType Ty,
if (Ty->getAs<BuiltinType>() || Ty->isPointerType())
return true;
- // Complex types "should" be ok by the definition above, but they are not.
- if (Ty->isAnyComplexType())
- return false;
+ // Small complex integer types are "integer like".
+ if (const ComplexType *CT = Ty->getAs<ComplexType>())
+ return isIntegerLikeType(CT->getElementType(), Context, VMContext);
// Single element and zero sized arrays should be allowed, by the definition
// above, but they are not.
@@ -1603,30 +1654,30 @@ static bool isIntegerLikeType(QualType Ty,
i != e; ++i, ++idx) {
const FieldDecl *FD = *i;
- // Check if this field is at offset 0.
- uint64_t Offset = Layout.getFieldOffset(idx);
- if (Offset != 0) {
- // Allow padding bit-fields, but only if they are all at the end of the
- // structure (despite the wording above, this matches gcc).
- if (FD->isBitField() &&
- !FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) {
- for (; i != e; ++i)
- if (!i->isBitField() ||
- i->getBitWidth()->EvaluateAsInt(Context).getZExtValue())
- return false;
-
- // All remaining fields are padding, allow this.
- return true;
- }
+ // Bit-fields are not addressable, we only need to verify they are "integer
+ // like". We still have to disallow a subsequent non-bitfield, for example:
+ // struct { int : 0; int x }
+ // is non-integer like according to gcc.
+ if (FD->isBitField()) {
+ if (!RD->isUnion())
+ HadField = true;
- return false;
+ if (!isIntegerLikeType(FD->getType(), Context, VMContext))
+ return false;
+
+ continue;
}
+ // Check if this field is at offset 0.
+ if (Layout.getFieldOffset(idx) != 0)
+ return false;
+
if (!isIntegerLikeType(FD->getType(), Context, VMContext))
return false;
- // Only allow at most one field in a structure. Again this doesn't match the
- // wording above, but follows gcc.
+ // Only allow at most one field in a structure. This doesn't match the
+ // wording above, but follows gcc in situations with a field following an
+ // empty structure.
if (!RD->isUnion()) {
if (HadField)
return false;
@@ -1644,15 +1695,28 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy,
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
- if (!CodeGenFunction::hasAggregateLLVMType(RetTy))
+ if (!CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
+ RetTy = EnumTy->getDecl()->getIntegerType();
+
return (RetTy->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
// Are we following APCS?
if (getABIKind() == APCS) {
if (isEmptyRecord(Context, RetTy, false))
return ABIArgInfo::getIgnore();
+ // Complex types are all returned as packed integers.
+ //
+ // FIXME: Consider using 2 x vector types if the back end handles them
+ // correctly.
+ if (RetTy->isAnyComplexType())
+ return ABIArgInfo::getCoerce(llvm::IntegerType::get(
+ VMContext, Context.getTypeSize(RetTy)));
+
// Integer like structures are returned in r0.
if (isIntegerLikeType(RetTy, Context, VMContext)) {
// Return in the smallest viable integer type.
@@ -1721,6 +1785,10 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy,
} else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
return ABIArgInfo::getIndirect(0);
} else {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
+ RetTy = EnumTy->getDecl()->getIntegerType();
+
return (RetTy->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 852a018e10f4..15df767d9707 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -50,8 +50,8 @@ Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir,
Name(_Name), Dir(_Dir), DefaultHostTriple(_DefaultHostTriple),
DefaultImageName(_DefaultImageName),
Host(0),
- CCCIsCXX(false), CCCEcho(false), CCCPrintBindings(false),
- CCCGenericGCCName("gcc"), CCCUseClang(true),
+ CCCGenericGCCName("gcc"), CCCIsCXX(false), CCCEcho(false),
+ CCCPrintBindings(false), CheckInputsExist(true), CCCUseClang(true),
CCCUseClangCXX(true), CCCUseClangCPP(true), CCCUsePCH(true),
SuppressMissingInputWarning(false) {
if (IsProduction) {
@@ -158,10 +158,8 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) {
llvm::Triple::ArchType Arch =
llvm::Triple(Split.first, "", "").getArch();
- if (Arch == llvm::Triple::UnknownArch) {
- Diag(clang::diag::err_drv_invalid_arch_name) << Arch;
- continue;
- }
+ if (Arch == llvm::Triple::UnknownArch)
+ Diag(clang::diag::err_drv_invalid_arch_name) << Split.first;
CCCClangArchs.insert(Arch);
}
@@ -579,10 +577,9 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const {
Ty = InputType;
}
- // Check that the file exists. It isn't clear this is worth doing, since
- // the tool presumably does this anyway, and this just adds an extra stat
- // to the equation, but this is gcc compatible.
- if (memcmp(Value, "-", 2) != 0 && !llvm::sys::Path(Value).exists())
+ // Check that the file exists, if enabled.
+ if (CheckInputsExist && memcmp(Value, "-", 2) != 0 &&
+ !llvm::sys::Path(Value).exists())
Diag(clang::diag::err_drv_no_such_file) << A->getValue(Args);
else
Inputs.push_back(std::make_pair(Ty, A));
@@ -625,6 +622,7 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const {
// -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler.
} else if ((FinalPhaseArg = Args.getLastArg(options::OPT_fsyntax_only)) ||
+ (FinalPhaseArg = Args.getLastArg(options::OPT_rewrite_objc)) ||
(FinalPhaseArg = Args.getLastArg(options::OPT__analyze,
options::OPT__analyze_auto)) ||
(FinalPhaseArg = Args.getLastArg(options::OPT_emit_ast)) ||
@@ -745,6 +743,8 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
if (Args.hasArg(options::OPT_fsyntax_only)) {
return new CompileJobAction(Input, types::TY_Nothing);
+ } else if (Args.hasArg(options::OPT_rewrite_objc)) {
+ return new CompileJobAction(Input, types::TY_RewrittenObjC);
} else if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto)) {
return new AnalyzeJobAction(Input, types::TY_Plist);
} else if (Args.hasArg(options::OPT_emit_ast)) {
@@ -866,6 +866,44 @@ void Driver::BuildJobs(Compilation &C) const {
}
}
+static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC,
+ const JobAction *JA,
+ const ActionList *&Inputs) {
+ const Tool *ToolForJob = 0;
+
+ // See if we should look for a compiler with an integrated assembler. We match
+ // bottom up, so what we are actually looking for is an assembler job with a
+ // compiler input.
+ if (C.getArgs().hasArg(options::OPT_integrated_as,
+ options::OPT_no_integrated_as,
+ TC->IsIntegratedAssemblerDefault()) &&
+ !C.getArgs().hasArg(options::OPT_save_temps) &&
+ isa<AssembleJobAction>(JA) &&
+ Inputs->size() == 1 && isa<CompileJobAction>(*Inputs->begin())) {
+ const Tool &Compiler = TC->SelectTool(C,cast<JobAction>(**Inputs->begin()));
+ if (Compiler.hasIntegratedAssembler()) {
+ Inputs = &(*Inputs)[0]->getInputs();
+ ToolForJob = &Compiler;
+ }
+ }
+
+ // Otherwise use the tool for the current job.
+ if (!ToolForJob)
+ ToolForJob = &TC->SelectTool(C, *JA);
+
+ // See if we should use an integrated preprocessor. We do so when we have
+ // exactly one input, since this is the only use case we care about
+ // (irrelevant since we don't support combine yet).
+ if (Inputs->size() == 1 && isa<PreprocessJobAction>(*Inputs->begin()) &&
+ !C.getArgs().hasArg(options::OPT_no_integrated_cpp) &&
+ !C.getArgs().hasArg(options::OPT_traditional_cpp) &&
+ !C.getArgs().hasArg(options::OPT_save_temps) &&
+ ToolForJob->hasIntegratedCPP())
+ Inputs = &(*Inputs)[0]->getInputs();
+
+ return *ToolForJob;
+}
+
void Driver::BuildJobsForAction(Compilation &C,
const Action *A,
const ToolChain *TC,
@@ -906,21 +944,10 @@ void Driver::BuildJobsForAction(Compilation &C,
return;
}
- const JobAction *JA = cast<JobAction>(A);
- const Tool &T = TC->SelectTool(C, *JA);
-
- // See if we should use an integrated preprocessor. We do so when we have
- // exactly one input, since this is the only use case we care about
- // (irrelevant since we don't support combine yet).
const ActionList *Inputs = &A->getInputs();
- if (Inputs->size() == 1 && isa<PreprocessJobAction>(*Inputs->begin())) {
- if (!C.getArgs().hasArg(options::OPT_no_integrated_cpp) &&
- !C.getArgs().hasArg(options::OPT_traditional_cpp) &&
- !C.getArgs().hasArg(options::OPT_save_temps) &&
- T.hasIntegratedCPP()) {
- Inputs = &(*Inputs)[0]->getInputs();
- }
- }
+
+ const JobAction *JA = cast<JobAction>(A);
+ const Tool &T = SelectToolForJob(C, TC, JA, Inputs);
// Only use pipes when there is exactly one input.
bool TryToUsePipeInput = Inputs->size() == 1 && T.acceptsPipedInput();
@@ -1147,8 +1174,10 @@ bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA,
return false;
}
- // Always use clang for precompiling and AST generation, regardless of archs.
- if (isa<PrecompileJobAction>(JA) || JA.getType() == types::TY_AST)
+ // Always use clang for precompiling, AST generation, and rewriting,
+ // regardless of archs.
+ if (isa<PrecompileJobAction>(JA) || JA.getType() == types::TY_AST ||
+ JA.getType() == types::TY_RewrittenObjC)
return true;
// Finally, don't use clang if this isn't one of the user specified archs to
diff --git a/lib/Driver/HostInfo.cpp b/lib/Driver/HostInfo.cpp
index ed73b17d75f1..18bb78659305 100644
--- a/lib/Driver/HostInfo.cpp
+++ b/lib/Driver/HostInfo.cpp
@@ -106,7 +106,7 @@ ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args,
if (Arg *A = Args.getLastArg(options::OPT_arch)) {
// The gcc driver behavior with multiple -arch flags wasn't consistent for
// things which rely on a default architecture. We just use the last -arch
- // to find the default tool chain (assuming it is valid..
+ // to find the default tool chain (assuming it is valid).
Arch = llvm::Triple::getArchTypeForDarwinArchName(A->getValue(Args));
// If it was invalid just use the host, we will reject this command line
@@ -146,10 +146,10 @@ ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args,
// If we recognized the arch, match it to the toolchains we support.
if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
// We still use the legacy DarwinGCC toolchain on X86.
- TC = new toolchains::DarwinGCC(*this, TCTriple, DarwinVersion, GCCVersion,
- false);
+ TC = new toolchains::DarwinGCC(*this, TCTriple, DarwinVersion,
+ GCCVersion);
} else if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)
- TC = new toolchains::DarwinClang(*this, TCTriple, DarwinVersion, true);
+ TC = new toolchains::DarwinClang(*this, TCTriple, DarwinVersion);
else
TC = new toolchains::Darwin_Generic_GCC(*this, TCTriple);
}
@@ -159,8 +159,7 @@ ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args,
// Unknown Host Info
-/// UnknownHostInfo - Generic host information to use for unknown
-/// hosts.
+/// UnknownHostInfo - Generic host information to use for unknown hosts.
class UnknownHostInfo : public HostInfo {
/// Cache of tool chains we have created.
mutable llvm::StringMap<ToolChain*> ToolChains;
diff --git a/lib/Driver/Makefile b/lib/Driver/Makefile
index dbacf8be0141..371bda781c67 100644
--- a/lib/Driver/Makefile
+++ b/lib/Driver/Makefile
@@ -10,7 +10,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangDriver
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index a9c6a68ceb8a..a7cd711df1bc 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -31,20 +31,12 @@ using namespace clang::driver::toolchains;
/// Darwin - Darwin tool chain for i386 and x86_64.
Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple,
- const unsigned (&_DarwinVersion)[3], bool _IsIPhoneOS)
- : ToolChain(Host, Triple),
- IsIPhoneOS(_IsIPhoneOS)
+ const unsigned (&_DarwinVersion)[3])
+ : ToolChain(Host, Triple), TargetInitialized(false)
{
- DarwinVersion[0] = _DarwinVersion[0];
- DarwinVersion[1] = _DarwinVersion[1];
- DarwinVersion[2] = _DarwinVersion[2];
-
llvm::raw_string_ostream(MacosxVersionMin)
- << "10." << std::max(0, (int)DarwinVersion[0] - 4) << '.'
- << DarwinVersion[1];
-
- // FIXME: Lift default up.
- IPhoneOSVersionMin = "3.0";
+ << "10." << std::max(0, (int)_DarwinVersion[0] - 4) << '.'
+ << _DarwinVersion[1];
}
// FIXME: Can we tablegen this?
@@ -112,8 +104,8 @@ llvm::StringRef Darwin::getDarwinArchName(const ArgList &Args) const {
DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple,
const unsigned (&DarwinVersion)[3],
- const unsigned (&_GCCVersion)[3], bool IsIPhoneOS)
- : Darwin(Host, Triple, DarwinVersion, IsIPhoneOS)
+ const unsigned (&_GCCVersion)[3])
+ : Darwin(Host, Triple, DarwinVersion)
{
GCCVersion[0] = _GCCVersion[0];
GCCVersion[1] = _GCCVersion[1];
@@ -245,8 +237,7 @@ void DarwinGCC::AddLinkSearchPathArgs(const ArgList &Args,
void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
- unsigned MacosxVersionMin[3];
- getMacosxVersionMin(Args, MacosxVersionMin);
+ // Note that this routine is only used for targetting OS X.
// Derived from libgcc and lib specs but refactored.
if (Args.hasArg(options::OPT_static)) {
@@ -256,7 +247,7 @@ void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args,
CmdArgs.push_back("-lgcc_eh");
} else if (Args.hasArg(options::OPT_miphoneos_version_min_EQ)) {
// Derived from darwin_iphoneos_libgcc spec.
- if (isIPhoneOS()) {
+ if (isTargetIPhoneOS()) {
CmdArgs.push_back("-lgcc_s.1");
} else {
CmdArgs.push_back("-lgcc_s.10.5");
@@ -266,20 +257,20 @@ void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args,
options::OPT_fno_exceptions) ||
Args.hasArg(options::OPT_fgnu_runtime)) {
// FIXME: This is probably broken on 10.3?
- if (isMacosxVersionLT(MacosxVersionMin, 10, 5))
+ if (isMacosxVersionLT(10, 5))
CmdArgs.push_back("-lgcc_s.10.4");
- else if (isMacosxVersionLT(MacosxVersionMin, 10, 6))
+ else if (isMacosxVersionLT(10, 6))
CmdArgs.push_back("-lgcc_s.10.5");
} else {
- if (isMacosxVersionLT(MacosxVersionMin, 10, 3, 9))
+ if (isMacosxVersionLT(10, 3, 9))
; // Do nothing.
- else if (isMacosxVersionLT(MacosxVersionMin, 10, 5))
+ else if (isMacosxVersionLT(10, 5))
CmdArgs.push_back("-lgcc_s.10.4");
- else if (isMacosxVersionLT(MacosxVersionMin, 10, 6))
+ else if (isMacosxVersionLT(10, 6))
CmdArgs.push_back("-lgcc_s.10.5");
}
- if (isIPhoneOS() || isMacosxVersionLT(MacosxVersionMin, 10, 6)) {
+ if (isTargetIPhoneOS() || isMacosxVersionLT(10, 6)) {
CmdArgs.push_back("-lgcc");
CmdArgs.push_back("-lSystem");
} else {
@@ -290,9 +281,8 @@ void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args,
}
DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple,
- const unsigned (&DarwinVersion)[3],
- bool IsIPhoneOS)
- : Darwin(Host, Triple, DarwinVersion, IsIPhoneOS)
+ const unsigned (&DarwinVersion)[3])
+ : Darwin(Host, Triple, DarwinVersion)
{
// We expect 'as', 'ld', etc. to be adjacent to our install dir.
getProgramPaths().push_back(getDriver().Dir);
@@ -325,7 +315,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
// Select the dynamic runtime library and the target specific static library.
const char *DarwinStaticLib = 0;
- if (isIPhoneOS()) {
+ if (isTargetIPhoneOS()) {
CmdArgs.push_back("-lgcc_s.1");
// We may need some static functions for armv6/thumb which are required to
@@ -333,20 +323,17 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
if (getDarwinArchName(Args) == "armv6")
DarwinStaticLib = "libclang_rt.armv6.a";
} else {
- unsigned MacosxVersionMin[3];
- getMacosxVersionMin(Args, MacosxVersionMin);
-
// The dynamic runtime library was merged with libSystem for 10.6 and
// beyond; only 10.4 and 10.5 need an additional runtime library.
- if (isMacosxVersionLT(MacosxVersionMin, 10, 5))
+ if (isMacosxVersionLT(10, 5))
CmdArgs.push_back("-lgcc_s.10.4");
- else if (isMacosxVersionLT(MacosxVersionMin, 10, 6))
+ else if (isMacosxVersionLT(10, 6))
CmdArgs.push_back("-lgcc_s.10.5");
// For OS X, we only need a static runtime library when targetting 10.4, to
// provide versions of the static functions which were omitted from
// 10.4.dylib.
- if (isMacosxVersionLT(MacosxVersionMin, 10, 5))
+ if (isMacosxVersionLT(10, 5))
DarwinStaticLib = "libclang_rt.10.4.a";
}
@@ -367,21 +354,6 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
}
}
-void Darwin::getMacosxVersionMin(const ArgList &Args,
- unsigned (&Res)[3]) const {
- if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ)) {
- bool HadExtra;
- if (!Driver::GetReleaseVersion(A->getValue(Args), Res[0], Res[1], Res[2],
- HadExtra) ||
- HadExtra) {
- const Driver &D = getDriver();
- D.Diag(clang::diag::err_drv_invalid_version_number)
- << A->getAsString(Args);
- }
- } else
- return getMacosxVersion(Res);
-}
-
DerivedArgList *Darwin::TranslateArgs(InputArgList &Args,
const char *BoundArch) const {
DerivedArgList *DAL = new DerivedArgList(Args, false);
@@ -394,34 +366,84 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args,
// have something that works, we should reevaluate each translation
// and try to push it down into tool specific logic.
- Arg *OSXVersion =
- Args.getLastArgNoClaim(options::OPT_mmacosx_version_min_EQ);
- Arg *iPhoneVersion =
- Args.getLastArgNoClaim(options::OPT_miphoneos_version_min_EQ);
+ Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ);
+ Arg *iPhoneVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ);
if (OSXVersion && iPhoneVersion) {
getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with)
<< OSXVersion->getAsString(Args)
<< iPhoneVersion->getAsString(Args);
+ iPhoneVersion = 0;
} else if (!OSXVersion && !iPhoneVersion) {
- // Chose the default version based on the arch.
+ // If neither OS X nor iPhoneOS targets were specified, check for
+ // environment defines.
+ const char *OSXTarget = ::getenv("MACOSX_DEPLOYMENT_TARGET");
+ const char *iPhoneOSTarget = ::getenv("IPHONEOS_DEPLOYMENT_TARGET");
+
+ // Ignore empty strings.
+ if (OSXTarget && OSXTarget[0] == '\0')
+ OSXTarget = 0;
+ if (iPhoneOSTarget && iPhoneOSTarget[0] == '\0')
+ iPhoneOSTarget = 0;
+
+ // Diagnose conflicting deployment targets, and choose default platform
+ // based on the tool chain.
//
- // FIXME: Are there iPhone overrides for this?
-
- if (!isIPhoneOS()) {
- // Look for MACOSX_DEPLOYMENT_TARGET, otherwise use the version
- // from the host.
- const char *Version = ::getenv("MACOSX_DEPLOYMENT_TARGET");
- if (!Version)
- Version = MacosxVersionMin.c_str();
+ // FIXME: Don't hardcode default here.
+ if (OSXTarget && iPhoneOSTarget) {
+ // FIXME: We should see if we can get away with warning or erroring on
+ // this. Perhaps put under -pedantic?
+ if (getTriple().getArch() == llvm::Triple::arm ||
+ getTriple().getArch() == llvm::Triple::thumb)
+ OSXVersion = 0;
+ else
+ iPhoneVersion = 0;
+ }
+
+ if (OSXTarget) {
const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
- DAL->append(DAL->MakeJoinedArg(0, O, Version));
- } else {
- const char *Version = IPhoneOSVersionMin.c_str();
+ OSXVersion = DAL->MakeJoinedArg(0, O, OSXTarget);
+ DAL->append(OSXVersion);
+ } else if (iPhoneOSTarget) {
const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ);
- DAL->append(DAL->MakeJoinedArg(0, O, Version));
+ iPhoneVersion = DAL->MakeJoinedArg(0, O, iPhoneOSTarget);
+ DAL->append(iPhoneVersion);
+ } else {
+ // Otherwise, choose a default platform based on the tool chain.
+ //
+ // FIXME: Don't hardcode default here.
+ if (getTriple().getArch() == llvm::Triple::arm ||
+ getTriple().getArch() == llvm::Triple::thumb) {
+ const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ);
+ iPhoneVersion = DAL->MakeJoinedArg(0, O, "3.0");
+ DAL->append(iPhoneVersion);
+ } else {
+ const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
+ OSXVersion = DAL->MakeJoinedArg(0, O, MacosxVersionMin);
+ DAL->append(OSXVersion);
+ }
}
}
+ // Set the tool chain target information.
+ unsigned Major, Minor, Micro;
+ bool HadExtra;
+ if (OSXVersion) {
+ assert(!iPhoneVersion && "Unknown target platform!");
+ if (!Driver::GetReleaseVersion(OSXVersion->getValue(Args), Major, Minor,
+ Micro, HadExtra) || HadExtra ||
+ Major != 10 || Minor >= 10 || Micro >= 10)
+ getDriver().Diag(clang::diag::err_drv_invalid_version_number)
+ << OSXVersion->getAsString(Args);
+ } else {
+ assert(iPhoneVersion && "Unknown target platform!");
+ if (!Driver::GetReleaseVersion(iPhoneVersion->getValue(Args), Major, Minor,
+ Micro, HadExtra) || HadExtra ||
+ Major >= 10 || Minor >= 100 || Micro >= 100)
+ getDriver().Diag(clang::diag::err_drv_invalid_version_number)
+ << iPhoneVersion->getAsString(Args);
+ }
+ setTarget(iPhoneVersion, Major, Minor, Micro);
+
for (ArgList::iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) {
Arg *A = *it;
@@ -618,6 +640,12 @@ bool Darwin::UseDwarfDebugFlags() const {
return false;
}
+bool Darwin::UseSjLjExceptions() const {
+ // Darwin uses SjLj exceptions on ARM.
+ return (getTriple().getArch() == llvm::Triple::arm ||
+ getTriple().getArch() == llvm::Triple::thumb);
+}
+
const char *Darwin::GetDefaultRelocationModel() const {
return "pic";
}
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 3ca6ad88972c..fda08758c9bc 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -47,42 +47,60 @@ public:
class VISIBILITY_HIDDEN Darwin : public ToolChain {
mutable llvm::DenseMap<unsigned, Tool*> Tools;
- /// Darwin version of tool chain.
- unsigned DarwinVersion[3];
-
- /// Whether this is this an iPhoneOS toolchain.
+ /// Whether the information on the target has been initialized.
//
- // FIXME: This should go away, such differences should be completely
- // determined by the target triple.
- bool IsIPhoneOS;
+ // FIXME: This should be eliminated. What we want to do is make this part of
+ // the "default target for arguments" selection process, once we get out of
+ // the argument translation business.
+ mutable bool TargetInitialized;
+
+ /// Whether we are targetting iPhoneOS target.
+ mutable bool TargetIsIPhoneOS;
+
+ /// The OS version we are targetting.
+ mutable unsigned TargetVersion[3];
/// The default macosx-version-min of this tool chain; empty until
/// initialized.
- mutable std::string MacosxVersionMin;
-
- /// The default iphoneos-version-min of this tool chain.
- std::string IPhoneOSVersionMin;
-
- const char *getMacosxVersionMin() const;
+ std::string MacosxVersionMin;
public:
Darwin(const HostInfo &Host, const llvm::Triple& Triple,
- const unsigned (&DarwinVersion)[3], bool IsIPhoneOS);
+ const unsigned (&DarwinVersion)[3]);
~Darwin();
/// @name Darwin Specific Toolchain API
/// {
- void getDarwinVersion(unsigned (&Res)[3]) const {
- Res[0] = DarwinVersion[0];
- Res[1] = DarwinVersion[1];
- Res[2] = DarwinVersion[2];
+ // FIXME: Eliminate these ...Target functions and derive separate tool chains
+ // for these targets and put version in constructor.
+ void setTarget(bool isIPhoneOS, unsigned Major, unsigned Minor,
+ unsigned Micro) const {
+ // FIXME: For now, allow reinitialization as long as values don't
+ // change. This will go away when we move away from argument translation.
+ if (TargetInitialized && TargetIsIPhoneOS == isIPhoneOS &&
+ TargetVersion[0] == Major && TargetVersion[1] == Minor &&
+ TargetVersion[2] == Micro)
+ return;
+
+ assert(!TargetInitialized && "Target already initialized!");
+ TargetInitialized = true;
+ TargetIsIPhoneOS = isIPhoneOS;
+ TargetVersion[0] = Major;
+ TargetVersion[1] = Minor;
+ TargetVersion[2] = Micro;
}
- void getMacosxVersion(unsigned (&Res)[3]) const {
- Res[0] = 10;
- Res[1] = DarwinVersion[0] - 4;
- Res[2] = DarwinVersion[1];
+ bool isTargetIPhoneOS() const {
+ assert(TargetInitialized && "Target not initialized!");
+ return TargetIsIPhoneOS;
+ }
+
+ void getTargetVersion(unsigned (&Res)[3]) const {
+ assert(TargetInitialized && "Target not initialized!");
+ Res[0] = TargetVersion[0];
+ Res[1] = TargetVersion[1];
+ Res[2] = TargetVersion[2];
}
/// getDarwinArchName - Get the "Darwin" arch name for a particular compiler
@@ -90,11 +108,7 @@ public:
/// distinct architectures.
llvm::StringRef getDarwinArchName(const ArgList &Args) const;
- /// getMacosxVersionMin - Get the effective -mmacosx-version-min, which is
- /// either the -mmacosx-version-min, or the current version if unspecified.
- void getMacosxVersionMin(const ArgList &Args, unsigned (&Res)[3]) const;
-
- static bool isMacosxVersionLT(unsigned (&A)[3], unsigned (&B)[3]) {
+ static bool isVersionLT(unsigned (&A)[3], unsigned (&B)[3]) {
for (unsigned i=0; i < 3; ++i) {
if (A[i] > B[i]) return false;
if (A[i] < B[i]) return true;
@@ -102,18 +116,16 @@ public:
return false;
}
- static bool isMacosxVersionLT(unsigned (&A)[3],
- unsigned V0, unsigned V1=0, unsigned V2=0) {
+ bool isIPhoneOSVersionLT(unsigned V0, unsigned V1=0, unsigned V2=0) const {
+ assert(isTargetIPhoneOS() && "Unexpected call for OS X target!");
unsigned B[3] = { V0, V1, V2 };
- return isMacosxVersionLT(A, B);
+ return isVersionLT(TargetVersion, B);
}
- const char *getMacosxVersionStr() const {
- return MacosxVersionMin.c_str();
- }
-
- const char *getIPhoneOSVersionStr() const {
- return IPhoneOSVersionMin.c_str();
+ bool isMacosxVersionLT(unsigned V0, unsigned V1=0, unsigned V2=0) const {
+ assert(!isTargetIPhoneOS() && "Unexpected call for iPhoneOS target!");
+ unsigned B[3] = { V0, V1, V2 };
+ return isVersionLT(TargetVersion, B);
}
/// AddLinkSearchPathArgs - Add the linker search paths to \arg CmdArgs.
@@ -129,8 +141,6 @@ public:
virtual void AddLinkRuntimeLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const = 0;
- bool isIPhoneOS() const { return IsIPhoneOS; }
-
/// }
/// @name ToolChain Implementation
/// {
@@ -141,24 +151,33 @@ public:
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
virtual bool IsBlocksDefault() const {
- // Blocks default to on for 10.6 (darwin10) and beyond.
- return (DarwinVersion[0] > 9);
+ // Blocks default to on for OS X 10.6 and iPhoneOS 3.0 and beyond.
+ if (isTargetIPhoneOS())
+ return !isIPhoneOSVersionLT(3);
+ else
+ return !isMacosxVersionLT(10, 6);
}
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);
+ // Non-fragile ABI default to on for iPhoneOS and x86-64.
+ return isTargetIPhoneOS() || getTriple().getArch() == llvm::Triple::x86_64;
+ }
+ virtual bool IsObjCLegacyDispatchDefault() const {
+ // This is only used with the non-fragile ABI.
+ return (getTriple().getArch() == llvm::Triple::arm ||
+ getTriple().getArch() == llvm::Triple::thumb);
}
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;
+ // Stack protectors default to on for 10.6 and beyond.
+ return !isTargetIPhoneOS() && !isMacosxVersionLT(10, 6);
}
virtual const char *GetDefaultRelocationModel() const;
virtual const char *GetForcedPicModel() const;
virtual bool UseDwarfDebugFlags() const;
+ virtual bool UseSjLjExceptions() const;
+
/// }
};
@@ -166,7 +185,7 @@ public:
class VISIBILITY_HIDDEN DarwinClang : public Darwin {
public:
DarwinClang(const HostInfo &Host, const llvm::Triple& Triple,
- const unsigned (&DarwinVersion)[3], bool IsIPhoneOS);
+ const unsigned (&DarwinVersion)[3]);
/// @name Darwin ToolChain Implementation
/// {
@@ -190,8 +209,8 @@ class VISIBILITY_HIDDEN DarwinGCC : public Darwin {
public:
DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple,
- const unsigned (&DarwinVersion)[3], const unsigned (&GCCVersion)[3],
- bool IsIPhoneOS);
+ const unsigned (&DarwinVersion)[3],
+ const unsigned (&GCCVersion)[3]);
/// @name Darwin ToolChain Implementation
/// {
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index afb22a236767..aff70bc7ba0d 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -512,7 +512,7 @@ void Clang::AddX86TargetArgs(const ArgList &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().getOS().startswith("darwin")) {
if (getToolChain().getArchName() == "x86_64")
CPUName = "core2";
else if (getToolChain().getArchName() == "i386")
@@ -586,43 +586,35 @@ static std::string getEffectiveClangTriple(const Driver &D,
const ArgList &Args) {
llvm::Triple Triple(getLLVMTriple(TC, Args));
+ // Handle -mmacosx-version-min and -miphoneos-version-min.
if (Triple.getOS() != llvm::Triple::Darwin) {
// Diagnose use of -mmacosx-version-min and -miphoneos-version-min on
// non-Darwin.
if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ,
options::OPT_miphoneos_version_min_EQ))
D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
- return Triple.getTriple();
- }
-
- // If -mmacosx-version-min=10.3.9 is specified, change the effective triple
- // from being something like powerpc-apple-darwin9 to powerpc-apple-darwin7.
- if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ)) {
- unsigned Major, Minor, Micro;
- bool HadExtra;
- if (!Driver::GetReleaseVersion(A->getValue(Args), Major, Minor, Micro,
- HadExtra) || HadExtra ||
- Major != 10)
- D.Diag(clang::diag::err_drv_invalid_version_number)
- << A->getAsString(Args);
+ } else {
+ const toolchains::Darwin &DarwinTC(
+ reinterpret_cast<const toolchains::Darwin&>(TC));
+ unsigned Version[3];
+ DarwinTC.getTargetVersion(Version);
+
+ // Mangle the target version into the OS triple component. For historical
+ // reasons that make little sense, the version passed here is the "darwin"
+ // version, which drops the 10 and offsets by 4. See inverse code when
+ // setting the OS version preprocessor define.
+ if (!DarwinTC.isTargetIPhoneOS()) {
+ Version[0] = Version[1] + 4;
+ Version[1] = Version[2];
+ Version[2] = 0;
+ } else {
+ // Use the environment to communicate that we are targetting iPhoneOS.
+ Triple.setEnvironmentName("iphoneos");
+ }
- // Mangle the MacOS version min number into the Darwin number: e.g. 10.3.9
- // is darwin7.9.
- llvm::SmallString<16> Str;
- llvm::raw_svector_ostream(Str) << "darwin" << Minor + 4 << "." << Micro;
- Triple.setOSName(Str.str());
- } else if (Arg *A = Args.getLastArg(options::OPT_miphoneos_version_min_EQ)) {
- unsigned Major, Minor, Micro;
- bool HadExtra;
- if (!Driver::GetReleaseVersion(A->getValue(Args), Major, Minor, Micro,
- HadExtra) || HadExtra)
- D.Diag(clang::diag::err_drv_invalid_version_number)
- << A->getAsString(Args);
-
- // Mangle the iPhoneOS version number into the Darwin number: e.g. 2.0 is 2
- // -> 9.2.0.
llvm::SmallString<16> Str;
- llvm::raw_svector_ostream(Str) << "darwin9." << Major << "." << Minor;
+ llvm::raw_svector_ostream(Str) << "darwin" << Version[0]
+ << "." << Version[1] << "." << Version[2];
Triple.setOSName(Str.str());
}
@@ -659,6 +651,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-Eonly");
else
CmdArgs.push_back("-E");
+ } else if (isa<AssembleJobAction>(JA)) {
+ CmdArgs.push_back("-emit-obj");
} else if (isa<PrecompileJobAction>(JA)) {
// Use PCH if the user requested it, except for C++ (for now).
bool UsePCH = D.CCCUsePCH;
@@ -682,12 +676,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-S");
} else if (JA.getType() == types::TY_AST) {
CmdArgs.push_back("-emit-pch");
+ } else if (JA.getType() == types::TY_RewrittenObjC) {
+ CmdArgs.push_back("-rewrite-objc");
+ } else {
+ assert(JA.getType() == types::TY_PP_Asm &&
+ "Unexpected output type!");
}
}
// The make clang go fast button.
CmdArgs.push_back("-disable-free");
+ // Disable the verification pass in -asserts builds.
+#ifdef NDEBUG
+ CmdArgs.push_back("-disable-llvm-verifier");
+#endif
+
// Set the main file name, so that debug info works even with
// -save-temps.
CmdArgs.push_back("-main-file-name");
@@ -707,14 +711,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Add default argument set.
if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
- CmdArgs.push_back("-warn-dead-stores");
- CmdArgs.push_back("-warn-security-syntactic");
- CmdArgs.push_back("-checker-cfref");
+ CmdArgs.push_back("-analyzer-check-dead-stores");
+ CmdArgs.push_back("-analyzer-check-security-syntactic");
+ CmdArgs.push_back("-analyzer-check-objc-mem");
CmdArgs.push_back("-analyzer-eagerly-assume");
- CmdArgs.push_back("-warn-objc-methodsigs");
+ CmdArgs.push_back("-analyzer-check-objc-methodsigs");
// Do not enable the missing -dealloc check.
- // '-warn-objc-missing-dealloc',
- CmdArgs.push_back("-warn-objc-unused-ivars");
+ // '-analyzer-check-objc-missing-dealloc',
+ CmdArgs.push_back("-analyzer-check-objc-unused-ivars");
}
// Set the output format. The default is plist, for (lame) historical
@@ -909,8 +913,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
A->render(Args, CmdArgs);
} else {
// Honor -std-default.
- Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
- "-std=", /*Joined=*/true);
+ //
+ // FIXME: Clang doesn't correctly handle -std= when the input language
+ // doesn't match. For the time being just ignore this for C++ inputs;
+ // eventually we want to do all the standard defaulting here instead of
+ // splitting it between the driver and clang -cc1.
+ if (!types::isCXX(InputType))
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
+ "-std=", /*Joined=*/true);
Args.AddLastArg(CmdArgs, options::OPT_trigraphs);
}
@@ -1004,6 +1014,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (needsExceptions(Args, InputType, getToolChain().getTriple()))
CmdArgs.push_back("-fexceptions");
+ if (getToolChain().UseSjLjExceptions())
+ CmdArgs.push_back("-fsjlj-exceptions");
+
// -frtti is default.
if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti))
CmdArgs.push_back("-fno-rtti");
@@ -1013,6 +1026,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
isSignedCharDefault(getToolChain().getTriple())))
CmdArgs.push_back("-fno-signed-char");
+ // -fthreadsafe-static is default.
+ if (!Args.hasFlag(options::OPT_fthreadsafe_statics,
+ options::OPT_fno_threadsafe_statics))
+ CmdArgs.push_back("-fno-threadsafe-statics");
+
// -fms-extensions=0 is default.
if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
getToolChain().getTriple().getOS() == llvm::Triple::Win32))
@@ -1026,10 +1044,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fobjc-nonfragile-abi=0 is default.
if (types::isObjC(InputType)) {
if (Args.hasArg(options::OPT_fobjc_nonfragile_abi) ||
- getToolChain().IsObjCNonFragileABIDefault())
+ getToolChain().IsObjCNonFragileABIDefault()) {
CmdArgs.push_back("-fobjc-nonfragile-abi");
+
+ // -fobjc-legacy-dispatch is only relevant with the nonfragile-abi, and
+ // defaults to off.
+ if (Args.hasFlag(options::OPT_fobjc_legacy_dispatch,
+ options::OPT_fno_objc_legacy_dispatch,
+ getToolChain().IsObjCLegacyDispatchDefault()))
+ CmdArgs.push_back("-fobjc-legacy-dispatch");
+ }
}
+ if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
+ options::OPT_fno_assume_sane_operator_new))
+ CmdArgs.push_back("-fno-assume-sane-operator-new");
+
// -fshort-wchar default varies depending on platform; only
// pass if specified.
if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar)) {
@@ -1066,6 +1096,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_diagnostics_fixit_info))
CmdArgs.push_back("-fno-diagnostics-fixit-info");
+ Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_binary);
+
// Enable -fdiagnostics-show-option by default.
if (Args.hasFlag(options::OPT_fdiagnostics_show_option,
options::OPT_fno_diagnostics_show_option))
@@ -1213,7 +1245,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- RenderExtraToolArgs(CmdArgs);
+ RenderExtraToolArgs(JA, CmdArgs);
// If using a driver driver, force the arch.
const std::string &Arch = getToolChain().getArchName();
@@ -1291,23 +1323,39 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
-void gcc::Preprocess::RenderExtraToolArgs(ArgStringList &CmdArgs) const {
+void gcc::Preprocess::RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const {
CmdArgs.push_back("-E");
}
-void gcc::Precompile::RenderExtraToolArgs(ArgStringList &CmdArgs) const {
+void gcc::Precompile::RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const {
// The type is good enough.
}
-void gcc::Compile::RenderExtraToolArgs(ArgStringList &CmdArgs) const {
- CmdArgs.push_back("-S");
+void gcc::Compile::RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const {
+ const Driver &D = getToolChain().getDriver();
+
+ // If -flto, etc. are present then make sure not to force assembly output.
+ if (JA.getType() == types::TY_LLVMBC)
+ CmdArgs.push_back("-c");
+ else {
+ if (JA.getType() != types::TY_PP_Asm)
+ D.Diag(clang::diag::err_drv_invalid_gcc_output_type)
+ << getTypeName(JA.getType());
+
+ CmdArgs.push_back("-S");
+ }
}
-void gcc::Assemble::RenderExtraToolArgs(ArgStringList &CmdArgs) const {
+void gcc::Assemble::RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const {
CmdArgs.push_back("-c");
}
-void gcc::Link::RenderExtraToolArgs(ArgStringList &CmdArgs) const {
+void gcc::Link::RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const {
// The types are (hopefully) good enough.
}
@@ -1703,6 +1751,10 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
else if (Output.getType() == types::TY_AST)
D.Diag(clang::diag::err_drv_no_ast_support)
<< getToolChain().getTripleString();
+ else if (JA.getType() != types::TY_PP_Asm &&
+ JA.getType() != types::TY_PCH)
+ D.Diag(clang::diag::err_drv_invalid_gcc_output_type)
+ << getTypeName(JA.getType());
ArgStringList OutputArgs;
if (Output.getType() != types::TY_PCH) {
@@ -1798,7 +1850,7 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
// Derived from asm spec.
AddDarwinArch(Args, CmdArgs);
- if (!getDarwinToolChain().isIPhoneOS() ||
+ if (!getDarwinToolChain().isTargetIPhoneOS() ||
Args.hasArg(options::OPT_force__cpusubtype__ALL))
CmdArgs.push_back("-force_cpusubtype_ALL");
@@ -1921,7 +1973,7 @@ void darwin::Link::AddLinkArgs(const ArgList &Args,
Args.AddLastArg(CmdArgs, options::OPT_all__load);
Args.AddAllArgs(CmdArgs, options::OPT_allowable__client);
Args.AddLastArg(CmdArgs, options::OPT_bind__at__load);
- if (getDarwinToolChain().isIPhoneOS())
+ if (getDarwinToolChain().isTargetIPhoneOS())
Args.AddLastArg(CmdArgs, options::OPT_arch__errors__fatal);
Args.AddLastArg(CmdArgs, options::OPT_dead__strip);
Args.AddLastArg(CmdArgs, options::OPT_no__dead__strip__inits__and__terms);
@@ -1933,20 +1985,11 @@ void darwin::Link::AddLinkArgs(const ArgList &Args,
Args.AddAllArgs(CmdArgs, options::OPT_image__base);
Args.AddAllArgs(CmdArgs, options::OPT_init);
- if (!Args.hasArg(options::OPT_mmacosx_version_min_EQ) &&
- !Args.hasArg(options::OPT_miphoneos_version_min_EQ)) {
- // Add default version min.
- if (!getDarwinToolChain().isIPhoneOS()) {
- CmdArgs.push_back("-macosx_version_min");
- CmdArgs.push_back(getDarwinToolChain().getMacosxVersionStr());
- } else {
- CmdArgs.push_back("-iphoneos_version_min");
- CmdArgs.push_back(getDarwinToolChain().getIPhoneOSVersionStr());
- }
- }
-
- // Adding all arguments doesn't make sense here but this is what
- // gcc does.
+ // Adding all arguments doesn't make sense here but this is what gcc does. One
+ // of this should always be present thanks to argument translation.
+ assert((Args.hasArg(options::OPT_mmacosx_version_min_EQ) ||
+ Args.hasArg(options::OPT_miphoneos_version_min_EQ)) &&
+ "Missing version argument (lost in translation)?");
Args.AddAllArgsTranslated(CmdArgs, options::OPT_mmacosx_version_min_EQ,
"-macosx_version_min");
Args.AddAllArgsTranslated(CmdArgs, options::OPT_miphoneos_version_min_EQ,
@@ -1978,7 +2021,7 @@ void darwin::Link::AddLinkArgs(const ArgList &Args,
Args.AddAllArgs(CmdArgs, options::OPT_sub__umbrella);
Args.AddAllArgsTranslated(CmdArgs, options::OPT_isysroot, "-syslibroot");
- if (getDarwinToolChain().isIPhoneOS()) {
+ if (getDarwinToolChain().isTargetIPhoneOS()) {
if (!Args.hasArg(options::OPT_isysroot)) {
CmdArgs.push_back("-syslibroot");
CmdArgs.push_back("/Developer/SDKs/Extra");
@@ -2037,26 +2080,32 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
-
- unsigned MacosxVersionMin[3];
- getDarwinToolChain().getMacosxVersionMin(Args, MacosxVersionMin);
-
if (!Args.hasArg(options::OPT_A) &&
!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nostartfiles)) {
// Derived from startfile spec.
if (Args.hasArg(options::OPT_dynamiclib)) {
// Derived from darwin_dylib1 spec.
- if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 5))
- CmdArgs.push_back("-ldylib1.o");
- else if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 6))
- CmdArgs.push_back("-ldylib1.10.5.o");
+ if (getDarwinToolChain().isTargetIPhoneOS()) {
+ if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1))
+ CmdArgs.push_back("-ldylib1.o");
+ } else {
+ if (getDarwinToolChain().isMacosxVersionLT(10, 5))
+ CmdArgs.push_back("-ldylib1.o");
+ else if (getDarwinToolChain().isMacosxVersionLT(10, 6))
+ CmdArgs.push_back("-ldylib1.10.5.o");
+ }
} else {
if (Args.hasArg(options::OPT_bundle)) {
if (!Args.hasArg(options::OPT_static)) {
// Derived from darwin_bundle1 spec.
- if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 6))
- CmdArgs.push_back("-lbundle1.o");
+ if (getDarwinToolChain().isTargetIPhoneOS()) {
+ if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1))
+ CmdArgs.push_back("-lbundle1.o");
+ } else {
+ if (getDarwinToolChain().isMacosxVersionLT(10, 6))
+ CmdArgs.push_back("-lbundle1.o");
+ }
}
} else {
if (Args.hasArg(options::OPT_pg)) {
@@ -2076,26 +2125,29 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lcrt0.o");
} else {
// Derived from darwin_crt1 spec.
- if (getDarwinToolChain().isIPhoneOS()) {
- CmdArgs.push_back("-lcrt1.o");
- } else if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin,
- 10, 5))
- CmdArgs.push_back("-lcrt1.o");
- else if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin,
- 10, 6))
- CmdArgs.push_back("-lcrt1.10.5.o");
- else
- CmdArgs.push_back("-lcrt1.10.6.o");
-
- // darwin_crt2 spec is empty.
+ if (getDarwinToolChain().isTargetIPhoneOS()) {
+ if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1))
+ CmdArgs.push_back("-lcrt1.o");
+ else
+ CmdArgs.push_back("-lcrt1.3.1.o");
+ } else {
+ if (getDarwinToolChain().isMacosxVersionLT(10, 5))
+ CmdArgs.push_back("-lcrt1.o");
+ else if (getDarwinToolChain().isMacosxVersionLT(10, 6))
+ CmdArgs.push_back("-lcrt1.10.5.o");
+ else
+ CmdArgs.push_back("-lcrt1.10.6.o");
+
+ // darwin_crt2 spec is empty.
+ }
}
}
}
}
- if (Args.hasArg(options::OPT_shared_libgcc) &&
- !Args.hasArg(options::OPT_miphoneos_version_min_EQ) &&
- getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 5)) {
+ if (!getDarwinToolChain().isTargetIPhoneOS() &&
+ Args.hasArg(options::OPT_shared_libgcc) &&
+ getDarwinToolChain().isMacosxVersionLT(10, 5)) {
const char *Str =
Args.MakeArgString(getToolChain().GetFilePath(C, "crt3.o"));
CmdArgs.push_back(Str);
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index abd8cfc6d42f..db596417a9d2 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -41,6 +41,7 @@ namespace tools {
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
+ virtual bool hasIntegratedAssembler() const { return true; }
virtual bool hasIntegratedCPP() const { return true; }
virtual void ConstructJob(Compilation &C, const JobAction &JA,
@@ -66,7 +67,8 @@ namespace gcc {
/// RenderExtraToolArgs - Render any arguments necessary to force
/// the particular tool mode.
- virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const = 0;
+ virtual void RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const = 0;
};
@@ -78,7 +80,8 @@ namespace gcc {
virtual bool canPipeOutput() const { return true; }
virtual bool hasIntegratedCPP() const { return false; }
- virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const;
+ virtual void RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const;
};
class VISIBILITY_HIDDEN Precompile : public Common {
@@ -89,7 +92,8 @@ namespace gcc {
virtual bool canPipeOutput() const { return false; }
virtual bool hasIntegratedCPP() const { return true; }
- virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const;
+ virtual void RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const;
};
class VISIBILITY_HIDDEN Compile : public Common {
@@ -100,7 +104,8 @@ namespace gcc {
virtual bool canPipeOutput() const { return true; }
virtual bool hasIntegratedCPP() const { return true; }
- virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const;
+ virtual void RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const;
};
class VISIBILITY_HIDDEN Assemble : public Common {
@@ -111,7 +116,8 @@ namespace gcc {
virtual bool canPipeOutput() const { return false; }
virtual bool hasIntegratedCPP() const { return false; }
- virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const;
+ virtual void RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const;
};
class VISIBILITY_HIDDEN Link : public Common {
@@ -122,7 +128,8 @@ namespace gcc {
virtual bool canPipeOutput() const { return false; }
virtual bool hasIntegratedCPP() const { return false; }
- virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const;
+ virtual void RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const;
};
} // end namespace gcc
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 33cb94e02dc3..ebbd720ceb63 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -564,7 +564,7 @@ public:
if (RD->isInvalidDecl())
continue;
- if (!RD->getDefinition(C))
+ if (!RD->getDefinition())
continue;
// FIXME: Do we really need to hard code this?
diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp
new file mode 100644
index 000000000000..2228ea45df33
--- /dev/null
+++ b/lib/Frontend/ASTMerge.cpp
@@ -0,0 +1,103 @@
+//===-- ASTMerge.cpp - AST Merging Frontent Action --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/ASTImporter.h"
+
+using namespace clang;
+
+ASTConsumer *ASTMergeAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return AdaptedAction->CreateASTConsumer(CI, InFile);
+}
+
+bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI,
+ llvm::StringRef Filename) {
+ // FIXME: This is a hack. We need a better way to communicate the
+ // AST file, compiler instance, and file name than member variables
+ // of FrontendAction.
+ AdaptedAction->setCurrentFile(getCurrentFile(), takeCurrentASTUnit());
+ AdaptedAction->setCompilerInstance(&CI);
+ return AdaptedAction->BeginSourceFileAction(CI, Filename);
+}
+
+void ASTMergeAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ CI.getDiagnostics().getClient()->BeginSourceFile(
+ CI.getASTContext().getLangOptions());
+ CI.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
+ &CI.getASTContext());
+ for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) {
+ ASTUnit *Unit = ASTUnit::LoadFromPCHFile(ASTFiles[I], CI.getDiagnostics(),
+ false);
+ if (!Unit)
+ continue;
+
+ ASTImporter Importer(CI.getDiagnostics(),
+ CI.getASTContext(),
+ CI.getFileManager(),
+ Unit->getASTContext(),
+ Unit->getFileManager());
+
+ TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
+ for (DeclContext::decl_iterator D = TU->decls_begin(),
+ DEnd = TU->decls_end();
+ D != DEnd; ++D) {
+ // Don't re-import __va_list_tag, __builtin_va_list.
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
+ if (IdentifierInfo *II = ND->getIdentifier())
+ if (II->isStr("__va_list_tag") || II->isStr("__builtin_va_list"))
+ continue;
+
+ Importer.Import(*D);
+ }
+
+ delete Unit;
+ }
+
+ AdaptedAction->ExecuteAction();
+ CI.getDiagnostics().getClient()->EndSourceFile();
+}
+
+void ASTMergeAction::EndSourceFileAction() {
+ return AdaptedAction->EndSourceFileAction();
+}
+
+ASTMergeAction::ASTMergeAction(FrontendAction *AdaptedAction,
+ std::string *ASTFiles, unsigned NumASTFiles)
+ : AdaptedAction(AdaptedAction), ASTFiles(ASTFiles, ASTFiles + NumASTFiles) {
+ assert(AdaptedAction && "ASTMergeAction needs an action to adapt");
+}
+
+ASTMergeAction::~ASTMergeAction() {
+ delete AdaptedAction;
+}
+
+bool ASTMergeAction::usesPreprocessorOnly() const {
+ return AdaptedAction->usesPreprocessorOnly();
+}
+
+bool ASTMergeAction::usesCompleteTranslationUnit() {
+ return AdaptedAction->usesCompleteTranslationUnit();
+}
+
+bool ASTMergeAction::hasPCHSupport() const {
+ return AdaptedAction->hasPCHSupport();
+}
+
+bool ASTMergeAction::hasASTSupport() const {
+ return AdaptedAction->hasASTSupport();
+}
+
+bool ASTMergeAction::hasCodeCompletionSupport() const {
+ return AdaptedAction->hasCodeCompletionSupport();
+}
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 2fb47cbd8a85..a0c4889c1631 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -98,13 +98,12 @@ const std::string &ASTUnit::getOriginalSourceFileName() {
const std::string &ASTUnit::getPCHFileName() {
assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
- return dyn_cast<PCHReader>(Ctx->getExternalSource())->getFileName();
+ return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName();
}
ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
Diagnostic &Diags,
bool OnlyLocalDecls,
- bool UseBumpAllocator,
RemappedFile *RemappedFiles,
unsigned NumRemappedFiles) {
llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
@@ -184,7 +183,7 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
PP.getIdentifierTable(),
PP.getSelectorTable(),
PP.getBuiltinInfo(),
- /* FreeMemory = */ !UseBumpAllocator,
+ /* FreeMemory = */ false,
/* size_reserve = */0));
ASTContext &Context = *AST->Ctx.get();
@@ -230,7 +229,7 @@ public:
}
-ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI,
+ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
Diagnostic &Diags,
bool OnlyLocalDecls) {
// Create the compiler instance to use for building the AST.
@@ -238,7 +237,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI,
llvm::OwningPtr<ASTUnit> AST;
llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
- Clang.getInvocation() = CI;
+ Clang.setInvocation(CI);
Clang.setDiagnostics(&Diags);
Clang.setDiagnosticClient(Diags.getClient());
@@ -294,7 +293,9 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI,
Clang.takeDiagnosticClient();
Clang.takeDiagnostics();
+ Clang.takeInvocation();
+ AST->Invocation.reset(Clang.takeInvocation());
return AST.take();
error:
@@ -310,7 +311,6 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
Diagnostic &Diags,
llvm::StringRef ResourceFilesPath,
bool OnlyLocalDecls,
- bool UseBumpAllocator,
RemappedFile *RemappedFiles,
unsigned NumRemappedFiles) {
llvm::SmallVector<const char *, 16> Args;
@@ -324,6 +324,10 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
// FIXME: We shouldn't have to pass in the path info.
driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(),
"a.out", false, Diags);
+
+ // Don't check that inputs exist, they have been remapped.
+ TheDriver.setCheckInputsExist(false);
+
llvm::OwningPtr<driver::Compilation> C(
TheDriver.BuildCompilation(Args.size(), Args.data()));
@@ -345,19 +349,19 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
}
const driver::ArgStringList &CCArgs = Cmd->getArguments();
- CompilerInvocation CI;
- CompilerInvocation::CreateFromArgs(CI, (const char**) CCArgs.data(),
+ llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
+ CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(),
(const char**) CCArgs.data()+CCArgs.size(),
Diags);
// Override any files that need remapping
for (unsigned I = 0; I != NumRemappedFiles; ++I)
- CI.getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
- RemappedFiles[I].second);
+ CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
+ RemappedFiles[I].second);
// Override the resources path.
- CI.getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
+ CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
- CI.getFrontendOpts().DisableFree = UseBumpAllocator;
- return LoadFromCompilerInvocation(CI, Diags, OnlyLocalDecls);
+ CI->getFrontendOpts().DisableFree = true;
+ return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls);
}
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
index 45a3b15caecc..d764fd078968 100644
--- a/lib/Frontend/AnalysisConsumer.cpp
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -18,14 +18,15 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ParentMap.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/Analyses/UninitializedValues.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"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
+#include "clang/Checker/ManagerRegistry.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/PathSensitive/AnalysisManager.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/PathDiagnosticClients.h"
@@ -64,13 +65,17 @@ namespace {
class AnalysisConsumer : public ASTConsumer {
public:
typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D);
-
+ typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M,
+ TranslationUnitDecl &TU);
+
private:
typedef std::vector<CodeAction> Actions;
+ typedef std::vector<TUAction> TUActions;
+
Actions FunctionActions;
Actions ObjCMethodActions;
Actions ObjCImplementationActions;
- Actions TranslationUnitActions;
+ TUActions TranslationUnitActions;
public:
ASTContext* Ctx;
@@ -133,11 +138,11 @@ public:
}
}
}
-
+
void DisplayFunction(const Decl *D) {
if (!Opts.AnalyzerDisplayProgress || declDisplayed)
return;
-
+
declDisplayed = true;
SourceManager &SM = Mgr->getASTContext().getSourceManager();
PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
@@ -162,7 +167,7 @@ public:
ObjCImplementationActions.push_back(action);
}
- void addTranslationUnitAction(CodeAction action) {
+ void addTranslationUnitAction(TUAction action) {
TranslationUnitActions.push_back(action);
}
@@ -191,7 +196,7 @@ public:
namespace llvm {
template <> struct FoldingSetTrait<AnalysisConsumer::CodeAction> {
- static inline void Profile(AnalysisConsumer::CodeAction X,
+ static inline void Profile(AnalysisConsumer::CodeAction X,
FoldingSetNodeID& ID) {
ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X)));
}
@@ -204,42 +209,30 @@ namespace llvm {
void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) {
switch (D->getKind()) {
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ case Decl::CXXMethod:
case Decl::Function: {
FunctionDecl* FD = cast<FunctionDecl>(D);
-
if (!Opts.AnalyzeSpecificFunction.empty() &&
- Opts.AnalyzeSpecificFunction != FD->getIdentifier()->getName())
- break;
+ FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
+ break;
- Stmt* Body = FD->getBody();
- if (Body) HandleCode(FD, Body, FunctionActions);
+ if (Stmt *Body = FD->getBody())
+ HandleCode(FD, Body, FunctionActions);
break;
}
case Decl::ObjCMethod: {
ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
- if (Opts.AnalyzeSpecificFunction.size() > 0 &&
+ if (!Opts.AnalyzeSpecificFunction.empty() &&
Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString())
return;
- Stmt* Body = MD->getBody();
- if (Body) HandleCode(MD, Body, ObjCMethodActions);
- break;
- }
-
- case Decl::CXXConstructor:
- case Decl::CXXDestructor:
- case Decl::CXXConversion:
- case Decl::CXXMethod: {
- CXXMethodDecl *CXXMD = cast<CXXMethodDecl>(D);
-
- if (Opts.AnalyzeSpecificFunction.size() > 0 &&
- Opts.AnalyzeSpecificFunction != CXXMD->getName())
- return;
-
- Stmt *Body = CXXMD->getBody();
- if (Body) HandleCode(CXXMD, Body, FunctionActions);
+ if (Stmt* Body = MD->getBody())
+ HandleCode(MD, Body, ObjCMethodActions);
break;
}
@@ -249,30 +242,12 @@ void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) {
}
void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
-
+
TranslationUnitDecl *TU = C.getTranslationUnitDecl();
-
- if (!TranslationUnitActions.empty()) {
- // Find the entry function definition (if any).
- FunctionDecl *FD = 0;
- // Must specify an entry function.
- if (!Opts.AnalyzeSpecificFunction.empty()) {
- for (DeclContext::decl_iterator I=TU->decls_begin(), E=TU->decls_end();
- I != E; ++I) {
- if (FunctionDecl *fd = dyn_cast<FunctionDecl>(*I))
- if (fd->isThisDeclarationADefinition() &&
- fd->getNameAsString() == Opts.AnalyzeSpecificFunction) {
- FD = fd;
- break;
- }
- }
- }
- if (FD) {
- for (Actions::iterator I = TranslationUnitActions.begin(),
- E = TranslationUnitActions.end(); I != E; ++I)
- (*I)(*this, *Mgr, FD);
- }
+ for (TUActions::iterator I = TranslationUnitActions.begin(),
+ E = TranslationUnitActions.end(); I != E; ++I) {
+ (*I)(*this, *Mgr, *TU);
}
if (!ObjCImplementationActions.empty()) {
@@ -293,7 +268,7 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) {
if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
WL.push_back(BD);
-
+
for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
I!=E; ++I)
if (DeclContext *DC = dyn_cast<DeclContext>(*I))
@@ -314,14 +289,14 @@ void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) {
// Clear the AnalysisManager of old AnalysisContexts.
Mgr->ClearContexts();
-
+
// Dispatch on the actions.
llvm::SmallVector<Decl*, 10> WL;
WL.push_back(D);
-
+
if (Body && Opts.AnalyzeNestedBlocks)
FindBlocks(cast<DeclContext>(D), WL);
-
+
for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I)
for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
WI != WE; ++WI)
@@ -351,7 +326,7 @@ static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr,
static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
- Decl *D,
+ Decl *D,
GRTransferFuncs* tf) {
llvm::OwningPtr<GRTransferFuncs> TF(tf);
@@ -363,18 +338,18 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
// information to see if the CFG is valid.
// FIXME: Inter-procedural analysis will need to handle invalid CFGs.
if (!mgr.getLiveVariables(D))
- return;
-
+ return;
+
GRExprEngine Eng(mgr, TF.take());
-
+
if (C.Opts.EnableExperimentalInternalChecks)
RegisterExperimentalInternalChecks(Eng);
-
+
RegisterAppleChecks(Eng, *D);
-
+
if (C.Opts.EnableExperimentalChecks)
RegisterExperimentalChecks(Eng);
-
+
// Set the graph auditor.
llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
if (mgr.shouldVisualizeUbigraph()) {
@@ -397,7 +372,7 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
Eng.getBugReporter().FlushReports();
}
-static void ActionCheckerCFRefAux(AnalysisConsumer &C, AnalysisManager& mgr,
+static void ActionObjCMemCheckerAux(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D, bool GCEnabled) {
GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(),
@@ -407,23 +382,23 @@ static void ActionCheckerCFRefAux(AnalysisConsumer &C, AnalysisManager& mgr,
ActionGRExprEngine(C, mgr, D, TF);
}
-static void ActionCheckerCFRef(AnalysisConsumer &C, AnalysisManager& mgr,
+static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) {
switch (mgr.getLangOptions().getGCMode()) {
default:
assert (false && "Invalid GC mode.");
case LangOptions::NonGC:
- ActionCheckerCFRefAux(C, mgr, D, false);
+ ActionObjCMemCheckerAux(C, mgr, D, false);
break;
case LangOptions::GCOnly:
- ActionCheckerCFRefAux(C, mgr, D, true);
+ ActionObjCMemCheckerAux(C, mgr, D, true);
break;
case LangOptions::HybridGC:
- ActionCheckerCFRefAux(C, mgr, D, false);
- ActionCheckerCFRefAux(C, mgr, D, true);
+ ActionObjCMemCheckerAux(C, mgr, D, false);
+ ActionObjCMemCheckerAux(C, mgr, D, true);
break;
}
}
@@ -457,6 +432,13 @@ static void ActionSecuritySyntacticChecks(AnalysisConsumer &C,
CheckSecuritySyntaxOnly(D, BR);
}
+static void ActionLLVMConventionChecker(AnalysisConsumer &C,
+ AnalysisManager &mgr,
+ TranslationUnitDecl &TU) {
+ BugReporter BR(mgr);
+ CheckLLVMConventions(TU, BR);
+}
+
static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) {
if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
@@ -489,8 +471,29 @@ static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr,
}
static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr,
- Decl *D) {
- // FIXME: This is largely copy of ActionGRExprEngine. Needs cleanup.
+ TranslationUnitDecl &TU) {
+
+ // Find the entry function definition (if any).
+ FunctionDecl *D = 0;
+
+ // Must specify an entry function.
+ if (!C.Opts.AnalyzeSpecificFunction.empty()) {
+ for (DeclContext::decl_iterator I=TU.decls_begin(), E=TU.decls_end();
+ I != E; ++I) {
+ if (FunctionDecl *fd = dyn_cast<FunctionDecl>(*I))
+ if (fd->isThisDeclarationADefinition() &&
+ fd->getNameAsString() == C.Opts.AnalyzeSpecificFunction) {
+ D = fd;
+ break;
+ }
+ }
+ }
+
+ if (!D)
+ return;
+
+
+ // FIXME: This is largely copy of ActionGRExprEngine. Needs cleanup.
// Display progress.
C.DisplayFunction(D);
@@ -500,9 +503,9 @@ static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr,
if (C.Opts.EnableExperimentalInternalChecks)
RegisterExperimentalInternalChecks(Eng);
-
+
RegisterAppleChecks(Eng, *D);
-
+
if (C.Opts.EnableExperimentalChecks)
RegisterExperimentalChecks(Eng);
diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp
index 9be6786b5f75..f5291a9525e7 100644
--- a/lib/Frontend/Backend.cpp
+++ b/lib/Frontend/Backend.cpp
@@ -17,7 +17,6 @@
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/Module.h"
-#include "llvm/ModuleProvider.h"
#include "llvm/PassManager.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Assembly/PrintModulePass.h"
@@ -56,7 +55,6 @@ namespace {
llvm::Module *TheModule;
llvm::TargetData *TheTargetData;
- mutable llvm::ModuleProvider *ModuleProvider;
mutable FunctionPassManager *CodeGenPasses;
mutable PassManager *PerModulePasses;
mutable FunctionPassManager *PerFunctionPasses;
@@ -89,7 +87,7 @@ namespace {
LLVMIRGeneration("LLVM IR Generation Time"),
CodeGenerationTime("Code Generation Time"),
Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)),
- TheModule(0), TheTargetData(0), ModuleProvider(0),
+ TheModule(0), TheTargetData(0),
CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) {
if (AsmOutStream)
@@ -101,7 +99,7 @@ namespace {
~BackendConsumer() {
delete TheTargetData;
- delete ModuleProvider;
+ delete TheModule;
delete CodeGenPasses;
delete PerModulePasses;
delete PerFunctionPasses;
@@ -116,7 +114,6 @@ namespace {
Gen->Initialize(Ctx);
TheModule = Gen->GetModule();
- ModuleProvider = new ExistingModuleProvider(TheModule);
TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription());
if (llvm::TimePassesIsEnabled)
@@ -172,7 +169,7 @@ namespace {
FunctionPassManager *BackendConsumer::getCodeGenPasses() const {
if (!CodeGenPasses) {
- CodeGenPasses = new FunctionPassManager(ModuleProvider);
+ CodeGenPasses = new FunctionPassManager(TheModule);
CodeGenPasses->add(new TargetData(*TheTargetData));
}
@@ -190,7 +187,7 @@ PassManager *BackendConsumer::getPerModulePasses() const {
FunctionPassManager *BackendConsumer::getPerFunctionPasses() const {
if (!PerFunctionPasses) {
- PerFunctionPasses = new FunctionPassManager(ModuleProvider);
+ PerFunctionPasses = new FunctionPassManager(TheModule);
PerFunctionPasses->add(new TargetData(*TheTargetData));
}
@@ -306,20 +303,12 @@ bool BackendConsumer::AddEmitPasses() {
case 3: OptLevel = CodeGenOpt::Aggressive; break;
}
- // Normal mode, emit a .s file by running the code generator.
- // Note, this also adds codegenerator level optimization passes.
- switch (TM->addPassesToEmitFile(*PM, FormattedOutStream,
- TargetMachine::AssemblyFile, OptLevel)) {
- default:
- case FileModel::Error:
- Diags.Report(diag::err_fe_unable_to_interface_with_target);
- return false;
- case FileModel::AsmFile:
- break;
- }
-
- if (TM->addPassesToEmitFileFinish(*CodeGenPasses, (MachineCodeEmitter *)0,
- OptLevel)) {
+ // Normal mode, emit a .s or .o file by running the code generator. Note,
+ // this also adds codegenerator level optimization passes.
+ TargetMachine::CodeGenFileType CGFT = TargetMachine::CGFT_AssemblyFile;
+ if (Action == Backend_EmitObj)
+ CGFT = TargetMachine::CGFT_ObjectFile;
+ if (TM->addPassesToEmitFile(*PM, FormattedOutStream, CGFT, OptLevel)) {
Diags.Report(diag::err_fe_unable_to_interface_with_target);
return false;
}
@@ -354,11 +343,11 @@ void BackendConsumer::CreatePasses() {
// Set the inline threshold following llvm-gcc.
//
// FIXME: Derive these constants in a principled fashion.
- unsigned Threshold = 200;
+ unsigned Threshold = 225;
if (CodeGenOpts.OptimizeSize)
- Threshold = 50;
+ Threshold = 75;
else if (OptLevel > 2)
- Threshold = 250;
+ Threshold = 275;
InliningPass = createFunctionInliningPass(Threshold);
break;
}
@@ -392,7 +381,6 @@ void BackendConsumer::EmitAssembly() {
if (!M) {
// The module has been released by IR gen on failures, do not
// double free.
- ModuleProvider->releaseModule();
TheModule = 0;
return;
}
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 58aaa43aab8f..1d0b5c12041a 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -2,6 +2,7 @@ set(LLVM_NO_RTTI 1)
add_clang_library(clangFrontend
ASTConsumers.cpp
+ ASTMerge.cpp
ASTUnit.cpp
AnalysisConsumer.cpp
Backend.cpp
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 19c740d17a83..917cbd711ad3 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -35,15 +35,19 @@
#include "llvm/System/Program.h"
using namespace clang;
-CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext,
- bool _OwnsLLVMContext)
- : LLVMContext(_LLVMContext),
- OwnsLLVMContext(_OwnsLLVMContext) {
- }
+CompilerInstance::CompilerInstance()
+ : Invocation(new CompilerInvocation()) {
+}
CompilerInstance::~CompilerInstance() {
- if (OwnsLLVMContext)
- delete LLVMContext;
+}
+
+void CompilerInstance::setLLVMContext(llvm::LLVMContext *Value) {
+ LLVMContext.reset(Value);
+}
+
+void CompilerInstance::setInvocation(CompilerInvocation *Value) {
+ Invocation.reset(Value);
}
void CompilerInstance::setDiagnostics(Diagnostic *Value) {
@@ -83,6 +87,23 @@ void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
}
// Diagnostics
+namespace {
+ class BinaryDiagnosticSerializer : public DiagnosticClient {
+ llvm::raw_ostream &OS;
+ SourceManager *SourceMgr;
+ public:
+ explicit BinaryDiagnosticSerializer(llvm::raw_ostream &OS)
+ : OS(OS), SourceMgr(0) { }
+
+ virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info);
+ };
+}
+
+void BinaryDiagnosticSerializer::HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info) {
+ Info.Serialize(DiagLevel, OS);
+}
static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
unsigned argc, char **argv,
@@ -122,8 +143,23 @@ Diagnostic *CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
// Create the diagnostic client for reporting errors or for
// implementing -verify.
- llvm::OwningPtr<DiagnosticClient> DiagClient(
- new TextDiagnosticPrinter(llvm::errs(), Opts));
+ llvm::OwningPtr<DiagnosticClient> DiagClient;
+ if (Opts.BinaryOutput) {
+ if (llvm::sys::Program::ChangeStderrToBinary()) {
+ // We weren't able to set standard error to binary, which is a
+ // bit of a problem. So, just create a text diagnostic printer
+ // to complain about this problem, and pretend that the user
+ // didn't try to use binary output.
+ DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts));
+ Diags->setClient(DiagClient.take());
+ Diags->Report(diag::err_fe_stderr_binary);
+ return Diags.take();
+ } else {
+ DiagClient.reset(new BinaryDiagnosticSerializer(llvm::errs()));
+ }
+ } else {
+ DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts));
+ }
// Chain in -verify checker, if requested.
if (Opts.VerifyDiagnostics)
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 0bca4754ec11..a193ac870307 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -170,6 +170,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
}
if (Opts.NoZeroInitializedInBSS)
Res.push_back("-mno-zero-initialized-bss");
+ if (Opts.ObjCLegacyDispatch)
+ Res.push_back("-fobjc-legacy-dispatch");
if (Opts.SoftFloat)
Res.push_back("-msoft-float");
if (Opts.UnwindTables)
@@ -178,6 +180,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-mrelocation-model");
Res.push_back(Opts.RelocationModel);
}
+ if (!Opts.VerifyModule)
+ Res.push_back("-disable-llvm-verifier");
}
static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts,
@@ -220,6 +224,8 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
Res.push_back("-fcolor-diagnostics");
if (Opts.VerifyDiagnostics)
Res.push_back("-verify");
+ if (Opts.BinaryOutput)
+ Res.push_back("-fdiagnostics-binary");
if (Opts.ShowOptionNames)
Res.push_back("-fdiagnostics-show-option");
if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) {
@@ -276,6 +282,7 @@ static const char *getActionName(frontend::ActionKind Kind) {
case frontend::EmitHTML: return "-emit-html";
case frontend::EmitLLVM: return "-emit-llvm";
case frontend::EmitLLVMOnly: return "-emit-llvm-only";
+ case frontend::EmitObj: return "-emit-obj";
case frontend::FixIt: return "-fixit";
case frontend::GeneratePCH: return "-emit-pch";
case frontend::GeneratePTH: return "-emit-pth";
@@ -362,6 +369,10 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-load");
Res.push_back(Opts.Plugins[i]);
}
+ for (unsigned i = 0, e = Opts.ASTMergeFiles.size(); i != e; ++i) {
+ Res.push_back("-ast-merge");
+ Res.push_back(Opts.ASTMergeFiles[i]);
+ }
}
static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
@@ -450,6 +461,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fms-extensions");
if (Opts.ObjCNonFragileABI)
Res.push_back("-fobjc-nonfragile-abi");
+ if (Opts.ObjCNonFragileABI2)
+ Res.push_back("-fobjc-nonfragile-abi2");
// NoInline is implicit.
if (!Opts.CXXOperatorNames)
Res.push_back("-fno-operator-names");
@@ -465,6 +478,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-faltivec");
if (Opts.Exceptions)
Res.push_back("-fexceptions");
+ if (Opts.SjLjExceptions)
+ Res.push_back("-fsjlj-exceptions");
if (!Opts.RTTI)
Res.push_back("-fno-rtti");
if (!Opts.NeXTRuntime)
@@ -475,8 +490,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fno-builtin");
if (!Opts.AssumeSaneOperatorNew)
Res.push_back("-fno-assume-sane-operator-new");
- if (Opts.ThreadsafeStatics)
- llvm::llvm_report_error("FIXME: Not yet implemented!");
+ if (!Opts.ThreadsafeStatics)
+ Res.push_back("-fno-threadsafe-statics");
if (Opts.POSIXThreads)
Res.push_back("-pthread");
if (Opts.Blocks)
@@ -770,18 +785,13 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.FloatABI = getLastArgValue(Args, OPT_mfloat_abi);
Opts.LimitFloatPrecision = getLastArgValue(Args, OPT_mlimit_float_precision);
Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss);
+ Opts.ObjCLegacyDispatch = Args.hasArg(OPT_fobjc_legacy_dispatch);
Opts.SoftFloat = Args.hasArg(OPT_msoft_float);
Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
Opts.RelocationModel = getLastArgValue(Args, OPT_mrelocation_model, "pic");
Opts.MainFileName = getLastArgValue(Args, OPT_main_file_name);
-
- // FIXME: Put elsewhere?
-#ifdef NDEBUG
- Opts.VerifyModule = 0;
-#else
- Opts.VerifyModule = 1;
-#endif
+ Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
}
static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
@@ -808,6 +818,7 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option);
Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
+ Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary);
Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
DiagnosticOptions::DefaultTabStop, Diags);
if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
@@ -852,6 +863,8 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
Opts.ProgramAction = frontend::EmitLLVM; break;
case OPT_emit_llvm_only:
Opts.ProgramAction = frontend::EmitLLVMOnly; break;
+ case OPT_emit_obj:
+ Opts.ProgramAction = frontend::EmitObj; break;
case OPT_fixit:
Opts.ProgramAction = frontend::FixIt; break;
case OPT_emit_pch:
@@ -920,6 +933,7 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
Opts.ShowTimers = Args.hasArg(OPT_ftime_report);
Opts.ShowVersion = Args.hasArg(OPT_version);
Opts.ViewClassInheritance = getLastArgValue(Args, OPT_cxx_inheritance_view);
+ Opts.ASTMergeFiles = getAllArgValues(Args, OPT_ast_merge);
FrontendOptions::InputKind DashX = FrontendOptions::IK_None;
if (const Arg *A = Args.getLastArg(OPT_x)) {
@@ -1146,7 +1160,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.Microsoft = Args.hasArg(OPT_fms_extensions);
Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
if (Args.hasArg(OPT_fno_lax_vector_conversions))
- Opts.LaxVectorConversions = 0;
+ Opts.LaxVectorConversions = 0;
+ if (Args.hasArg(OPT_fno_threadsafe_statics))
+ Opts.ThreadsafeStatics = 0;
Opts.Exceptions = Args.hasArg(OPT_fexceptions);
Opts.RTTI = !Args.hasArg(OPT_fno_rtti);
Opts.Blocks = Args.hasArg(OPT_fblocks);
@@ -1165,10 +1181,15 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.ObjCConstantStringClass = getLastArgValue(Args,
OPT_fconstant_string_class);
Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi);
+ Opts.ObjCNonFragileABI2 = Args.hasArg(OPT_fobjc_nonfragile_abi2);
+ if (Opts.ObjCNonFragileABI2)
+ Opts.ObjCNonFragileABI = true;
Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior);
Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls);
Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags);
+ Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions);
Opts.Static = Args.hasArg(OPT_static_define);
+ Opts.DumpVtableLayouts = Args.hasArg(OPT_fdump_vtable_layouts);
Opts.OptimizeSize = 0;
// FIXME: Eliminate this dependency.
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 0baba3f4673a..1c958a7087a9 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -177,6 +177,9 @@ ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
break;
case Backend_EmitNothing:
break;
+ case Backend_EmitObj:
+ OS.reset(CI.createDefaultOutputFile(true, InFile, "o"));
+ break;
}
if (BA != Backend_EmitNothing && !OS)
return 0;
@@ -196,6 +199,8 @@ EmitLLVMAction::EmitLLVMAction() : CodeGenAction(Backend_EmitLL) {}
EmitLLVMOnlyAction::EmitLLVMOnlyAction() : CodeGenAction(Backend_EmitNothing) {}
+EmitObjAction::EmitObjAction() : CodeGenAction(Backend_EmitObj) {}
+
//===----------------------------------------------------------------------===//
// Preprocessor Actions
//===----------------------------------------------------------------------===//
diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp
index b163e267b049..f695254cb466 100644
--- a/lib/Frontend/HTMLDiagnostics.cpp
+++ b/lib/Frontend/HTMLDiagnostics.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/PathDiagnosticClients.h"
-#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/SourceManager.h"
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 6102760aef53..2e0b4bdbfce3 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -483,10 +483,10 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
AddPath("/usr/include/c++/4.1", System, true, false, false);
break;
case llvm::Triple::Linux:
- // Exherbo (2009-10-26)
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
+ // Exherbo (2010-01-25)
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
"x86_64-pc-linux-gnu", "32", "", triple);
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
"i686-pc-linux-gnu", "", "", triple);
// Debian sid
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
@@ -522,6 +522,10 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
"i686-redhat-linux","", "", triple);
+ // Fedora 12 (February-2010+)
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
+ "i686-redhat-linux","", "", triple);
+
// openSUSE 11.1 32 bit
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
"i586-suse-linux", "", "", triple);
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 9aaf1320346f..b7ab3d8cd452 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -279,6 +279,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (LangOpts.Exceptions)
Builder.defineMacro("__EXCEPTIONS");
+ if (LangOpts.SjLjExceptions)
+ Builder.defineMacro("__USING_SJLJ_EXCEPTIONS__");
if (LangOpts.CPlusPlus) {
Builder.defineMacro("__DEPRECATED");
diff --git a/lib/Frontend/Makefile b/lib/Frontend/Makefile
index 8d708475783f..a630b0133632 100644
--- a/lib/Frontend/Makefile
+++ b/lib/Frontend/Makefile
@@ -10,7 +10,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangFrontend
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 259355145aa3..a878df784005 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -72,12 +72,14 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
PARSE_LANGOPT_IMPORTANT(ObjC1, diag::warn_pch_objective_c);
PARSE_LANGOPT_IMPORTANT(ObjC2, diag::warn_pch_objective_c2);
PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI, diag::warn_pch_nonfragile_abi);
+ PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI2, diag::warn_pch_nonfragile_abi2);
PARSE_LANGOPT_BENIGN(PascalStrings);
PARSE_LANGOPT_BENIGN(WritableStrings);
PARSE_LANGOPT_IMPORTANT(LaxVectorConversions,
diag::warn_pch_lax_vector_conversions);
PARSE_LANGOPT_IMPORTANT(AltiVec, diag::warn_pch_altivec);
PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions);
+ PARSE_LANGOPT_IMPORTANT(SjLjExceptions, diag::warn_pch_sjlj_exceptions);
PARSE_LANGOPT_IMPORTANT(NeXTRuntime, diag::warn_pch_objc_runtime);
PARSE_LANGOPT_IMPORTANT(Freestanding, diag::warn_pch_freestanding);
PARSE_LANGOPT_IMPORTANT(NoBuiltin, diag::warn_pch_builtins);
@@ -434,7 +436,9 @@ public:
continue;
}
- Prev->Next = new ObjCMethodList(Method, 0);
+ ObjCMethodList *Mem =
+ Reader.getSema()->BumpAlloc.Allocate<ObjCMethodList>();
+ Prev->Next = new (Mem) ObjCMethodList(Method, 0);
Prev = Prev->Next;
}
@@ -450,7 +454,9 @@ public:
continue;
}
- Prev->Next = new ObjCMethodList(Method, 0);
+ ObjCMethodList *Mem =
+ Reader.getSema()->BumpAlloc.Allocate<ObjCMethodList>();
+ Prev->Next = new (Mem) ObjCMethodList(Method, 0);
Prev = Prev->Next;
}
@@ -1326,6 +1332,14 @@ PCHReader::ReadPCHBlock() {
TentativeDefinitions.swap(Record);
break;
+ case pch::UNUSED_STATIC_FUNCS:
+ if (!UnusedStaticFuncs.empty()) {
+ Error("duplicate UNUSED_STATIC_FUNCS record in PCH file");
+ return Failure;
+ }
+ UnusedStaticFuncs.swap(Record);
+ break;
+
case pch::LOCALLY_SCOPED_EXTERNAL_DECLS:
if (!LocallyScopedExternalDecls.empty()) {
Error("duplicate LOCALLY_SCOPED_EXTERNAL_DECLS record in PCH file");
@@ -1400,9 +1414,9 @@ PCHReader::ReadPCHBlock() {
break;
case pch::VERSION_CONTROL_BRANCH_REVISION: {
- llvm::StringRef CurBranch = getClangFullRepositoryVersion();
+ const std::string &CurBranch = getClangFullRepositoryVersion();
llvm::StringRef PCHBranch(BlobStart, BlobLen);
- if (CurBranch != PCHBranch) {
+ if (llvm::StringRef(CurBranch) != PCHBranch) {
Diag(diag::warn_pch_different_branch) << PCHBranch << CurBranch;
return IgnorePCH;
}
@@ -1740,11 +1754,13 @@ bool PCHReader::ParseLanguageOptions(
PARSE_LANGOPT(ObjC1);
PARSE_LANGOPT(ObjC2);
PARSE_LANGOPT(ObjCNonFragileABI);
+ PARSE_LANGOPT(ObjCNonFragileABI2);
PARSE_LANGOPT(PascalStrings);
PARSE_LANGOPT(WritableStrings);
PARSE_LANGOPT(LaxVectorConversions);
PARSE_LANGOPT(AltiVec);
PARSE_LANGOPT(Exceptions);
+ PARSE_LANGOPT(SjLjExceptions);
PARSE_LANGOPT(NeXTRuntime);
PARSE_LANGOPT(Freestanding);
PARSE_LANGOPT(NoBuiltin);
@@ -1880,18 +1896,20 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
}
case pch::TYPE_VECTOR: {
- if (Record.size() != 2) {
+ if (Record.size() != 4) {
Error("incorrect encoding of vector type in PCH file");
return QualType();
}
QualType ElementType = GetType(Record[0]);
unsigned NumElements = Record[1];
- return Context->getVectorType(ElementType, NumElements);
+ bool AltiVec = Record[2];
+ bool Pixel = Record[3];
+ return Context->getVectorType(ElementType, NumElements, AltiVec, Pixel);
}
case pch::TYPE_EXT_VECTOR: {
- if (Record.size() != 2) {
+ if (Record.size() != 4) {
Error("incorrect encoding of extended vector type in PCH file");
return QualType();
}
@@ -2464,11 +2482,17 @@ void PCHReader::InitializeSema(Sema &S) {
PreloadedDecls.clear();
// If there were any tentative definitions, deserialize them and add
- // them to Sema's table of tentative definitions.
+ // them to Sema's list of tentative definitions.
for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
VarDecl *Var = cast<VarDecl>(GetDecl(TentativeDefinitions[I]));
- SemaObj->TentativeDefinitions[Var->getDeclName()] = Var;
- SemaObj->TentativeDefinitionList.push_back(Var->getDeclName());
+ SemaObj->TentativeDefinitions.push_back(Var);
+ }
+
+ // If there were any unused static functions, deserialize them and add to
+ // Sema's list of unused static functions.
+ for (unsigned I = 0, N = UnusedStaticFuncs.size(); I != N; ++I) {
+ FunctionDecl *FD = cast<FunctionDecl>(GetDecl(UnusedStaticFuncs[I]));
+ SemaObj->UnusedStaticFuncs.push_back(FD);
}
// If there were any locally-scoped external declarations,
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index 4dc1318a3ee8..625997cac232 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -117,6 +117,7 @@ void PCHDeclReader::VisitTagDecl(TagDecl *TD) {
cast_or_null<TagDecl>(Reader.GetDecl(Record[Idx++])));
TD->setTagKind((TagDecl::TagKind)Record[Idx++]);
TD->setDefinition(Record[Idx++]);
+ TD->setEmbeddedInDeclarator(Record[Idx++]);
TD->setTypedefForAnonDecl(
cast_or_null<TypedefDecl>(Reader.GetDecl(Record[Idx++])));
TD->setRBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
@@ -179,7 +180,7 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
Params.reserve(NumParams);
for (unsigned I = 0; I != NumParams; ++I)
Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
- FD->setParams(*Reader.getContext(), Params.data(), NumParams);
+ FD->setParams(Params.data(), NumParams);
}
void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
@@ -387,7 +388,7 @@ void PCHDeclReader::VisitVarDecl(VarDecl *VD) {
VD->setPreviousDeclaration(
cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
if (Record[Idx++])
- VD->setInit(*Reader.getContext(), Reader.ReadDeclExpr());
+ VD->setInit(Reader.ReadDeclExpr());
}
void PCHDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) {
@@ -412,7 +413,7 @@ void PCHDeclReader::VisitBlockDecl(BlockDecl *BD) {
Params.reserve(NumParams);
for (unsigned I = 0; I != NumParams; ++I)
Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
- BD->setParams(*Reader.getContext(), Params.data(), NumParams);
+ BD->setParams(Params.data(), NumParams);
}
std::pair<uint64_t, uint64_t>
@@ -445,7 +446,7 @@ Attr *PCHReader::ReadAttributes() {
#define STRING_ATTR(Name) \
case Attr::Name: \
- New = ::new (*Context) Name##Attr(ReadString(Record, Idx)); \
+ New = ::new (*Context) Name##Attr(*Context, ReadString(Record, Idx)); \
break
#define UNSIGNED_ATTR(Name) \
@@ -496,7 +497,7 @@ Attr *PCHReader::ReadAttributes() {
std::string Type = ReadString(Record, Idx);
unsigned FormatIdx = Record[Idx++];
unsigned FirstArg = Record[Idx++];
- New = ::new (*Context) FormatAttr(Type, FormatIdx, FirstArg);
+ New = ::new (*Context) FormatAttr(*Context, Type, FormatIdx, FirstArg);
break;
}
@@ -531,7 +532,7 @@ Attr *PCHReader::ReadAttributes() {
llvm::SmallVector<unsigned, 16> ArgNums;
ArgNums.insert(ArgNums.end(), &Record[Idx], &Record[Idx] + Size);
Idx += Size;
- New = ::new (*Context) NonNullAttr(ArgNums.data(), Size);
+ New = ::new (*Context) NonNullAttr(*Context, ArgNums.data(), Size);
break;
}
diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
index 21c9cbf17cd7..d123694d699d 100644
--- a/lib/Frontend/PCHReaderStmt.cpp
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -123,6 +123,8 @@ namespace {
unsigned VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E);
unsigned VisitCXXConstCastExpr(CXXConstCastExpr *E);
unsigned VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E);
+ unsigned VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
+ unsigned VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E);
};
}
@@ -317,22 +319,24 @@ unsigned PCHStmtReader::VisitAsmStmt(AsmStmt *S) {
S->setAsmString(cast_or_null<StringLiteral>(StmtStack[StackIdx++]));
// Outputs and inputs
- llvm::SmallVector<std::string, 16> Names;
+ llvm::SmallVector<IdentifierInfo *, 16> Names;
llvm::SmallVector<StringLiteral*, 16> Constraints;
llvm::SmallVector<Stmt*, 16> Exprs;
for (unsigned I = 0, N = NumOutputs + NumInputs; I != N; ++I) {
- Names.push_back(Reader.ReadString(Record, Idx));
+ Names.push_back(Reader.GetIdentifierInfo(Record, Idx));
Constraints.push_back(cast_or_null<StringLiteral>(StmtStack[StackIdx++]));
Exprs.push_back(StmtStack[StackIdx++]);
}
- S->setOutputsAndInputs(NumOutputs, NumInputs,
- Names.data(), Constraints.data(), Exprs.data());
// Constraints
llvm::SmallVector<StringLiteral*, 16> Clobbers;
for (unsigned I = 0; I != NumClobbers; ++I)
Clobbers.push_back(cast_or_null<StringLiteral>(StmtStack[StackIdx++]));
- S->setClobbers(Clobbers.data(), NumClobbers);
+
+ S->setOutputsAndInputsAndClobbers(*Reader.getContext(),
+ Names.data(), Constraints.data(),
+ Exprs.data(), NumOutputs, NumInputs,
+ Clobbers.data(), NumClobbers);
assert(StackIdx == StmtStack.size() && "Error deserializing AsmStmt");
return NumOutputs*2 + NumInputs*2 + NumClobbers + 1;
@@ -904,6 +908,19 @@ unsigned PCHStmtReader::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
return num;
}
+unsigned PCHStmtReader::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
+ VisitExpr(E);
+ E->setValue(Record[Idx++]);
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) {
+ VisitExpr(E);
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 0;
+}
+
// Within the bitstream, expressions are stored in Reverse Polish
// Notation, with each of the subexpressions preceding the
// expression they are stored in. To evaluate expressions, we
@@ -1233,7 +1250,13 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
S = new (Context) CXXFunctionalCastExpr(Empty);
break;
+ case pch::EXPR_CXX_BOOL_LITERAL:
+ S = new (Context) CXXBoolLiteralExpr(Empty);
+ break;
+ case pch::EXPR_CXX_NULL_PTR_LITERAL:
+ S = new (Context) CXXNullPtrLiteralExpr(Empty);
+ break;
}
// We hit a STMT_STOP, so we're done with this expression.
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 9909c95847ee..4c99dbe24504 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -128,6 +128,8 @@ void PCHTypeWriter::VisitVariableArrayType(const VariableArrayType *T) {
void PCHTypeWriter::VisitVectorType(const VectorType *T) {
Writer.AddTypeRef(T->getElementType(), Record);
Record.push_back(T->getNumElements());
+ Record.push_back(T->isAltiVec());
+ Record.push_back(T->isPixel());
Code = pch::TYPE_VECTOR;
}
@@ -511,6 +513,15 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(STMT_OBJC_AT_TRY);
RECORD(STMT_OBJC_AT_SYNCHRONIZED);
RECORD(STMT_OBJC_AT_THROW);
+ RECORD(EXPR_CXX_OPERATOR_CALL);
+ RECORD(EXPR_CXX_CONSTRUCT);
+ RECORD(EXPR_CXX_STATIC_CAST);
+ RECORD(EXPR_CXX_DYNAMIC_CAST);
+ RECORD(EXPR_CXX_REINTERPRET_CAST);
+ RECORD(EXPR_CXX_CONST_CAST);
+ RECORD(EXPR_CXX_FUNCTIONAL_CAST);
+ RECORD(EXPR_CXX_BOOL_LITERAL);
+ RECORD(EXPR_CXX_NULL_PTR_LITERAL);
#undef RECORD
}
@@ -534,6 +545,7 @@ void PCHWriter::WriteBlockInfoBlock() {
RECORD(SPECIAL_TYPES);
RECORD(STATISTICS);
RECORD(TENTATIVE_DEFINITIONS);
+ RECORD(UNUSED_STATIC_FUNCS);
RECORD(LOCALLY_SCOPED_EXTERNAL_DECLS);
RECORD(SELECTOR_OFFSETS);
RECORD(METHOD_POOL);
@@ -737,13 +749,17 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
Record.push_back(LangOpts.ObjC1); // Objective-C 1 support enabled.
Record.push_back(LangOpts.ObjC2); // Objective-C 2 support enabled.
- Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C modern abi enabled
+ Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C
+ // modern abi enabled.
+ Record.push_back(LangOpts.ObjCNonFragileABI2); // Objective-C enhanced
+ // modern abi enabled.
Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings
Record.push_back(LangOpts.WritableStrings); // Allow writable strings
Record.push_back(LangOpts.LaxVectorConversions);
Record.push_back(LangOpts.AltiVec);
Record.push_back(LangOpts.Exceptions); // Support exception handling.
+ Record.push_back(LangOpts.SjLjExceptions);
Record.push_back(LangOpts.NeXTRuntime); // Use NeXT runtime.
Record.push_back(LangOpts.Freestanding); // Freestanding implementation
@@ -1960,15 +1976,18 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
}
// Build a record containing all of the tentative definitions in this file, in
- // TentativeDefinitionList order. Generally, this record will be empty for
+ // TentativeDefinitions order. Generally, this record will be empty for
// headers.
RecordData TentativeDefinitions;
- for (unsigned i = 0, e = SemaRef.TentativeDefinitionList.size(); i != e; ++i){
- VarDecl *VD =
- SemaRef.TentativeDefinitions.lookup(SemaRef.TentativeDefinitionList[i]);
- if (VD) AddDeclRef(VD, TentativeDefinitions);
+ for (unsigned i = 0, e = SemaRef.TentativeDefinitions.size(); i != e; ++i) {
+ AddDeclRef(SemaRef.TentativeDefinitions[i], TentativeDefinitions);
}
+ // Build a record containing all of the static unused functions in this file.
+ RecordData UnusedStaticFuncs;
+ for (unsigned i=0, e = SemaRef.UnusedStaticFuncs.size(); i !=e; ++i)
+ AddDeclRef(SemaRef.UnusedStaticFuncs[i], UnusedStaticFuncs);
+
// Build a record containing all of the locally-scoped external
// declarations in this header file. Generally, this record will be
// empty.
@@ -2070,6 +2089,10 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
if (!TentativeDefinitions.empty())
Stream.EmitRecord(pch::TENTATIVE_DEFINITIONS, TentativeDefinitions);
+ // Write the record containing unused static functions.
+ if (!UnusedStaticFuncs.empty())
+ Stream.EmitRecord(pch::UNUSED_STATIC_FUNCS, UnusedStaticFuncs);
+
// Write the record containing locally-scoped external definitions.
if (!LocallyScopedExternalDecls.empty())
Stream.EmitRecord(pch::LOCALLY_SCOPED_EXTERNAL_DECLS,
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index 020f69b3e669..d105382b4354 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -115,6 +115,7 @@ void PCHDeclWriter::VisitTagDecl(TagDecl *D) {
Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding
Record.push_back(D->isDefinition());
+ Record.push_back(D->isEmbeddedInDeclarator());
Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record);
Writer.AddSourceLocation(D->getRBraceLoc(), Record);
Writer.AddSourceLocation(D->getTagKeywordLoc(), Record);
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
index fdfdfefe08ef..a8cc9d6f4591 100644
--- a/lib/Frontend/PCHWriterStmt.cpp
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -118,6 +118,8 @@ namespace {
void VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E);
void VisitCXXConstCastExpr(CXXConstCastExpr *E);
void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E);
+ void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
+ void VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E);
};
}
@@ -287,15 +289,15 @@ void PCHStmtWriter::VisitAsmStmt(AsmStmt *S) {
Writer.WriteSubStmt(S->getAsmString());
// Outputs
- for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
- Writer.AddString(S->getOutputName(I), Record);
+ for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
+ Writer.AddIdentifierRef(S->getOutputIdentifier(I), Record);
Writer.WriteSubStmt(S->getOutputConstraintLiteral(I));
Writer.WriteSubStmt(S->getOutputExpr(I));
}
// Inputs
for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) {
- Writer.AddString(S->getInputName(I), Record);
+ Writer.AddIdentifierRef(S->getInputIdentifier(I), Record);
Writer.WriteSubStmt(S->getInputConstraintLiteral(I));
Writer.WriteSubStmt(S->getInputExpr(I));
}
@@ -834,6 +836,19 @@ void PCHStmtWriter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
Code = pch::EXPR_CXX_FUNCTIONAL_CAST;
}
+void PCHStmtWriter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getValue());
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Code = pch::EXPR_CXX_BOOL_LITERAL;
+}
+
+void PCHStmtWriter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Code = pch::EXPR_CXX_NULL_PTR_LITERAL;
+}
+
//===----------------------------------------------------------------------===//
// PCHWriter Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp
index 98be869d2646..5706a07e5a0f 100644
--- a/lib/Frontend/PlistDiagnostics.cpp
+++ b/lib/Frontend/PlistDiagnostics.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/PathDiagnosticClients.h"
-#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Lex/Preprocessor.h"
diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp
index a91dd8d55e92..8d64a6413304 100644
--- a/lib/Frontend/PrintParserCallbacks.cpp
+++ b/lib/Frontend/PrintParserCallbacks.cpp
@@ -391,7 +391,7 @@ namespace {
bool IsVolatile,
unsigned NumOutputs,
unsigned NumInputs,
- std::string *Names,
+ IdentifierInfo **Names,
MultiExprArg Constraints,
MultiExprArg Exprs,
ExprArg AsmString,
@@ -684,7 +684,8 @@ namespace {
virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc,
IdentifierInfo *Ident,
- SourceLocation LBrace) {
+ SourceLocation LBrace,
+ AttributeList *AttrList) {
Out << __FUNCTION__ << "\n";
return DeclPtrTy();
}
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index 35d8dde8eaab..9dade66d4ab4 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -124,8 +124,10 @@ namespace {
llvm::DenseMap<BlockDeclRefExpr *, CallExpr *> BlockCallExprs;
// Block related declarations.
- llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls;
- llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls;
+ llvm::SmallVector<ValueDecl *, 8> BlockByCopyDecls;
+ llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDeclsPtrSet;
+ llvm::SmallVector<ValueDecl *, 8> BlockByRefDecls;
+ llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDeclsPtrSet;
llvm::DenseMap<ValueDecl *, unsigned> BlockByRefDeclNo;
llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls;
@@ -212,11 +214,10 @@ namespace {
<< Old->getSourceRange();
}
- void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen,
+ void InsertText(SourceLocation Loc, llvm::StringRef Str,
bool InsertAfter = true) {
// If insertion succeeded or warning disabled return with no warning.
- if (!Rewrite.InsertText(Loc, llvm::StringRef(StrData, StrLen),
- InsertAfter) ||
+ if (!Rewrite.InsertText(Loc, Str, InsertAfter) ||
SilenceRewriteMacroWarning)
return;
@@ -232,10 +233,9 @@ namespace {
}
void ReplaceText(SourceLocation Start, unsigned OrigLength,
- const char *NewStr, unsigned NewLength) {
+ llvm::StringRef Str) {
// If removal succeeded or warning disabled return with no warning.
- if (!Rewrite.ReplaceText(Start, OrigLength,
- llvm::StringRef(NewStr, NewLength)) ||
+ if (!Rewrite.ReplaceText(Start, OrigLength, Str) ||
SilenceRewriteMacroWarning)
return;
@@ -263,6 +263,7 @@ namespace {
void RewriteFunctionDecl(FunctionDecl *FD);
void RewriteBlockLiteralFunctionDecl(FunctionDecl *FD);
void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl);
+ void RewriteTypeOfDecl(VarDecl *VD);
void RewriteObjCQualifiedInterfaceTypes(Expr *E);
bool needToScanForQualifiers(QualType T);
ObjCInterfaceDecl *isSuperReceiver(Expr *recExpr);
@@ -278,7 +279,9 @@ namespace {
ParentMap *PropParentMap; // created lazily.
Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
- Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation OrigStart);
+ Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation OrigStart,
+ bool &replaced);
+ Stmt *RewriteObjCNestedIvarRefExpr(Stmt *S, bool &replaced);
Stmt *RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr);
Stmt *RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt,
SourceRange SrcRange);
@@ -632,6 +635,9 @@ void RewriteObjC::Initialize(ASTContext &context) {
//===----------------------------------------------------------------------===//
void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
+ if (Diags.hasErrorOccurred())
+ return;
+
// Two cases: either the decl could be in the main file, or it could be in a
// #included file. If the former, rewrite it now. If the later, check to see
// if we rewrote the #include/#import.
@@ -681,7 +687,6 @@ void RewriteObjC::RewriteInclude() {
const char *MainBufStart = MainBuf.first;
const char *MainBufEnd = MainBuf.second;
size_t ImportLen = strlen("import");
- size_t IncludeLen = strlen("include");
// Loop over the whole file, looking for includes.
for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) {
@@ -695,7 +700,7 @@ void RewriteObjC::RewriteInclude() {
// replace import with include
SourceLocation ImportLoc =
LocStart.getFileLocWithOffset(BufPtr-MainBufStart);
- ReplaceText(ImportLoc, ImportLen, "include", IncludeLen);
+ ReplaceText(ImportLoc, ImportLen, "include");
BufPtr += ImportLen;
}
}
@@ -728,7 +733,7 @@ void RewriteObjC::RewriteTabs() {
TabLoc = TabLoc.getFileLocWithOffset(BufPtr-MainBufStart);
// Rewrite the single tab character into a sequence of spaces.
- ReplaceText(TabLoc, 1, " ", Spaces);
+ ReplaceText(TabLoc, 1, llvm::StringRef(" ", Spaces));
}
}
@@ -746,7 +751,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
ObjCImplementationDecl *IMD,
ObjCCategoryImplDecl *CID) {
SourceLocation startLoc = PID->getLocStart();
- InsertText(startLoc, "// ", 3);
+ InsertText(startLoc, "// ");
const char *startBuf = SM->getCharacterData(startLoc);
assert((*startBuf == '@') && "bogus @synthesize location");
const char *semiBuf = strchr(startBuf, ';');
@@ -774,7 +779,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
// See objc-act.c:objc_synthesize_new_getter() for details.
Getr += "return " + getIvarAccessString(ClassDecl, OID);
Getr += "; }";
- InsertText(onePastSemiLoc, Getr.c_str(), Getr.size());
+ InsertText(onePastSemiLoc, Getr);
if (PD->isReadOnly())
return;
@@ -789,7 +794,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
Setr += getIvarAccessString(ClassDecl, OID) + " = ";
Setr += PD->getNameAsCString();
Setr += "; }";
- InsertText(onePastSemiLoc, Setr.c_str(), Setr.size());
+ InsertText(onePastSemiLoc, Setr);
}
void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) {
@@ -828,8 +833,7 @@ void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) {
}
// Replace the @class with typedefs corresponding to the classes.
- ReplaceText(startLoc, semiPtr-startBuf+1,
- typedefString.c_str(), typedefString.size());
+ ReplaceText(startLoc, semiPtr-startBuf+1, typedefString);
}
void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) {
@@ -842,17 +846,17 @@ void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) {
if (SM->getInstantiationLineNumber(LocEnd) >
SM->getInstantiationLineNumber(LocStart)) {
- InsertText(LocStart, "#if 0\n", 6);
- ReplaceText(LocEnd, 1, ";\n#endif\n", 9);
+ InsertText(LocStart, "#if 0\n");
+ ReplaceText(LocEnd, 1, ";\n#endif\n");
} else {
- InsertText(LocStart, "// ", 3);
+ InsertText(LocStart, "// ");
}
}
void RewriteObjC::RewriteProperty(ObjCPropertyDecl *prop) {
SourceLocation Loc = prop->getAtLoc();
- ReplaceText(Loc, 0, "// ", 3);
+ ReplaceText(Loc, 0, "// ");
// FIXME: handle properties that are declared across multiple lines.
}
@@ -860,8 +864,12 @@ void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
SourceLocation LocStart = CatDecl->getLocStart();
// FIXME: handle category headers that are declared across multiple lines.
- ReplaceText(LocStart, 0, "// ", 3);
+ ReplaceText(LocStart, 0, "// ");
+ for (ObjCCategoryDecl::prop_iterator I = CatDecl->prop_begin(),
+ E = CatDecl->prop_end(); I != E; ++I)
+ RewriteProperty(*I);
+
for (ObjCCategoryDecl::instmeth_iterator
I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end();
I != E; ++I)
@@ -872,7 +880,7 @@ void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
RewriteMethodDeclaration(*I);
// Lastly, comment out the @end.
- ReplaceText(CatDecl->getAtEndRange().getBegin(), 0, "// ", 3);
+ ReplaceText(CatDecl->getAtEndRange().getBegin(), 0, "// ");
}
void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
@@ -881,7 +889,7 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
SourceLocation LocStart = PDecl->getLocStart();
// FIXME: handle protocol headers that are declared across multiple lines.
- ReplaceText(LocStart, 0, "// ", 3);
+ ReplaceText(LocStart, 0, "// ");
for (ObjCProtocolDecl::instmeth_iterator
I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
@@ -894,24 +902,20 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
// Lastly, comment out the @end.
SourceLocation LocEnd = PDecl->getAtEndRange().getBegin();
- ReplaceText(LocEnd, 0, "// ", 3);
+ ReplaceText(LocEnd, 0, "// ");
// Must comment out @optional/@required
const char *startBuf = SM->getCharacterData(LocStart);
const char *endBuf = SM->getCharacterData(LocEnd);
for (const char *p = startBuf; p < endBuf; p++) {
if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) {
- std::string CommentedOptional = "/* @optional */";
SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
- ReplaceText(OptionalLoc, strlen("@optional"),
- CommentedOptional.c_str(), CommentedOptional.size());
+ ReplaceText(OptionalLoc, strlen("@optional"), "/* @optional */");
}
else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) {
- std::string CommentedRequired = "/* @required */";
SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
- ReplaceText(OptionalLoc, strlen("@required"),
- CommentedRequired.c_str(), CommentedRequired.size());
+ ReplaceText(OptionalLoc, strlen("@required"), "/* @required */");
}
}
@@ -922,7 +926,7 @@ void RewriteObjC::RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *PDecl) {
if (LocStart.isInvalid())
assert(false && "Invalid SourceLocation");
// FIXME: handle forward protocol that are declared across multiple lines.
- ReplaceText(LocStart, 0, "// ", 3);
+ ReplaceText(LocStart, 0, "// ");
}
void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD,
@@ -1050,10 +1054,7 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(OID);
ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(OID);
- if (IMD)
- InsertText(IMD->getLocStart(), "// ", 3);
- else
- InsertText(CID->getLocStart(), "// ", 3);
+ InsertText(IMD ? IMD->getLocStart() : CID->getLocStart(), "// ");
for (ObjCCategoryImplDecl::instmeth_iterator
I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(),
@@ -1067,8 +1068,7 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
const char *startBuf = SM->getCharacterData(LocStart);
const char *endBuf = SM->getCharacterData(LocEnd);
- ReplaceText(LocStart, endBuf-startBuf,
- ResultStr.c_str(), ResultStr.size());
+ ReplaceText(LocStart, endBuf-startBuf, ResultStr);
}
for (ObjCCategoryImplDecl::classmeth_iterator
@@ -1083,8 +1083,7 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
const char *startBuf = SM->getCharacterData(LocStart);
const char *endBuf = SM->getCharacterData(LocEnd);
- ReplaceText(LocStart, endBuf-startBuf,
- ResultStr.c_str(), ResultStr.size());
+ ReplaceText(LocStart, endBuf-startBuf, ResultStr);
}
for (ObjCCategoryImplDecl::propimpl_iterator
I = IMD ? IMD->propimpl_begin() : CID->propimpl_begin(),
@@ -1093,10 +1092,7 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
RewritePropertyImplDecl(*I, IMD, CID);
}
- if (IMD)
- InsertText(IMD->getLocEnd(), "// ", 3);
- else
- InsertText(CID->getLocEnd(), "// ", 3);
+ InsertText(IMD ? IMD->getLocEnd() : CID->getLocEnd(), "// ");
}
void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
@@ -1130,7 +1126,7 @@ void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
RewriteMethodDeclaration(*I);
// Lastly, comment out the @end.
- ReplaceText(ClassDecl->getAtEndRange().getBegin(), 0, "// ", 3);
+ ReplaceText(ClassDecl->getAtEndRange().getBegin(), 0, "// ");
}
Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt,
@@ -1149,7 +1145,7 @@ Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt,
// This allows us to handle chain/nested property getters.
Receiver = PropGetters[PRE];
}
- MsgExpr = new (Context) ObjCMessageExpr(dyn_cast<Expr>(Receiver),
+ MsgExpr = new (Context) ObjCMessageExpr(*Context, dyn_cast<Expr>(Receiver),
PDecl->getSetterName(), PDecl->getType(),
PDecl->getSetterMethodDecl(),
SourceLocation(), SourceLocation(),
@@ -1178,7 +1174,7 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) {
// This allows us to handle chain/nested property getters.
Receiver = PropGetters[PRE];
}
- MsgExpr = new (Context) ObjCMessageExpr(dyn_cast<Expr>(Receiver),
+ MsgExpr = new (Context) ObjCMessageExpr(*Context, dyn_cast<Expr>(Receiver),
PDecl->getGetterName(), PDecl->getType(),
PDecl->getGetterMethodDecl(),
SourceLocation(), SourceLocation(),
@@ -1209,14 +1205,15 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) {
}
Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
- SourceLocation OrigStart) {
+ SourceLocation OrigStart,
+ bool &replaced) {
ObjCIvarDecl *D = IV->getDecl();
const Expr *BaseExpr = IV->getBase();
if (CurMethodDef) {
- if (BaseExpr->getType()->isObjCObjectPointerType() &&
- isa<DeclRefExpr>(BaseExpr)) {
+ if (BaseExpr->getType()->isObjCObjectPointerType()) {
ObjCInterfaceType *iFaceDecl =
dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
+ assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null");
// lookup which class implements the instance variable.
ObjCInterfaceDecl *clsDeclared = 0;
iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
@@ -1226,7 +1223,7 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
// Synthesize an explicit cast to gain access to the ivar.
std::string RecName = clsDeclared->getIdentifier()->getName();
RecName += "_IMPL";
- IdentifierInfo *II = &Context->Idents.get(RecName.c_str());
+ IdentifierInfo *II = &Context->Idents.get(RecName);
RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
SourceLocation(), II);
assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
@@ -1238,17 +1235,16 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
IV->getBase()->getLocEnd(),
castExpr);
+ replaced = true;
if (IV->isFreeIvar() &&
CurMethodDef->getClassInterface() == iFaceDecl->getDecl()) {
MemberExpr *ME = new (Context) MemberExpr(PE, true, D,
IV->getLocation(),
D->getType());
- ReplaceStmt(IV, ME);
// delete IV; leak for now, see RewritePropertySetter() usage for more info.
return ME;
}
-
- ReplaceStmt(IV->getBase(), PE);
+ // Get the new text
// Cannot delete IV->getBase(), since PE points to it.
// Replace the old base with the cast. This is important when doing
// embedded rewrites. For example, [newInv->_container addObject:0].
@@ -1272,7 +1268,7 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
// Synthesize an explicit cast to gain access to the ivar.
std::string RecName = clsDeclared->getIdentifier()->getName();
RecName += "_IMPL";
- IdentifierInfo *II = &Context->Idents.get(RecName.c_str());
+ IdentifierInfo *II = &Context->Idents.get(RecName);
RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
SourceLocation(), II);
assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
@@ -1283,7 +1279,7 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
// Don't forget the parens to enforce the proper binding.
ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
IV->getBase()->getLocEnd(), castExpr);
- ReplaceStmt(IV->getBase(), PE);
+ replaced = true;
// Cannot delete IV->getBase(), since PE points to it.
// Replace the old base with the cast. This is important when doing
// embedded rewrites. For example, [newInv->_container addObject:0].
@@ -1294,6 +1290,28 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
return IV;
}
+Stmt *RewriteObjC::RewriteObjCNestedIvarRefExpr(Stmt *S, bool &replaced) {
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
+ CI != E; ++CI) {
+ if (*CI) {
+ Stmt *newStmt = RewriteObjCNestedIvarRefExpr(*CI, replaced);
+ if (newStmt)
+ *CI = newStmt;
+ }
+ }
+ if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) {
+ SourceRange OrigStmtRange = S->getSourceRange();
+ Stmt *newStmt = RewriteObjCIvarRefExpr(IvarRefExpr, OrigStmtRange.getBegin(),
+ replaced);
+ return newStmt;
+ }
+ if (ObjCMessageExpr *MsgRefExpr = dyn_cast<ObjCMessageExpr>(S)) {
+ Stmt *newStmt = SynthMessageExpr(MsgRefExpr);
+ return newStmt;
+ }
+ return S;
+}
+
/// SynthCountByEnumWithState - To print:
/// ((unsigned int (*)
/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
@@ -1326,7 +1344,7 @@ Stmt *RewriteObjC::RewriteBreakStmt(BreakStmt *S) {
SourceLocation startLoc = S->getLocStart();
buf = "goto __break_label_";
buf += utostr(ObjCBcLabelNo.back());
- ReplaceText(startLoc, strlen("break"), buf.c_str(), buf.size());
+ ReplaceText(startLoc, strlen("break"), buf);
return 0;
}
@@ -1343,7 +1361,7 @@ Stmt *RewriteObjC::RewriteContinueStmt(ContinueStmt *S) {
SourceLocation startLoc = S->getLocStart();
buf = "goto __continue_label_";
buf += utostr(ObjCBcLabelNo.back());
- ReplaceText(startLoc, strlen("continue"), buf.c_str(), buf.size());
+ ReplaceText(startLoc, strlen("continue"), buf);
return 0;
}
@@ -1442,8 +1460,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
startCollectionBuf += 3;
// Replace: "for (type element in" with string constructed thus far.
- ReplaceText(startLoc, startCollectionBuf - startBuf,
- buf.c_str(), buf.size());
+ ReplaceText(startLoc, startCollectionBuf - startBuf, buf);
// Replace ')' in for '(' type elem in collection ')' with ';'
SourceLocation rightParenLoc = S->getRParenLoc();
const char *rparenBuf = SM->getCharacterData(rightParenLoc);
@@ -1484,7 +1501,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
buf += elementTypeAsString;
buf += ")enumState.itemsPtr[counter++];";
// Replace ')' in for '(' type elem in collection ')' with all of these.
- ReplaceText(lparenLoc, 1, buf.c_str(), buf.size());
+ ReplaceText(lparenLoc, 1, buf);
/// __continue_label: ;
/// } while (counter < limit);
@@ -1525,7 +1542,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
// FIXME: If this should support Obj-C++, support CXXTryStmt
if (isa<CompoundStmt>(S->getBody())) {
SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(1);
- InsertText(endBodyLoc, buf.c_str(), buf.size());
+ InsertText(endBodyLoc, buf);
} else {
/* Need to treat single statements specially. For example:
*
@@ -1538,7 +1555,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
const char *semiBuf = strchr(stmtBuf, ';');
assert(semiBuf && "Can't find ';'");
SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(semiBuf-stmtBuf+1);
- InsertText(endBodyLoc, buf.c_str(), buf.size());
+ InsertText(endBodyLoc, buf);
}
Stmts.pop_back();
ObjCBcLabelNo.pop_back();
@@ -1562,7 +1579,7 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
buf = "objc_sync_enter((id)";
const char *lparenBuf = startBuf;
while (*lparenBuf != '(') lparenBuf++;
- ReplaceText(startLoc, lparenBuf-startBuf+1, buf.c_str(), buf.size());
+ ReplaceText(startLoc, lparenBuf-startBuf+1, buf);
// We can't use S->getSynchExpr()->getLocEnd() to find the end location, since
// the sync expression is typically a message expression that's already
// been rewritten! (which implies the SourceLocation's are invalid).
@@ -1578,7 +1595,7 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
buf += "id volatile _rethrow = 0;\n";
buf += "objc_exception_try_enter(&_stack);\n";
buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
- ReplaceText(rparenLoc, 1, buf.c_str(), buf.size());
+ ReplaceText(rparenLoc, 1, buf);
startLoc = S->getSynchBody()->getLocEnd();
startBuf = SM->getCharacterData(startLoc);
@@ -1607,7 +1624,7 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
buf += "}\n";
buf += "}";
- ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size());
+ ReplaceText(lastCurlyLoc, 1, buf);
bool hasReturns = false;
HasReturnStmts(S->getSynchBody(), hasReturns);
@@ -1663,8 +1680,8 @@ void RewriteObjC::RewriteTryReturnStmts(Stmt *S) {
std::string buf;
buf = "{ objc_exception_try_exit(&_stack); return";
- ReplaceText(startLoc, 6, buf.c_str(), buf.size());
- InsertText(onePastSemiLoc, "}", 1);
+ ReplaceText(startLoc, 6, buf);
+ InsertText(onePastSemiLoc, "}");
}
return;
}
@@ -1689,8 +1706,8 @@ void RewriteObjC::RewriteSyncReturnStmts(Stmt *S, std::string syncExitBuf) {
buf += syncExitBuf;
buf += " return";
- ReplaceText(startLoc, 6, buf.c_str(), buf.size());
- InsertText(onePastSemiLoc, "}", 1);
+ ReplaceText(startLoc, 6, buf);
+ InsertText(onePastSemiLoc, "}");
}
return;
}
@@ -1711,7 +1728,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
buf += "objc_exception_try_enter(&_stack);\n";
buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
- ReplaceText(startLoc, 4, buf.c_str(), buf.size());
+ ReplaceText(startLoc, 4, buf);
startLoc = S->getTryBody()->getLocEnd();
startBuf = SM->getCharacterData(startLoc);
@@ -1729,12 +1746,12 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
buf += " _rethrow = objc_exception_extract(&_stack);\n";
buf += " else { /* @catch continue */";
- InsertText(startLoc, buf.c_str(), buf.size());
+ InsertText(startLoc, buf);
} else { /* no catch list */
buf = "}\nelse {\n";
buf += " _rethrow = objc_exception_extract(&_stack);\n";
buf += "}";
- ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size());
+ ReplaceText(lastCurlyLoc, 1, buf);
}
bool sawIdTypedCatch = false;
Stmt *lastCatchBody = 0;
@@ -1767,7 +1784,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
QualType t = catchDecl->getType();
if (t == Context->getObjCIdType()) {
buf += "1) { ";
- ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size());
+ ReplaceText(startLoc, lParenLoc-startBuf+1, buf);
sawIdTypedCatch = true;
} else if (t->isObjCObjectPointerType()) {
QualType InterfaceTy = t->getPointeeType();
@@ -1777,7 +1794,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
buf += "objc_exception_match((struct objc_class *)objc_getClass(\"";
buf += cls->getDecl()->getNameAsString();
buf += "\"), (struct objc_object *)_caught)) { ";
- ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size());
+ ReplaceText(startLoc, lParenLoc-startBuf+1, buf);
}
}
// Now rewrite the body...
@@ -1789,10 +1806,9 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
assert((*rParenBuf == ')') && "bogus @catch paren location");
assert((*bodyBuf == '{') && "bogus @catch body location");
- buf = " = _caught;";
// Here we replace ") {" with "= _caught;" (which initializes and
// declares the @catch parameter).
- ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, buf.c_str(), buf.size());
+ ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, " = _caught;");
} else {
assert(false && "@catch rewrite bug");
}
@@ -1814,7 +1830,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
buf += "} } /* @catch end */\n";
if (!S->getFinallyStmt())
buf += "}\n";
- InsertText(bodyLoc, buf.c_str(), buf.size());
+ InsertText(bodyLoc, buf);
// Set lastCurlyLoc
lastCurlyLoc = lastCatchBody->getLocEnd();
@@ -1824,8 +1840,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
startBuf = SM->getCharacterData(startLoc);
assert((*startBuf == '@') && "bogus @finally start");
- buf = "/* @finally */";
- ReplaceText(startLoc, 8, buf.c_str(), buf.size());
+ ReplaceText(startLoc, 8, "/* @finally */");
Stmt *body = finalStmt->getFinallyBody();
SourceLocation startLoc = body->getLocStart();
@@ -1836,11 +1851,9 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
"bogus @finally body location");
startLoc = startLoc.getFileLocWithOffset(1);
- buf = " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
- InsertText(startLoc, buf.c_str(), buf.size());
+ InsertText(startLoc, " if (!_rethrow) objc_exception_try_exit(&_stack);\n");
endLoc = endLoc.getFileLocWithOffset(-1);
- buf = " if (_rethrow) objc_exception_throw(_rethrow);\n";
- InsertText(endLoc, buf.c_str(), buf.size());
+ InsertText(endLoc, " if (_rethrow) objc_exception_throw(_rethrow);\n");
// Set lastCurlyLoc
lastCurlyLoc = body->getLocEnd();
@@ -1852,7 +1865,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
buf += " if (_rethrow) objc_exception_throw(_rethrow);\n";
buf += "}";
- ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size());
+ ReplaceText(lastCurlyLoc, 1, buf);
// Now check for any return/continue/go statements within the @try.
// The implicit finally clause won't called if the @try contains any
@@ -1864,8 +1877,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
}
// Now emit the final closing curly brace...
lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1);
- buf = " } /* @try scope end */\n";
- InsertText(lastCurlyLoc, buf.c_str(), buf.size());
+ InsertText(lastCurlyLoc, " } /* @try scope end */\n");
return 0;
}
@@ -1897,13 +1909,12 @@ Stmt *RewriteObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) {
// handle "@ throw" correctly.
const char *wBuf = strchr(startBuf, 'w');
assert((*wBuf == 'w') && "@throw: can't find 'w'");
- ReplaceText(startLoc, wBuf-startBuf+1, buf.c_str(), buf.size());
+ ReplaceText(startLoc, wBuf-startBuf+1, buf);
const char *semiBuf = strchr(startBuf, ';');
assert((*semiBuf == ';') && "@throw: can't find ';'");
SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf);
- buf = ");";
- ReplaceText(semiLoc, 1, buf.c_str(), buf.size());
+ ReplaceText(semiLoc, 1, ");");
return 0;
}
@@ -1991,7 +2002,17 @@ static void scanToNextArgument(const char *&argRef) {
}
bool RewriteObjC::needToScanForQualifiers(QualType T) {
- return T->isObjCQualifiedIdType() || T->isObjCQualifiedInterfaceType();
+ if (T->isObjCQualifiedIdType())
+ return true;
+ if (const PointerType *PT = T->getAs<PointerType>()) {
+ if (PT->getPointeeType()->isObjCQualifiedIdType())
+ return true;
+ }
+ if (T->isObjCObjectPointerType()) {
+ T = T->getPointeeType();
+ return T->isObjCQualifiedInterfaceType();
+ }
+ return false;
}
void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) {
@@ -2018,8 +2039,8 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) {
SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-startBuf);
SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-startBuf+1);
// Comment out the protocol references.
- InsertText(LessLoc, "/*", 2);
- InsertText(GreaterLoc, "*/", 2);
+ InsertText(LessLoc, "/*");
+ InsertText(GreaterLoc, "*/");
}
}
}
@@ -2063,8 +2084,8 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-endBuf);
SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-endBuf+1);
// Comment out the protocol references.
- InsertText(LessLoc, "/*", 2);
- InsertText(GreaterLoc, "*/", 2);
+ InsertText(LessLoc, "/*");
+ InsertText(GreaterLoc, "*/");
}
}
if (!proto)
@@ -2087,8 +2108,8 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
SourceLocation GreaterLoc =
Loc.getFileLocWithOffset(endRef-startFuncBuf+1);
// Comment out the protocol references.
- InsertText(LessLoc, "/*", 2);
- InsertText(GreaterLoc, "*/", 2);
+ InsertText(LessLoc, "/*");
+ InsertText(GreaterLoc, "*/");
}
startBuf = ++endBuf;
}
@@ -2102,6 +2123,42 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
}
}
+void RewriteObjC::RewriteTypeOfDecl(VarDecl *ND) {
+ QualType QT = ND->getType();
+ const Type* TypePtr = QT->getAs<Type>();
+ if (!isa<TypeOfExprType>(TypePtr))
+ return;
+ while (isa<TypeOfExprType>(TypePtr)) {
+ const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr);
+ QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType();
+ TypePtr = QT->getAs<Type>();
+ }
+ // FIXME. This will not work for multiple declarators; as in:
+ // __typeof__(a) b,c,d;
+ std::string TypeAsString(QT.getAsString());
+ SourceLocation DeclLoc = ND->getTypeSpecStartLoc();
+ const char *startBuf = SM->getCharacterData(DeclLoc);
+ if (ND->getInit()) {
+ std::string Name(ND->getNameAsString());
+ TypeAsString += " " + Name + " = ";
+ Expr *E = ND->getInit();
+ SourceLocation startLoc;
+ if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E))
+ startLoc = ECE->getLParenLoc();
+ else
+ startLoc = E->getLocStart();
+ startLoc = SM->getInstantiationLoc(startLoc);
+ const char *endBuf = SM->getCharacterData(startLoc);
+ ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString);
+ }
+ else {
+ SourceLocation X = ND->getLocEnd();
+ X = SM->getInstantiationLoc(X);
+ const char *endBuf = SM->getCharacterData(X);
+ ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString);
+ }
+}
+
// SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str);
void RewriteObjC::SynthSelGetUidFunctionDecl() {
IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName");
@@ -2126,6 +2183,19 @@ void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) {
RewriteObjCQualifiedInterfaceTypes(FD);
}
+static void RewriteBlockPointerType(std::string& Str, QualType Type) {
+ std::string TypeString(Type.getAsString());
+ const char *argPtr = TypeString.c_str();
+ if (!strchr(argPtr, '^')) {
+ Str += TypeString;
+ return;
+ }
+ while (*argPtr) {
+ Str += (*argPtr == '^' ? '*' : *argPtr);
+ argPtr++;
+ }
+}
+
void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) {
SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
const FunctionType *funcType = FD->getType()->getAs<FunctionType>();
@@ -2140,13 +2210,12 @@ void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) {
unsigned numArgs = proto->getNumArgs();
for (unsigned i = 0; i < numArgs; i++) {
QualType ArgType = proto->getArgType(i);
- FdStr += ArgType.getAsString();
-
+ RewriteBlockPointerType(FdStr, ArgType);
if (i+1 < numArgs)
FdStr += ", ";
}
FdStr += ");\n";
- InsertText(FunLocStart, FdStr.c_str(), FdStr.size());
+ InsertText(FunLocStart, FdStr);
CurFunctionDeclToDeclareForBlock = 0;
}
@@ -2330,7 +2399,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
Preamble += utostr(Exp->getString()->getByteLength()) + "};\n";
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
- &Context->Idents.get(S.c_str()), strType, 0,
+ &Context->Idents.get(S), strType, 0,
VarDecl::Static);
DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, strType, SourceLocation());
Expr *Unop = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf,
@@ -2380,7 +2449,7 @@ QualType RewriteObjC::getSuperStructType() {
/*Mutable=*/false));
}
- SuperStructDecl->completeDefinition(*Context);
+ SuperStructDecl->completeDefinition();
}
return Context->getTagDeclType(SuperStructDecl);
}
@@ -2411,7 +2480,7 @@ QualType RewriteObjC::getConstantStringStructType() {
/*Mutable=*/true));
}
- ConstantStringDecl->completeDefinition(*Context);
+ ConstantStringDecl->completeDefinition();
}
return Context->getTagDeclType(ConstantStringDecl);
}
@@ -2871,7 +2940,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
if ((CDecl->isForwardDecl() || NumIvars == 0) &&
(!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) {
endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);
- ReplaceText(LocStart, endBuf-startBuf, Result.c_str(), Result.size());
+ ReplaceText(LocStart, endBuf-startBuf, Result);
return;
}
@@ -2913,10 +2982,10 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
endHeader++;
}
// rewrite the original header
- ReplaceText(LocStart, endHeader-startBuf, Result.c_str(), Result.size());
+ ReplaceText(LocStart, endHeader-startBuf, Result);
} else {
// rewrite the original header *without* disturbing the '{'
- ReplaceText(LocStart, cursor-startBuf, Result.c_str(), Result.size());
+ ReplaceText(LocStart, cursor-startBuf, Result);
}
if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) {
Result = "\n struct ";
@@ -2928,7 +2997,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
// insert the super class structure definition.
SourceLocation OnePastCurly =
LocStart.getFileLocWithOffset(cursor-startBuf+1);
- InsertText(OnePastCurly, Result.c_str(), Result.size());
+ InsertText(OnePastCurly, Result);
}
cursor++; // past '{'
@@ -2946,26 +3015,26 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
!strncmp(cursor, "private", strlen("private")) ||
!strncmp(cursor, "package", strlen("package")) ||
!strncmp(cursor, "protected", strlen("protected")))
- InsertText(atLoc, "// ", 3);
+ InsertText(atLoc, "// ");
}
// FIXME: If there are cases where '<' is used in ivar declaration part
// of user code, then scan the ivar list and use needToScanForQualifiers
// for type checking.
else if (*cursor == '<') {
SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
- InsertText(atLoc, "/* ", 3);
+ InsertText(atLoc, "/* ");
cursor = strchr(cursor, '>');
cursor++;
atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
- InsertText(atLoc, " */", 3);
+ InsertText(atLoc, " */");
} else if (*cursor == '^') { // rewrite block specifier.
SourceLocation caretLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
- ReplaceText(caretLoc, 1, "*", 1);
+ ReplaceText(caretLoc, 1, "*");
}
cursor++;
}
// Don't forget to add a ';'!!
- InsertText(LocEnd.getFileLocWithOffset(1), ";", 1);
+ InsertText(LocEnd.getFileLocWithOffset(1), ";");
} else { // we don't have any instance variables - insert super struct.
endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);
Result += " {\n struct ";
@@ -2973,7 +3042,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
Result += "_IMPL ";
Result += RCDecl->getNameAsString();
Result += "_IVARS;\n};\n";
- ReplaceText(LocStart, endBuf-startBuf, Result.c_str(), Result.size());
+ ReplaceText(LocStart, endBuf-startBuf, Result);
}
// Mark this struct as having been generated.
if (!ObjCSynthesizedStructs.insert(CDecl))
@@ -3805,7 +3874,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
// Create local declarations to avoid rewriting all closure decl ref exprs.
// First, emit a declaration for all "by ref" decls.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
S += " ";
std::string Name = (*I)->getNameAsString();
@@ -3816,7 +3885,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
}
// Next, emit a declaration for all "by copy" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
S += " ";
std::string Name = (*I)->getNameAsString();
@@ -3861,7 +3930,7 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
S += (*I)->getNameAsString();
S += ", (void*)src->";
S += (*I)->getNameAsString();
- if (BlockByRefDecls.count((*I)))
+ if (BlockByRefDeclsPtrSet.count((*I)))
S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
else
S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);";
@@ -3877,7 +3946,7 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
E = ImportedBlockDecls.end(); I != E; ++I) {
S += "_Block_object_dispose((void*)src->";
S += (*I)->getNameAsString();
- if (BlockByRefDecls.count((*I)))
+ if (BlockByRefDeclsPtrSet.count((*I)))
S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
else
S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);";
@@ -3901,7 +3970,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
if (BlockDeclRefs.size()) {
// Output all "by copy" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
S += " ";
std::string FieldName = (*I)->getNameAsString();
@@ -3927,7 +3996,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
S += FieldName + ";\n";
}
// Output all "by ref" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
S += " ";
std::string FieldName = (*I)->getNameAsString();
@@ -3966,7 +4035,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
Constructor += " Desc = desc;\n";
// Initialize all "by copy" arguments.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
std::string Name = (*I)->getNameAsString();
Constructor += " ";
@@ -3977,7 +4046,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
Constructor += Name + ";\n";
}
// Initialize all "by ref" arguments.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
std::string Name = (*I)->getNameAsString();
Constructor += " ";
@@ -4047,23 +4116,25 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag);
- InsertText(FunLocStart, CI.c_str(), CI.size());
+ InsertText(FunLocStart, CI);
std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag);
- InsertText(FunLocStart, CF.c_str(), CF.size());
+ InsertText(FunLocStart, CF);
if (ImportedBlockDecls.size()) {
std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag);
- InsertText(FunLocStart, HF.c_str(), HF.size());
+ InsertText(FunLocStart, HF);
}
std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName,
ImportedBlockDecls.size() > 0);
- InsertText(FunLocStart, BD.c_str(), BD.size());
+ InsertText(FunLocStart, BD);
BlockDeclRefs.clear();
BlockByRefDecls.clear();
+ BlockByRefDeclsPtrSet.clear();
BlockByCopyDecls.clear();
+ BlockByCopyDeclsPtrSet.clear();
BlockCallExprs.clear();
ImportedBlockDecls.clear();
}
@@ -4078,17 +4149,23 @@ void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
SynthesizeBlockLiterals(FunLocStart, FuncName);
}
-void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
- //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n");
- //SourceLocation FunLocStart = MD->getLocStart();
- // FIXME: This hack works around a bug in Rewrite.InsertText().
- SourceLocation FunLocStart = MD->getLocStart().getFileLocWithOffset(-1);
- std::string FuncName = MD->getSelector().getAsString();
+static void BuildUniqueMethodName(std::string &Name,
+ ObjCMethodDecl *MD) {
+ ObjCInterfaceDecl *IFace = MD->getClassInterface();
+ Name = IFace->getNameAsCString();
+ Name += "__" + MD->getSelector().getAsString();
// Convert colons to underscores.
std::string::size_type loc = 0;
- while ((loc = FuncName.find(":", loc)) != std::string::npos)
- FuncName.replace(loc, 1, "_");
+ while ((loc = Name.find(":", loc)) != std::string::npos)
+ Name.replace(loc, 1, "_");
+}
+void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
+ //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n");
+ //SourceLocation FunLocStart = MD->getLocStart();
+ SourceLocation FunLocStart = MD->getLocStart();
+ std::string FuncName;
+ BuildUniqueMethodName(FuncName, MD);
SynthesizeBlockLiterals(FunLocStart, FuncName.c_str());
}
@@ -4304,11 +4381,9 @@ void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) {
std::string TypeAsString = "(";
TypeAsString += QT.getAsString();
TypeAsString += ")";
- ReplaceText(LocStart, endBuf-startBuf+1,
- TypeAsString.c_str(), TypeAsString.size());
+ ReplaceText(LocStart, endBuf-startBuf+1, TypeAsString);
return;
}
-
// advance the location to startArgList.
const char *argPtr = startBuf;
@@ -4317,7 +4392,7 @@ void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) {
case '^':
// Replace the '^' with '*'.
LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf);
- ReplaceText(LocStart, 1, "*", 1);
+ ReplaceText(LocStart, 1, "*");
break;
}
}
@@ -4346,7 +4421,7 @@ void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
case '^':
// Replace the '^' with '*'.
DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList);
- ReplaceText(DeclLoc, 1, "*", 1);
+ ReplaceText(DeclLoc, 1, "*");
break;
case '(':
parenCount++;
@@ -4427,7 +4502,7 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
if (*startBuf == '^') {
// Replace the '^' with '*', computing a negative offset.
DeclLoc = DeclLoc.getFileLocWithOffset(startBuf-endBuf);
- ReplaceText(DeclLoc, 1, "*", 1);
+ ReplaceText(DeclLoc, 1, "*");
}
if (PointerTypeTakesAnyBlockArguments(DeclT)) {
// Replace the '^' with '*' for arguments.
@@ -4438,7 +4513,7 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
while (argListBegin < argListEnd) {
if (*argListBegin == '^') {
SourceLocation CaretLoc = DeclLoc.getFileLocWithOffset(argListBegin-startBuf);
- ReplaceText(CaretLoc, 1, "*", 1);
+ ReplaceText(CaretLoc, 1, "*");
}
argListBegin++;
}
@@ -4563,7 +4638,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null");
FunLocStart = CurMethodDef->getLocStart();
}
- InsertText(FunLocStart, ByrefType.c_str(), ByrefType.size());
+ InsertText(FunLocStart, ByrefType);
if (Ty.isObjCGCWeak()) {
flag |= BLOCK_FIELD_IS_WEAK;
isa = 1;
@@ -4579,7 +4654,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
flag |= BLOCK_FIELD_IS_OBJECT;
std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag);
if (!HF.empty())
- InsertText(FunLocStart, HF.c_str(), HF.size());
+ InsertText(FunLocStart, HF);
}
// struct __Block_byref_ND ND =
@@ -4592,10 +4667,12 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
Name = ND->getNameAsString();
ByrefType.clear();
RewriteByRefString(ByrefType, Name, ND);
+ std::string ForwardingCastType("(");
+ ForwardingCastType += ByrefType + " *)";
if (!hasInit) {
ByrefType += " " + Name + " = {(void*)";
ByrefType += utostr(isa);
- ByrefType += ", &" + Name + ", ";
+ ByrefType += "," + ForwardingCastType + "&" + Name + ", ";
ByrefType += utostr(flags);
ByrefType += ", ";
ByrefType += "sizeof(";
@@ -4608,8 +4685,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
ByrefType += utostr(flag);
}
ByrefType += "};\n";
- ReplaceText(DeclLoc, endBuf-startBuf+Name.size(),
- ByrefType.c_str(), ByrefType.size());
+ ReplaceText(DeclLoc, endBuf-startBuf+Name.size(), ByrefType);
}
else {
SourceLocation startLoc;
@@ -4624,7 +4700,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
ByrefType += " " + Name;
ByrefType += " = {(void*)";
ByrefType += utostr(isa);
- ByrefType += ", &" + Name + ", ";
+ ByrefType += "," + ForwardingCastType + "&" + Name + ", ";
ByrefType += utostr(flags);
ByrefType += ", ";
ByrefType += "sizeof(";
@@ -4637,8 +4713,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
ByrefType += utostr(flag);
ByrefType += ", ";
}
- ReplaceText(DeclLoc, endBuf-startBuf,
- ByrefType.c_str(), ByrefType.size());
+ ReplaceText(DeclLoc, endBuf-startBuf, ByrefType);
// Complete the newly synthesized compound expression by inserting a right
// curly brace before the end of the declaration.
@@ -4654,7 +4729,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
SourceLocation semiLoc =
startLoc.getFileLocWithOffset(semiBuf-startBuf);
- InsertText(semiLoc, "}", 1);
+ InsertText(semiLoc, "}");
}
return;
}
@@ -4665,12 +4740,19 @@ void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {
if (BlockDeclRefs.size()) {
// Unique all "by copy" declarations.
for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
- if (!BlockDeclRefs[i]->isByRef())
- BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl());
+ if (!BlockDeclRefs[i]->isByRef()) {
+ if (!BlockByCopyDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) {
+ BlockByCopyDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl());
+ BlockByCopyDecls.push_back(BlockDeclRefs[i]->getDecl());
+ }
+ }
// Unique all "by ref" declarations.
for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
if (BlockDeclRefs[i]->isByRef()) {
- BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl());
+ if (!BlockByRefDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) {
+ BlockByRefDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl());
+ BlockByRefDecls.push_back(BlockDeclRefs[i]->getDecl());
+ }
}
// Find any imported blocks...they will need special attention.
for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
@@ -4699,13 +4781,9 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
if (CurFunctionDef)
FuncName = CurFunctionDef->getNameAsString();
- else if (CurMethodDef) {
- FuncName = CurMethodDef->getSelector().getAsString();
- // Convert colons to underscores.
- std::string::size_type loc = 0;
- while ((loc = FuncName.find(":", loc)) != std::string::npos)
- FuncName.replace(loc, 1, "_");
- } else if (GlobalVarDecl)
+ else if (CurMethodDef)
+ BuildUniqueMethodName(FuncName, CurMethodDef);
+ else if (GlobalVarDecl)
FuncName = std::string(GlobalVarDecl->getNameAsString());
std::string BlockNumber = utostr(Blocks.size()-1);
@@ -4752,7 +4830,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
if (BlockDeclRefs.size()) {
Expr *Exp;
// Output all "by copy" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
if (isObjCType((*I)->getType())) {
// FIXME: Conform to ABI ([[obj retain] autorelease]).
@@ -4770,13 +4848,25 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
InitExprs.push_back(Exp);
}
// Output all "by ref" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
+ ValueDecl *ND = (*I);
+ std::string Name(ND->getNameAsString());
+ std::string RecName;
+ RewriteByRefString(RecName, Name, ND);
+ IdentifierInfo *II = &Context->Idents.get(RecName.c_str()
+ + sizeof("struct"));
+ RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ SourceLocation(), II);
+ assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl");
+ QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
+
FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString());
Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
Exp = new (Context) UnaryOperator(Exp, UnaryOperator::AddrOf,
Context->getPointerType(Exp->getType()),
SourceLocation());
+ Exp = NoTypeInfoCStyleCastExpr(Context, castT, CastExpr::CK_Unknown, Exp);
InitExprs.push_back(Exp);
}
}
@@ -4798,7 +4888,9 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
NewRep);
BlockDeclRefs.clear();
BlockByRefDecls.clear();
+ BlockByRefDeclsPtrSet.clear();
BlockByCopyDecls.clear();
+ BlockByCopyDeclsPtrSet.clear();
ImportedBlockDecls.clear();
return NewRep;
}
@@ -4843,7 +4935,21 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
CI != E; ++CI)
if (*CI) {
- Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(*CI);
+ Stmt *newStmt;
+ Stmt *S = (*CI);
+ if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) {
+ Expr *OldBase = IvarRefExpr->getBase();
+ bool replaced = false;
+ newStmt = RewriteObjCNestedIvarRefExpr(S, replaced);
+ if (replaced) {
+ if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(newStmt))
+ ReplaceStmt(OldBase, IRE->getBase());
+ else
+ ReplaceStmt(S, newStmt);
+ }
+ }
+ else
+ newStmt = RewriteFunctionBodyOrGlobalInitializer(S);
if (newStmt)
*CI = newStmt;
}
@@ -4865,9 +4971,6 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
return RewriteAtEncode(AtEncode);
- if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S))
- return RewriteObjCIvarRefExpr(IvarRefExpr, OrigStmtRange.getBegin());
-
if (ObjCPropertyRefExpr *PropRefExpr = dyn_cast<ObjCPropertyRefExpr>(S)) {
BinaryOperator *BinOp = PropSetters[PropRefExpr];
if (BinOp) {
@@ -4995,7 +5098,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
RewriteBlockPointerDecl(ND);
else if (ND->getType()->isFunctionPointerType())
CheckFunctionPointerDecl(ND->getType(), ND);
- if (VarDecl *VD = dyn_cast<VarDecl>(SD))
+ if (VarDecl *VD = dyn_cast<VarDecl>(SD)) {
if (VD->hasAttr<BlocksAttr>()) {
static unsigned uniqueByrefDeclCount = 0;
assert(!BlockByRefDeclNo.count(ND) &&
@@ -5003,6 +5106,9 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
BlockByRefDeclNo[ND] = uniqueByrefDeclCount++;
RewriteByRefVar(VD);
}
+ else
+ RewriteTypeOfDecl(VD);
+ }
}
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
@@ -5191,11 +5297,6 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
}
void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
- // Get the top-level buffer that this corresponds to.
-
- // Rewrite tabs if we care.
- //RewriteTabs();
-
if (Diags.hasErrorOccurred())
return;
@@ -5207,8 +5308,7 @@ void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
E = ProtocolExprDecls.end(); I != E; ++I)
RewriteObjCProtocolMetaData(*I, "", "", Preamble);
- InsertText(SM->getLocForStartOfFile(MainFileID),
- Preamble.c_str(), Preamble.size(), false);
+ InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false);
if (ClassImplementation.size() || CategoryImplementation.size())
RewriteImplementations();
@@ -5219,7 +5319,7 @@ void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
//printf("Changed:\n");
*OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
} else {
- fprintf(stderr, "No changes\n");
+ llvm::errs() << "No changes\n";
}
if (ClassImplementation.size() || CategoryImplementation.size() ||
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 83b4542caa25..9ec5ffe1c353 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -104,11 +104,6 @@ void TextDiagnosticPrinter::HighlightRange(const SourceRange &R,
if (StartColNo) --StartColNo; // Zero base the col #.
}
- // Pick the first non-whitespace column.
- while (StartColNo < SourceLine.size() &&
- (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t'))
- ++StartColNo;
-
// Compute the column number of the end.
unsigned EndColNo = CaretLine.size();
if (EndLineNo == LineNo) {
@@ -123,16 +118,25 @@ void TextDiagnosticPrinter::HighlightRange(const SourceRange &R,
}
}
+ assert(StartColNo <= EndColNo && "Invalid range!");
+
+ // Pick the first non-whitespace column.
+ while (StartColNo < SourceLine.size() &&
+ (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t'))
+ ++StartColNo;
+
// Pick the last non-whitespace column.
- if (EndColNo <= SourceLine.size())
- while (EndColNo-1 &&
- (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
- --EndColNo;
- else
+ if (EndColNo > SourceLine.size())
EndColNo = SourceLine.size();
+ while (EndColNo-1 &&
+ (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
+ --EndColNo;
+
+ // If the start/end passed each other, then we are trying to highlight a range
+ // that just exists in whitespace, which must be some sort of other bug.
+ assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
// Fill the range with ~'s.
- assert(StartColNo <= EndColNo && "Invalid range!");
for (unsigned i = StartColNo; i < EndColNo; ++i)
CaretLine[i] = '~';
}
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index e27060295a81..b59c7e824bf1 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -462,7 +462,7 @@ _mm_cvtss_f32(__m128 a)
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_loadh_pi(__m128 a, __m64 const *p)
+_mm_loadh_pi(__m128 a, const __m64 *p)
{
__m128 b;
b[0] = *(float*)p;
@@ -471,7 +471,7 @@ _mm_loadh_pi(__m128 a, __m64 const *p)
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_loadl_pi(__m128 a, __m64 const *p)
+_mm_loadl_pi(__m128 a, const __m64 *p)
{
__m128 b;
b[0] = *(float*)p;
@@ -480,13 +480,13 @@ _mm_loadl_pi(__m128 a, __m64 const *p)
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_load_ss(float *p)
+_mm_load_ss(const float *p)
{
return (__m128){ *p, 0, 0, 0 };
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_load1_ps(float *p)
+_mm_load1_ps(const float *p)
{
return (__m128){ *p, *p, *p, *p };
}
@@ -494,19 +494,19 @@ _mm_load1_ps(float *p)
#define _mm_load_ps1(p) _mm_load1_ps(p)
static inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_load_ps(float *p)
+_mm_load_ps(const float *p)
{
return *(__m128*)p;
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_loadu_ps(float *p)
+_mm_loadu_ps(const float *p)
{
return __builtin_ia32_loadups(p);
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_loadr_ps(float *p)
+_mm_loadr_ps(const float *p)
{
__m128 a = _mm_load_ps(p);
return __builtin_shufflevector(a, a, 3, 2, 1, 0);
@@ -895,7 +895,7 @@ do { \
(row0) = _mm_movelh_ps(tmp0, tmp2); \
(row1) = _mm_movehl_ps(tmp2, tmp0); \
(row2) = _mm_movelh_ps(tmp1, tmp3); \
- (row3) = _mm_movelh_ps(tmp3, tmp1); \
+ (row3) = _mm_movehl_ps(tmp3, tmp1); \
} while (0)
/* Ugly hack for backwards-compatibility (compatible with gcc) */
diff --git a/lib/Index/Makefile b/lib/Index/Makefile
index 7dee87f3b6bb..9d33a2d175e3 100644
--- a/lib/Index/Makefile
+++ b/lib/Index/Makefile
@@ -16,7 +16,6 @@ include $(LEVEL)/Makefile.config
LIBRARYNAME := clangIndex
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
ifeq ($(ARCH),PowerPC)
CXXFLAGS += -maltivec
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index afd1ba885167..3207062ccadd 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -985,10 +985,11 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
if (CurPtr == BufferEnd+1) { --CurPtr; break; }
} while (C != '\n' && C != '\r');
- // Found but did not consume the newline.
- if (PP && PP->HandleComment(Result,
- SourceRange(getSourceLocation(BufferPtr),
- getSourceLocation(CurPtr)))) {
+ // Found but did not consume the newline. Notify comment handlers about the
+ // comment unless we're in a #if 0 block.
+ if (PP && !isLexingRawMode() &&
+ PP->HandleComment(Result, SourceRange(getSourceLocation(BufferPtr),
+ getSourceLocation(CurPtr)))) {
BufferPtr = CurPtr;
return true; // A token has to be returned.
}
@@ -1235,9 +1236,10 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
C = *CurPtr++;
}
- if (PP && PP->HandleComment(Result,
- SourceRange(getSourceLocation(BufferPtr),
- getSourceLocation(CurPtr)))) {
+ // Notify comment handlers about the comment unless we're in a #if 0 block.
+ if (PP && !isLexingRawMode() &&
+ PP->HandleComment(Result, SourceRange(getSourceLocation(BufferPtr),
+ getSourceLocation(CurPtr)))) {
BufferPtr = CurPtr;
return true; // A token has to be returned.
}
diff --git a/lib/Lex/Makefile b/lib/Lex/Makefile
index a2437da812bd..509077017c2d 100644
--- a/lib/Lex/Makefile
+++ b/lib/Lex/Makefile
@@ -16,7 +16,6 @@ include $(LEVEL)/Makefile.config
LIBRARYNAME := clangLex
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
ifeq ($(ARCH),PowerPC)
CXXFLAGS += -maltivec
diff --git a/lib/Lex/PPCaching.cpp b/lib/Lex/PPCaching.cpp
index 7c3780ffc0ac..6aeb6fa3a2f7 100644
--- a/lib/Lex/PPCaching.cpp
+++ b/lib/Lex/PPCaching.cpp
@@ -91,7 +91,7 @@ const Token &Preprocessor::PeekAhead(unsigned N) {
void Preprocessor::AnnotatePreviousCachedTokens(const Token &Tok) {
assert(Tok.isAnnotation() && "Expected annotation token");
assert(CachedLexPos != 0 && "Expected to have some cached tokens");
- assert(CachedTokens[CachedLexPos-1].getLocation() == Tok.getAnnotationEndLoc()
+ assert(CachedTokens[CachedLexPos-1].getLastLoc() == Tok.getAnnotationEndLoc()
&& "The annotation should be until the most recent cached token");
// Start from the end of the cached tokens list and look for the token
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index b0e784bcd96a..4803c5ab85d5 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -1514,18 +1514,21 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
// Check to see if this is the last token on the #if[n]def line.
CheckEndOfDirective(isIfndef ? "ifndef" : "ifdef");
+ IdentifierInfo *MII = MacroNameTok.getIdentifierInfo();
+ MacroInfo *MI = getMacroInfo(MII);
+
if (CurPPLexer->getConditionalStackDepth() == 0) {
- // If the start of a top-level #ifdef, inform MIOpt.
- if (!ReadAnyTokensBeforeDirective) {
+ // If the start of a top-level #ifdef and if the macro is not defined,
+ // inform MIOpt that this might be the start of a proper include guard.
+ // Otherwise it is some other form of unknown conditional which we can't
+ // handle.
+ if (!ReadAnyTokensBeforeDirective && MI == 0) {
assert(isIfndef && "#ifdef shouldn't reach here");
- CurPPLexer->MIOpt.EnterTopLevelIFNDEF(MacroNameTok.getIdentifierInfo());
+ CurPPLexer->MIOpt.EnterTopLevelIFNDEF(MII);
} else
CurPPLexer->MIOpt.EnterTopLevelConditional();
}
- IdentifierInfo *MII = MacroNameTok.getIdentifierInfo();
- MacroInfo *MI = getMacroInfo(MII);
-
// If there is a macro, process it.
if (MI) // Mark it used.
MI->setIsUsed(true);
@@ -1558,7 +1561,7 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
// If this condition is equivalent to #ifndef X, and if this is the first
// directive seen, handle it for the multiple-include optimization.
if (CurPPLexer->getConditionalStackDepth() == 0) {
- if (!ReadAnyTokensBeforeDirective && IfNDefMacro)
+ if (!ReadAnyTokensBeforeDirective && IfNDefMacro && ConditionalTrue)
CurPPLexer->MIOpt.EnterTopLevelIFNDEF(IfNDefMacro);
else
CurPPLexer->MIOpt.EnterTopLevelConditional();
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 13aeb88b1db0..b97ab2485d3d 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -19,6 +19,7 @@
#include "clang/Basic/FileManager.h"
#include "clang/Lex/LexDiagnostic.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstdio>
#include <ctime>
using namespace clang;
@@ -152,7 +153,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
MacroInfo *MI) {
if (Callbacks) Callbacks->MacroExpands(Identifier, MI);
- // If this is a macro exapnsion in the "#if !defined(x)" line for the file,
+ // If this is a macro expansion in the "#if !defined(x)" line for the file,
// then the macro could expand to different things in other contexts, we need
// to disable the optimization in this case.
if (CurPPLexer) CurPPLexer->MIOpt.ExpandedMacro();
@@ -627,7 +628,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
++NumBuiltinMacroExpanded;
- char TmpBuffer[100];
+ llvm::SmallString<128> TmpBuffer;
+ llvm::raw_svector_ostream OS(TmpBuffer);
// Set up the return result.
Tok.setIdentifierInfo(0);
@@ -652,9 +654,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
PresumedLoc PLoc = SourceMgr.getPresumedLoc(Loc);
// __LINE__ expands to a simple numeric value.
- sprintf(TmpBuffer, "%u", PLoc.getLine());
+ OS << PLoc.getLine();
Tok.setKind(tok::numeric_constant);
- CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
} else if (II == Ident__FILE__ || II == Ident__BASE_FILE__) {
// C99 6.10.8: "__FILE__: The presumed name of the current source file (a
// character string literal)". This can be affected by #line.
@@ -671,10 +672,11 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
}
// Escape this filename. Turn '\' -> '\\' '"' -> '\"'
- std::string FN = PLoc.getFilename();
- FN = '"' + Lexer::Stringify(FN) + '"';
+ llvm::SmallString<128> FN;
+ FN += PLoc.getFilename();
+ Lexer::Stringify(FN);
+ OS << '"' << FN.str() << '"';
Tok.setKind(tok::string_literal);
- CreateString(&FN[0], FN.size(), Tok, Tok.getLocation());
} else if (II == Ident__DATE__) {
if (!DATELoc.isValid())
ComputeDATE_TIME(DATELoc, TIMELoc, *this);
@@ -683,6 +685,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Tok.setLocation(SourceMgr.createInstantiationLoc(DATELoc, Tok.getLocation(),
Tok.getLocation(),
Tok.getLength()));
+ return;
} else if (II == Ident__TIME__) {
if (!TIMELoc.isValid())
ComputeDATE_TIME(DATELoc, TIMELoc, *this);
@@ -691,6 +694,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Tok.setLocation(SourceMgr.createInstantiationLoc(TIMELoc, Tok.getLocation(),
Tok.getLocation(),
Tok.getLength()));
+ return;
} else if (II == Ident__INCLUDE_LEVEL__) {
// Compute the presumed include depth of this token. This can be affected
// by GNU line markers.
@@ -702,9 +706,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc());
// __INCLUDE_LEVEL__ expands to a simple numeric value.
- sprintf(TmpBuffer, "%u", Depth);
+ OS << Depth;
Tok.setKind(tok::numeric_constant);
- CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
} else if (II == Ident__TIMESTAMP__) {
// MSVC, ICC, GCC, VisualAge C++ extension. The generated string should be
// of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime.
@@ -725,17 +728,13 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
} else {
Result = "??? ??? ?? ??:??:?? ????\n";
}
- TmpBuffer[0] = '"';
- unsigned Len = strlen(Result);
- memcpy(TmpBuffer+1, Result, Len-1); // Copy string without the newline.
- TmpBuffer[Len] = '"';
+ // Surround the string with " and strip the trailing newline.
+ OS << '"' << llvm::StringRef(Result, strlen(Result)-1) << '"';
Tok.setKind(tok::string_literal);
- CreateString(TmpBuffer, Len+1, Tok, Tok.getLocation());
} else if (II == Ident__COUNTER__) {
// __COUNTER__ expands to a simple numeric value.
- sprintf(TmpBuffer, "%u", CounterValue++);
+ OS << CounterValue++;
Tok.setKind(tok::numeric_constant);
- CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
} else if (II == Ident__has_feature ||
II == Ident__has_builtin) {
// The argument to these two builtins should be a parenthesized identifier.
@@ -770,9 +769,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Value = HasFeature(*this, FeatureII);
}
- sprintf(TmpBuffer, "%d", (int)Value);
+ OS << (int)Value;
Tok.setKind(tok::numeric_constant);
- CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
} else if (II == Ident__has_include ||
II == Ident__has_include_next) {
// The argument to these two builtins should be a parenthesized
@@ -784,10 +782,10 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
IsValid = EvaluateHasInclude(Value, Tok, II, *this);
else
IsValid = EvaluateHasIncludeNext(Value, Tok, II, *this);
- sprintf(TmpBuffer, "%d", (int)Value);
+ OS << (int)Value;
Tok.setKind(tok::numeric_constant);
- CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
} else {
assert(0 && "Unknown identifier!");
}
+ CreateString(OS.str().data(), OS.str().size(), Tok, Tok.getLocation());
}
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 5689baaac652..df0e702ab447 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -424,7 +424,7 @@ SourceLocation Preprocessor::AdvanceToTokenCharacter(SourceLocation TokStart,
// advanced by 3 should return the location of b, not of \\. One compounding
// detail of this is that the escape may be made by a trigraph.
if (!Lexer::isObviouslySimpleCharacter(*TokPtr))
- PhysOffset = Lexer::SkipEscapedNewLines(TokPtr)-TokPtr;
+ PhysOffset += Lexer::SkipEscapedNewLines(TokPtr)-TokPtr;
return TokStart.getFileLocWithOffset(PhysOffset);
}
diff --git a/lib/Makefile b/lib/Makefile
index d499ee555a38..538bf4394071 100755
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -9,7 +9,7 @@
LEVEL = ../../..
PARALLEL_DIRS = Headers Runtime Basic Lex Parse AST Sema CodeGen Analysis \
- Rewrite Frontend Index Driver
+ Checker Rewrite Frontend Index Driver
include $(LEVEL)/Makefile.common
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index 9e5f5a2ac098..4a699e7ad5e5 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -253,6 +253,11 @@ bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc,
return BadSpecifier(W, (TSW)TypeSpecWidth, PrevSpec, DiagID);
TypeSpecWidth = W;
TSWLoc = Loc;
+ if (TypeAltiVecVector && ((TypeSpecWidth == TSW_long) || (TypeSpecWidth == TSW_longlong))) {
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ DiagID = diag::warn_vector_long_decl_spec_combination;
+ return true;
+ }
return false;
}
@@ -289,6 +294,38 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
TypeRep = Rep;
TSTLoc = Loc;
TypeSpecOwned = Owned;
+ if (TypeAltiVecVector && (TypeSpecType == TST_double)) {
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ DiagID = diag::err_invalid_vector_double_decl_spec_combination;
+ return true;
+ }
+ return false;
+}
+
+bool DeclSpec::SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc,
+ const char *&PrevSpec, unsigned &DiagID) {
+ if (TypeSpecType != TST_unspecified) {
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ DiagID = diag::err_invalid_vector_decl_spec_combination;
+ return true;
+ }
+ TypeAltiVecVector = isAltiVecVector;
+ AltiVecLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc,
+ const char *&PrevSpec, unsigned &DiagID) {
+ if (!TypeAltiVecVector || (TypeSpecType != TST_unspecified)) {
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ DiagID = diag::err_invalid_pixel_decl_spec_combination;
+ return true;
+ }
+ TypeSpecType = TST_int;
+ TypeSpecSign = TSS_unsigned;
+ TypeSpecWidth = TSW_short;
+ TypeAltiVecPixel = isAltiVecPixel;
+ TSTLoc = Loc;
return false;
}
diff --git a/lib/Parse/Makefile b/lib/Parse/Makefile
index 5d69029edc1a..de16e3ea665a 100644
--- a/lib/Parse/Makefile
+++ b/lib/Parse/Makefile
@@ -14,7 +14,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangParse
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index b5ba8acafc8d..8aa69363beee 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -733,7 +733,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
if (TagName) {
Diag(Loc, diag::err_use_of_tag_name_without_tag)
- << Tok.getIdentifierInfo() << TagName
+ << Tok.getIdentifierInfo() << TagName << getLang().CPlusPlus
<< CodeModificationHint::CreateInsertion(Tok.getLocation(),TagName);
// Parse this as a tag as if the missing tag were present.
@@ -1029,6 +1029,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (DS.hasTypeSpecifier())
goto DoneWithDeclSpec;
+ // Check for need to substitute AltiVec keyword tokens.
+ if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
+ break;
+
// It has to be available as a typedef too!
TypeTy *TypeRep = Actions.getTypeName(*Tok.getIdentifierInfo(),
Tok.getLocation(), CurScope);
@@ -1270,6 +1274,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec,
DiagID);
break;
+ case tok::kw___vector:
+ isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
+ break;
+ case tok::kw___pixel:
+ isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID);
+ break;
// class-specifier:
case tok::kw_class:
@@ -1395,20 +1405,26 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
/// [OBJC] class-name objc-protocol-refs[opt] [TODO]
/// [OBJC] typedef-name objc-protocol-refs[opt] [TODO]
/// [C++0x] 'decltype' ( expression )
+/// [AltiVec] '__vector'
bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
const char *&PrevSpec,
unsigned &DiagID,
- const ParsedTemplateInfo &TemplateInfo) {
+ const ParsedTemplateInfo &TemplateInfo,
+ bool SuppressDeclarations) {
SourceLocation Loc = Tok.getLocation();
switch (Tok.getKind()) {
case tok::identifier: // foo::bar
+ // Check for need to substitute AltiVec keyword tokens.
+ if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
+ break;
+ // Fall through.
case tok::kw_typename: // typename foo::bar
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
if (TryAnnotateTypeOrScopeToken())
return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
- TemplateInfo);
+ TemplateInfo, SuppressDeclarations);
// Otherwise, not a type specifier.
return false;
case tok::coloncolon: // ::foo::bar
@@ -1420,7 +1436,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
// recurse to handle whatever we get.
if (TryAnnotateTypeOrScopeToken())
return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
- TemplateInfo);
+ TemplateInfo, SuppressDeclarations);
// Otherwise, not a type specifier.
return false;
@@ -1519,14 +1535,21 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec,
DiagID);
break;
-
+ case tok::kw___vector:
+ isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
+ break;
+ case tok::kw___pixel:
+ isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID);
+ break;
+
// class-specifier:
case tok::kw_class:
case tok::kw_struct:
case tok::kw_union: {
tok::TokenKind Kind = Tok.getKind();
ConsumeToken();
- ParseClassSpecifier(Kind, Loc, DS, TemplateInfo);
+ ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS_none,
+ SuppressDeclarations);
return true;
}
@@ -1750,14 +1773,14 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
ConsumeToken();
if (!Tok.isObjCAtKeyword(tok::objc_defs)) {
Diag(Tok, diag::err_unexpected_at);
- SkipUntil(tok::semi, true, true);
+ SkipUntil(tok::semi, true);
continue;
}
ConsumeToken();
ExpectAndConsume(tok::l_paren, diag::err_expected_lparen);
if (!Tok.is(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
- SkipUntil(tok::semi, true, true);
+ SkipUntil(tok::semi, true);
continue;
}
llvm::SmallVector<DeclPtrTy, 16> Fields;
@@ -1771,26 +1794,28 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
if (Tok.is(tok::semi)) {
ConsumeToken();
} else if (Tok.is(tok::r_brace)) {
- Diag(Tok, diag::ext_expected_semi_decl_list);
+ ExpectAndConsume(tok::semi, diag::ext_expected_semi_decl_list);
break;
} else {
- Diag(Tok, diag::err_expected_semi_decl_list);
- // Skip to end of block or statement
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list);
+ // Skip to end of block or statement to avoid ext-warning on extra ';'.
SkipUntil(tok::r_brace, true, true);
+ // If we stopped at a ';', eat it.
+ if (Tok.is(tok::semi)) ConsumeToken();
}
}
SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
- AttributeList *AttrList = 0;
+ llvm::OwningPtr<AttributeList> AttrList;
// If attributes exist after struct contents, parse them.
if (Tok.is(tok::kw___attribute))
- AttrList = ParseGNUAttributes();
+ AttrList.reset(ParseGNUAttributes());
Actions.ActOnFields(CurScope,
RecordLoc, TagDecl, FieldDecls.data(), FieldDecls.size(),
LBraceLoc, RBraceLoc,
- AttrList);
+ AttrList.get());
StructScope.Exit();
Actions.ActOnTagFinishDefinition(CurScope, TagDecl, RBraceLoc);
}
@@ -1817,10 +1842,10 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
ConsumeToken();
}
- AttributeList *Attr = 0;
+ llvm::OwningPtr<AttributeList> Attr;
// If attributes exist after tag, parse them.
if (Tok.is(tok::kw___attribute))
- Attr = ParseGNUAttributes();
+ Attr.reset(ParseGNUAttributes());
CXXScopeSpec SS;
if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, 0, false)) {
@@ -1870,7 +1895,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
bool Owned = false;
bool IsDependent = false;
DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TUK,
- StartLoc, SS, Name, NameLoc, Attr, AS,
+ StartLoc, SS, Name, NameLoc, Attr.get(),
+ AS,
Action::MultiTemplateParamsArg(Actions),
Owned, IsDependent);
assert(!IsDependent && "didn't expect dependent enum");
@@ -1878,10 +1904,12 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (Tok.is(tok::l_brace))
ParseEnumBody(StartLoc, TagDecl);
- // TODO: semantic analysis on the declspec for enums.
+ // FIXME: The DeclSpec should keep the locations of both the keyword and the
+ // name (if there is one).
+ SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc;
const char *PrevSpec = 0;
unsigned DiagID;
- if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, PrevSpec, DiagID,
+ if (DS.SetTypeSpecType(DeclSpec::TST_enum, TSTLoc, PrevSpec, DiagID,
TagDecl.getAs<void>(), Owned))
Diag(StartLoc, DiagID) << PrevSpec;
}
@@ -1948,14 +1976,14 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) {
// Eat the }.
SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
- AttributeList *Attr = 0;
+ llvm::OwningPtr<AttributeList> Attr;
// If attributes exist after the identifier list, parse them.
if (Tok.is(tok::kw___attribute))
- Attr = ParseGNUAttributes(); // FIXME: where do they do?
+ Attr.reset(ParseGNUAttributes()); // FIXME: where do they do?
Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl,
EnumConstantDecls.data(), EnumConstantDecls.size(),
- CurScope, Attr);
+ CurScope, Attr.get());
EnumScope.Exit();
Actions.ActOnTagFinishDefinition(CurScope, EnumDecl, RBraceLoc);
@@ -1981,6 +2009,9 @@ bool Parser::isTypeSpecifierQualifier() {
default: return false;
case tok::identifier: // foo::bar
+ if (TryAltiVecVectorToken())
+ return true;
+ // Fall through.
case tok::kw_typename: // typename T::type
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
@@ -2026,6 +2057,7 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw__Decimal32:
case tok::kw__Decimal64:
case tok::kw__Decimal128:
+ case tok::kw___vector:
// struct-or-union-specifier (C99) or class-specifier (C++)
case tok::kw_class:
@@ -2066,7 +2098,9 @@ bool Parser::isDeclarationSpecifier() {
// Unfortunate hack to support "Class.factoryMethod" notation.
if (getLang().ObjC1 && NextToken().is(tok::period))
return false;
- // Fall through
+ if (TryAltiVecVectorToken())
+ return true;
+ // Fall through.
case tok::kw_typename: // typename T::type
// Annotate typenames and C++ scope specifiers. If we get one, just
@@ -2117,6 +2151,7 @@ bool Parser::isDeclarationSpecifier() {
case tok::kw__Decimal32:
case tok::kw__Decimal64:
case tok::kw__Decimal128:
+ case tok::kw___vector:
// struct-or-union-specifier (C99) or class-specifier (C++)
case tok::kw_class:
@@ -2608,10 +2643,10 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// In either case, we need to eat any attributes to be able to determine what
// sort of paren this is.
//
- AttributeList *AttrList = 0;
+ llvm::OwningPtr<AttributeList> AttrList;
bool RequiresArg = false;
if (Tok.is(tok::kw___attribute)) {
- AttrList = ParseGNUAttributes();
+ AttrList.reset(ParseGNUAttributes());
// We require that the argument list (if this is a non-grouping paren) be
// present even if the attribute list was empty.
@@ -2621,7 +2656,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
if (Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) ||
Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___w64) ||
Tok.is(tok::kw___ptr64)) {
- AttrList = ParseMicrosoftTypeAttributes(AttrList);
+ AttrList.reset(ParseMicrosoftTypeAttributes(AttrList.take()));
}
// If we haven't past the identifier yet (or where the identifier would be
@@ -2652,7 +2687,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
bool hadGroupingParens = D.hasGroupingParens();
D.setGroupingParens(true);
if (AttrList)
- D.AddAttributes(AttrList, SourceLocation());
+ D.AddAttributes(AttrList.take(), SourceLocation());
ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
// Match the ')'.
@@ -2669,7 +2704,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// ParseFunctionDeclarator to handle of argument list.
D.SetIdentifier(0, Tok.getLocation());
- ParseFunctionDeclarator(StartLoc, D, AttrList, RequiresArg);
+ ParseFunctionDeclarator(StartLoc, D, AttrList.take(), RequiresArg);
}
/// ParseFunctionDeclarator - We are after the identifier and have parsed the
@@ -2762,7 +2797,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// Alternatively, this parameter list may be an identifier list form for a
// K&R-style function: void foo(a,b,c)
- if (!getLang().CPlusPlus && Tok.is(tok::identifier)) {
+ if (!getLang().CPlusPlus && Tok.is(tok::identifier)
+ && !TryAltiVecVectorToken()) {
if (!TryAnnotateTypeOrScopeToken()) {
// K&R identifier lists can't have typedefs as identifiers, per
// C99 6.7.5.3p11.
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index efaf8ee3270e..51ee6a443488 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -64,12 +64,12 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
}
// Read label attributes, if present.
- Action::AttrTy *AttrList = 0;
+ llvm::OwningPtr<AttributeList> AttrList;
if (Tok.is(tok::kw___attribute)) {
attrTok = Tok;
// FIXME: save these somewhere.
- AttrList = ParseGNUAttributes();
+ AttrList.reset(ParseGNUAttributes());
}
if (Tok.is(tok::equal)) {
@@ -91,7 +91,8 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
ParseScope NamespaceScope(this, Scope::DeclScope);
DeclPtrTy NamespcDecl =
- Actions.ActOnStartNamespaceDef(CurScope, IdentLoc, Ident, LBrace);
+ Actions.ActOnStartNamespaceDef(CurScope, IdentLoc, Ident, LBrace,
+ AttrList.get());
PrettyStackTraceActionsDecl CrashInfo(NamespcDecl, NamespaceLoc, Actions,
PP.getSourceManager(),
@@ -191,6 +192,8 @@ Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS,
SourceLocation());
}
+ DS.abort();
+
if (Attr.HasAttr)
Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
<< Attr.Range;
@@ -325,8 +328,6 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
// Parse nested-name-specifier.
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
- AttributeList *AttrList = 0;
-
// Check nested-name specifier.
if (SS.isInvalid()) {
SkipUntil(tok::semi);
@@ -348,8 +349,9 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
}
// Parse (optional) attributes (most likely GNU strong-using extension).
+ llvm::OwningPtr<AttributeList> AttrList;
if (Tok.is(tok::kw___attribute))
- AttrList = ParseGNUAttributes();
+ AttrList.reset(ParseGNUAttributes());
// Eat ';'.
DeclEnd = Tok.getLocation();
@@ -358,7 +360,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
tok::semi);
return Actions.ActOnUsingDeclaration(CurScope, AS, true, UsingLoc, SS, Name,
- AttrList, IsTypeName, TypenameLoc);
+ AttrList.get(), IsTypeName, TypenameLoc);
}
/// ParseStaticAssertDeclaration - Parse C++0x static_assert-declaratoion.
@@ -547,7 +549,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
/// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or
/// elaborated-type-specifier [C++ dcl.type.elab]; we can't tell which
/// until we reach the start of a definition or see a token that
-/// cannot start a definition.
+/// cannot start a definition. If SuppressDeclarations is true, we do know.
///
/// class-specifier: [C++ class]
/// class-head '{' member-specification[opt] '}'
@@ -587,7 +589,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
SourceLocation StartLoc, DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
- AccessSpecifier AS) {
+ AccessSpecifier AS, bool SuppressDeclarations){
DeclSpec::TST TagType;
if (TagTokKind == tok::kw_struct)
TagType = DeclSpec::TST_struct;
@@ -733,8 +735,16 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// have to be treated differently. If we have 'struct foo {...' or
// 'struct foo :...' then this is a definition. Otherwise we have
// something like 'struct foo xyz', a reference.
+ // However, in some contexts, things look like declarations but are just
+ // references, e.g.
+ // new struct s;
+ // or
+ // &T::operator struct s;
+ // For these, SuppressDeclarations is true.
Action::TagUseKind TUK;
- if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon))) {
+ if (SuppressDeclarations)
+ TUK = Action::TUK_Reference;
+ else if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon))){
if (DS.isFriendSpecified()) {
// C++ [class.friend]p2:
// A class shall not be defined in a friend declaration.
@@ -917,9 +927,62 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
const char *PrevSpec = 0;
unsigned DiagID;
- if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec, DiagID,
+ // FIXME: The DeclSpec should keep the locations of both the keyword and the
+ // name (if there is one).
+ SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc;
+
+ if (DS.SetTypeSpecType(TagType, TSTLoc, PrevSpec, DiagID,
Result, Owned))
Diag(StartLoc, DiagID) << PrevSpec;
+
+ // At this point, we've successfully parsed a class-specifier in 'definition'
+ // form (e.g. "struct foo { int x; }". While we could just return here, we're
+ // going to look at what comes after it to improve error recovery. If an
+ // impossible token occurs next, we assume that the programmer forgot a ; at
+ // the end of the declaration and recover that way.
+ //
+ // This switch enumerates the valid "follow" set for definition.
+ if (TUK == Action::TUK_Definition) {
+ switch (Tok.getKind()) {
+ case tok::semi: // struct foo {...} ;
+ case tok::star: // struct foo {...} * P;
+ case tok::amp: // struct foo {...} & R = ...
+ case tok::identifier: // struct foo {...} V ;
+ case tok::r_paren: //(struct foo {...} ) {4}
+ case tok::annot_cxxscope: // struct foo {...} a:: b;
+ case tok::annot_typename: // struct foo {...} a ::b;
+ case tok::annot_template_id: // struct foo {...} a<int> ::b;
+ case tok::l_paren: // struct foo {...} ( x);
+ case tok::comma: // __builtin_offsetof(struct foo{...} ,
+ // Storage-class specifiers
+ case tok::kw_static: // struct foo {...} static x;
+ case tok::kw_extern: // struct foo {...} extern x;
+ case tok::kw_typedef: // struct foo {...} typedef x;
+ case tok::kw_register: // struct foo {...} register x;
+ case tok::kw_auto: // struct foo {...} auto x;
+ // Type qualifiers
+ case tok::kw_const: // struct foo {...} const x;
+ case tok::kw_volatile: // struct foo {...} volatile x;
+ case tok::kw_restrict: // struct foo {...} restrict x;
+ case tok::kw_inline: // struct foo {...} inline foo() {};
+ break;
+
+ case tok::r_brace: // struct bar { struct foo {...} }
+ // Missing ';' at end of struct is accepted as an extension in C mode.
+ if (!getLang().CPlusPlus) break;
+ // FALL THROUGH.
+ default:
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
+ TagType == DeclSpec::TST_class ? "class"
+ : TagType == DeclSpec::TST_struct? "struct" : "union");
+ // Push this token back into the preprocessor and change our current token
+ // to ';' so that the rest of the code recovers as though there were an
+ // ';' after the definition.
+ PP.EnterToken(Tok);
+ Tok.setKind(tok::semi);
+ break;
+ }
+ }
}
/// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived].
@@ -1164,7 +1227,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return ParseCXXClassMemberDeclaration(AS, TemplateInfo);
}
- // Don't parse FOO:BAR as if it were a typo for FOO::BAR.
+ // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it
+ // is a bitfield.
ColonProtectionRAIIObject X(*this);
CXX0XAttributeList AttrList;
@@ -1185,8 +1249,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (Tok.is(tok::kw_namespace)) {
Diag(UsingLoc, diag::err_using_namespace_in_class);
SkipUntil(tok::semi, true, true);
- }
- else {
+ } else {
SourceLocation DeclEnd;
// Otherwise, it must be using-declaration.
ParseUsingDeclaration(Declarator::MemberContext, UsingLoc, DeclEnd, AS);
@@ -1367,19 +1430,16 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ParseDeclarator(DeclaratorInfo);
}
- if (Tok.is(tok::semi)) {
- ConsumeToken();
- Actions.FinalizeDeclaratorGroup(CurScope, DS, DeclsInGroup.data(),
- DeclsInGroup.size());
+ if (ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) {
+ // Skip to end of block or statement.
+ SkipUntil(tok::r_brace, true, true);
+ // If we stopped at a ';', eat it.
+ if (Tok.is(tok::semi)) ConsumeToken();
return;
}
- Diag(Tok, diag::err_expected_semi_decl_list);
- // Skip to end of block or statement
- SkipUntil(tok::r_brace, true, true);
- if (Tok.is(tok::semi))
- ConsumeToken();
- return;
+ Actions.FinalizeDeclaratorGroup(CurScope, DS, DeclsInGroup.data(),
+ DeclsInGroup.size());
}
/// ParseCXXMemberSpecification - Parse the class definition.
@@ -1489,10 +1549,10 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
- AttributeList *AttrList = 0;
// If attributes exist after class contents, parse them.
+ llvm::OwningPtr<AttributeList> AttrList;
if (Tok.is(tok::kw___attribute))
- AttrList = ParseGNUAttributes(); // FIXME: where should I put them?
+ AttrList.reset(ParseGNUAttributes()); // FIXME: where should I put them?
Actions.ActOnFinishCXXMemberSpecification(CurScope, RecordLoc, TagDecl,
LBraceLoc, RBraceLoc);
@@ -1546,12 +1606,15 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) {
SourceLocation ColonLoc = ConsumeToken();
llvm::SmallVector<MemInitTy*, 4> MemInitializers;
-
+ bool AnyErrors = false;
+
do {
MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
if (!MemInit.isInvalid())
MemInitializers.push_back(MemInit.get());
-
+ else
+ AnyErrors = true;
+
if (Tok.is(tok::comma))
ConsumeToken();
else if (Tok.is(tok::l_brace))
@@ -1565,7 +1628,8 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) {
} while (true);
Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc,
- MemInitializers.data(), MemInitializers.size());
+ MemInitializers.data(), MemInitializers.size(),
+ AnyErrors);
}
/// ParseMemInitializer - Parse a C++ member initializer, which is
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 669575c4f030..c763c2c6f65f 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -22,6 +22,7 @@
#include "clang/Parse/Parser.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
+#include "clang/Parse/Template.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "RAIIObjectsForParser.h"
#include "llvm/ADT/SmallVector.h"
@@ -780,6 +781,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw_void:
case tok::kw_typename:
case tok::kw_typeof:
+ case tok::kw___vector:
case tok::annot_typename: {
if (!getLang().CPlusPlus) {
Diag(Tok, diag::err_expected_expression);
@@ -805,9 +807,44 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
return ParsePostfixExpressionSuffix(move(Res));
}
- case tok::annot_cxxscope: // [C++] id-expression: qualified-id
+ case tok::annot_cxxscope: { // [C++] id-expression: qualified-id
+ Token Next = NextToken();
+ if (Next.is(tok::annot_template_id)) {
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue());
+ if (TemplateId->Kind == TNK_Type_template) {
+ // We have a qualified template-id that we know refers to a
+ // type, translate it into a type and continue parsing as a
+ // cast expression.
+ CXXScopeSpec SS;
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
+ AnnotateTemplateIdTokenAsType(&SS);
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
+ NotCastExpr, TypeOfCast);
+ }
+ }
+
+ // Parse as an id-expression.
+ Res = ParseCXXIdExpression(isAddressOfOperand);
+ return ParsePostfixExpressionSuffix(move(Res));
+ }
+
+ case tok::annot_template_id: { // [C++] template-id
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ if (TemplateId->Kind == TNK_Type_template) {
+ // We have a template-id that we know refers to a type,
+ // translate it into a type and continue parsing as a cast
+ // expression.
+ AnnotateTemplateIdTokenAsType();
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
+ NotCastExpr, TypeOfCast);
+ }
+
+ // Fall through to treat the template-id as an id-expression.
+ }
+
case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id
- case tok::annot_template_id: // [C++] template-id
Res = ParseCXXIdExpression(isAddressOfOperand);
return ParsePostfixExpressionSuffix(move(Res));
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index ca50ef400092..0dbe1ea83890 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -763,12 +763,15 @@ bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
bool isInvalid = 0;
// Parse one or more of the type specifiers.
- if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID)) {
+ if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
+ ParsedTemplateInfo(), /*SuppressDeclarations*/true)) {
Diag(Tok, diag::err_operator_missing_type_specifier);
return true;
}
- while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID)) ;
+ while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
+ ParsedTemplateInfo(), /*SuppressDeclarations*/true))
+ {}
return false;
}
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index ae85aa3a8aef..d1c9be233fe0 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -515,7 +515,8 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, DeclPtrTy ClassDecl,
DS.setSetterName(Tok.getIdentifierInfo());
ConsumeToken(); // consume method name
- if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "",
+ if (ExpectAndConsume(tok::colon,
+ diag::err_expected_colon_after_setter_name, "",
tok::r_paren))
return;
} else {
@@ -786,15 +787,15 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
llvm::SmallVector<Declarator, 8> CargNames;
if (Tok.isNot(tok::colon)) {
// If attributes exist after the method, parse them.
- AttributeList *MethodAttrs = 0;
+ llvm::OwningPtr<AttributeList> MethodAttrs;
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
- MethodAttrs = ParseGNUAttributes();
+ MethodAttrs.reset(ParseGNUAttributes());
Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
DeclPtrTy Result
= Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
mType, IDecl, DSRet, ReturnType, Sel,
- 0, CargNames, MethodAttrs,
+ 0, CargNames, MethodAttrs.get(),
MethodImplKind);
PD.complete(Result);
return Result;
@@ -862,9 +863,9 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// FIXME: Add support for optional parmameter list...
// If attributes exist after the method, parse them.
- AttributeList *MethodAttrs = 0;
+ llvm::OwningPtr<AttributeList> MethodAttrs;
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
- MethodAttrs = ParseGNUAttributes();
+ MethodAttrs.reset(ParseGNUAttributes());
if (KeyIdents.size() == 0)
return DeclPtrTy();
@@ -873,9 +874,16 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
DeclPtrTy Result
= Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
mType, IDecl, DSRet, ReturnType, Sel,
- &ArgInfos[0], CargNames, MethodAttrs,
+ &ArgInfos[0], CargNames,
+ MethodAttrs.get(),
MethodImplKind, isVariadic);
PD.complete(Result);
+
+ // Delete referenced AttributeList objects.
+ for (llvm::SmallVectorImpl<Action::ObjCArgInfo>::iterator
+ I = ArgInfos.begin(), E = ArgInfos.end(); I != E; ++I)
+ delete I->ArgAttrs;
+
return Result;
}
@@ -1481,7 +1489,9 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
// Inform the actions module about the parameter declarator, so it
// gets added to the current scope.
+ // FIXME. Probably can build a VarDecl and avoid setting DeclContext.
FirstPart = Actions.ActOnParamDeclarator(CurScope, ParmDecl);
+ Actions.ActOnObjCCatchParam(FirstPart);
} else
ConsumeToken(); // consume '...'
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 21e960aa8173..9fd145dc2676 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -81,6 +81,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
CXX0XAttributeList Attr;
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
Attr = ParseCXX0XAttributes();
+ llvm::OwningPtr<AttributeList> AttrList(Attr.AttrList);
// Cases in this switch statement should fall through if the parser expects
// the token to end in a semicolon (in which case SemiError should be set),
@@ -102,13 +103,14 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
case tok::identifier:
if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement
// identifier ':' statement
- return ParseLabeledStatement(Attr.AttrList);
+ return ParseLabeledStatement(AttrList.take());
}
// PASS THROUGH.
default: {
if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
+ AttrList.take(); //Passing 'Attr' to ParseDeclaration transfers ownership.
DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd,
Attr);
return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
@@ -135,43 +137,43 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
}
case tok::kw_case: // C99 6.8.1: labeled-statement
- return ParseCaseStatement(Attr.AttrList);
+ return ParseCaseStatement(AttrList.take());
case tok::kw_default: // C99 6.8.1: labeled-statement
- return ParseDefaultStatement(Attr.AttrList);
+ return ParseDefaultStatement(AttrList.take());
case tok::l_brace: // C99 6.8.2: compound-statement
- return ParseCompoundStatement(Attr.AttrList);
+ return ParseCompoundStatement(AttrList.take());
case tok::semi: // C99 6.8.3p3: expression[opt] ';'
return Actions.ActOnNullStmt(ConsumeToken());
case tok::kw_if: // C99 6.8.4.1: if-statement
- return ParseIfStatement(Attr.AttrList);
+ return ParseIfStatement(AttrList.take());
case tok::kw_switch: // C99 6.8.4.2: switch-statement
- return ParseSwitchStatement(Attr.AttrList);
+ return ParseSwitchStatement(AttrList.take());
case tok::kw_while: // C99 6.8.5.1: while-statement
- return ParseWhileStatement(Attr.AttrList);
+ return ParseWhileStatement(AttrList.take());
case tok::kw_do: // C99 6.8.5.2: do-statement
- Res = ParseDoStatement(Attr.AttrList);
+ Res = ParseDoStatement(AttrList.take());
SemiError = "do/while";
break;
case tok::kw_for: // C99 6.8.5.3: for-statement
- return ParseForStatement(Attr.AttrList);
+ return ParseForStatement(AttrList.take());
case tok::kw_goto: // C99 6.8.6.1: goto-statement
- Res = ParseGotoStatement(Attr.AttrList);
+ Res = ParseGotoStatement(AttrList.take());
SemiError = "goto";
break;
case tok::kw_continue: // C99 6.8.6.2: continue-statement
- Res = ParseContinueStatement(Attr.AttrList);
+ Res = ParseContinueStatement(AttrList.take());
SemiError = "continue";
break;
case tok::kw_break: // C99 6.8.6.3: break-statement
- Res = ParseBreakStatement(Attr.AttrList);
+ Res = ParseBreakStatement(AttrList.take());
SemiError = "break";
break;
case tok::kw_return: // C99 6.8.6.4: return-statement
- Res = ParseReturnStatement(Attr.AttrList);
+ Res = ParseReturnStatement(AttrList.take());
SemiError = "return";
break;
@@ -187,7 +189,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
}
case tok::kw_try: // C++ 15: try-block
- return ParseCXXTryBlock(Attr.AttrList);
+ return ParseCXXTryBlock(AttrList.take());
}
// If we reached this code, the statement must end in a semicolon.
@@ -215,6 +217,7 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) {
assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() &&
"Not an identifier!");
+ llvm::OwningPtr<AttributeList> AttrList(Attr);
Token IdentTok = Tok; // Save the whole token.
ConsumeToken(); // eat the identifier.
@@ -225,7 +228,7 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) {
// Read label attributes, if present.
if (Tok.is(tok::kw___attribute))
- Attr = addAttributeLists(Attr, ParseGNUAttributes());
+ AttrList.reset(addAttributeLists(AttrList.take(), ParseGNUAttributes()));
OwningStmtResult SubStmt(ParseStatement());
@@ -233,6 +236,7 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) {
if (SubStmt.isInvalid())
SubStmt = Actions.ActOnNullStmt(ColonLoc);
+ // FIXME: use attributes?
return Actions.ActOnLabelStmt(IdentTok.getLocation(),
IdentTok.getIdentifierInfo(),
ColonLoc, move(SubStmt));
@@ -246,6 +250,7 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) {
Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) {
assert(Tok.is(tok::kw_case) && "Not a case stmt!");
// FIXME: Use attributes?
+ delete Attr;
// It is very very common for code to contain many case statements recursively
// nested, as in (but usually without indentation):
@@ -371,6 +376,8 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) {
///
Parser::OwningStmtResult Parser::ParseDefaultStatement(AttributeList *Attr) {
//FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_default) && "Not a default stmt!");
SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'.
@@ -427,6 +434,8 @@ Parser::OwningStmtResult Parser::ParseDefaultStatement(AttributeList *Attr) {
Parser::OwningStmtResult Parser::ParseCompoundStatement(AttributeList *Attr,
bool isStmtExpr) {
//FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
// Enter a scope to hold everything within the compound stmt. Compound
@@ -562,6 +571,8 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &ExprResult,
///
Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_if) && "Not an if stmt!");
SourceLocation IfLoc = ConsumeToken(); // eat the 'if'.
@@ -686,6 +697,8 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) {
/// [C++] 'switch' '(' condition ')' statement
Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_switch) && "Not a switch stmt!");
SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'.
@@ -741,19 +754,19 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) {
// Read the body statement.
OwningStmtResult Body(ParseStatement());
- // Pop the body scope if needed.
+ // Pop the scopes.
InnerScope.Exit();
-
- if (Body.isInvalid()) {
- Body = Actions.ActOnNullStmt(Tok.getLocation());
- // FIXME: Remove the case statement list from the Switch statement.
- }
-
SwitchScope.Exit();
- if (Cond.isInvalid() && !CondVar.get())
+ if (Cond.isInvalid() && !CondVar.get()) {
+ Actions.ActOnSwitchBodyError(SwitchLoc, move(Switch), move(Body));
return StmtError();
+ }
+ if (Body.isInvalid())
+ // FIXME: Remove the case statement list from the Switch statement.
+ Body = Actions.ActOnNullStmt(Tok.getLocation());
+
return Actions.ActOnFinishSwitchStmt(SwitchLoc, move(Switch), move(Body));
}
@@ -763,6 +776,8 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) {
/// [C++] 'while' '(' condition ')' statement
Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_while) && "Not a while stmt!");
SourceLocation WhileLoc = Tok.getLocation();
ConsumeToken(); // eat the 'while'.
@@ -836,6 +851,8 @@ Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) {
/// Note: this lets the caller parse the end ';'.
Parser::OwningStmtResult Parser::ParseDoStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_do) && "Not a do stmt!");
SourceLocation DoLoc = ConsumeToken(); // eat the 'do'.
@@ -911,6 +928,8 @@ Parser::OwningStmtResult Parser::ParseDoStatement(AttributeList *Attr) {
///
Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_for) && "Not a for stmt!");
SourceLocation ForLoc = ConsumeToken(); // eat the 'for'.
@@ -1081,6 +1100,8 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) {
///
Parser::OwningStmtResult Parser::ParseGotoStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_goto) && "Not a goto stmt!");
SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'.
@@ -1115,6 +1136,8 @@ Parser::OwningStmtResult Parser::ParseGotoStatement(AttributeList *Attr) {
///
Parser::OwningStmtResult Parser::ParseContinueStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'.
return Actions.ActOnContinueStmt(ContinueLoc, CurScope);
}
@@ -1127,6 +1150,8 @@ Parser::OwningStmtResult Parser::ParseContinueStatement(AttributeList *Attr) {
///
Parser::OwningStmtResult Parser::ParseBreakStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'.
return Actions.ActOnBreakStmt(BreakLoc, CurScope);
}
@@ -1136,6 +1161,8 @@ Parser::OwningStmtResult Parser::ParseBreakStatement(AttributeList *Attr) {
/// 'return' expression[opt] ';'
Parser::OwningStmtResult Parser::ParseReturnStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_return) && "Not a return stmt!");
SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'.
@@ -1171,7 +1198,6 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() {
Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) &&
Tok.isNot(tok::eof));
}
- llvm::SmallVector<std::string, 4> Names;
Token t;
t.setKind(tok::string_literal);
t.setLiteralData("\"FIXME: not done\"");
@@ -1181,7 +1207,7 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() {
ExprVector Constraints(Actions);
ExprVector Exprs(Actions);
ExprVector Clobbers(Actions);
- return Actions.ActOnAsmStmt(Tok.getLocation(), true, true, 0, 0, Names.data(),
+ return Actions.ActOnAsmStmt(Tok.getLocation(), true, true, 0, 0, 0,
move_arg(Constraints), move_arg(Exprs),
move(AsmString), move_arg(Clobbers),
Tok.getLocation(), true);
@@ -1245,7 +1271,7 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) {
if (AsmString.isInvalid())
return StmtError();
- llvm::SmallVector<std::string, 4> Names;
+ llvm::SmallVector<IdentifierInfo *, 4> Names;
ExprVector Constraints(Actions);
ExprVector Exprs(Actions);
ExprVector Clobbers(Actions);
@@ -1336,9 +1362,9 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) {
///
//
// FIXME: Avoid unnecessary std::string trashing.
-bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names,
- llvm::SmallVectorImpl<ExprTy*> &Constraints,
- llvm::SmallVectorImpl<ExprTy*> &Exprs) {
+bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
+ llvm::SmallVectorImpl<ExprTy *> &Constraints,
+ llvm::SmallVectorImpl<ExprTy *> &Exprs) {
// 'asm-operands' isn't present?
if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))
return false;
@@ -1357,10 +1383,10 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names,
IdentifierInfo *II = Tok.getIdentifierInfo();
ConsumeToken();
- Names.push_back(II->getName());
+ Names.push_back(II);
MatchRHSPunctuation(tok::r_square, Loc);
} else
- Names.push_back(std::string());
+ Names.push_back(0);
OwningExprResult Constraint(ParseAsmStringLiteral());
if (Constraint.isInvalid()) {
@@ -1448,6 +1474,8 @@ Parser::DeclPtrTy Parser::ParseFunctionTryBlock(DeclPtrTy Decl) {
///
Parser::OwningStmtResult Parser::ParseCXXTryBlock(AttributeList* Attr) {
// FIXME: Add attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_try) && "Expected 'try'");
SourceLocation TryLoc = ConsumeToken();
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 797c1dfe3e6a..12f26bfcb94e 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -836,7 +836,7 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) {
Tok.setAnnotationValue(Type.isInvalid()? 0 : Type.get());
if (SS && SS->isNotEmpty()) // it was a C++ qualified type name.
Tok.setLocation(SS->getBeginLoc());
- Tok.setAnnotationEndLoc(TemplateId->TemplateNameLoc);
+ // End location stays the same
// Replace the template-id annotation token, and possible the scope-specifier
// that precedes it, with the typename annotation token.
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 51c56706bb59..6251a2f36754 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -672,6 +672,11 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
Parser::TPResult Parser::isCXXDeclarationSpecifier() {
switch (Tok.getKind()) {
case tok::identifier: // foo::bar
+ // Check for need to substitute AltiVec __vector keyword
+ // for "vector" identifier.
+ if (TryAltiVecVectorToken())
+ return TPResult::True();
+ // Fall through.
case tok::kw_typename: // typename T::type
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
@@ -750,6 +755,10 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw___ptr64:
case tok::kw___forceinline:
return TPResult::True();
+
+ // AltiVec
+ case tok::kw___vector:
+ return TPResult::True();
case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed
// We've already annotated a scope; try to annotate a type.
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index f2bc303acd69..30899c5dddb5 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -346,6 +346,11 @@ void Parser::Initialize() {
}
Ident_super = &PP.getIdentifierTable().get("super");
+
+ if (getLang().AltiVec) {
+ Ident_vector = &PP.getIdentifierTable().get("vector");
+ Ident_pixel = &PP.getIdentifierTable().get("pixel");
+ }
}
/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
@@ -588,7 +593,6 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS,
if (Tok.is(tok::string_literal) && getLang().CPlusPlus &&
DS.getStorageClassSpec() == DeclSpec::SCS_extern &&
DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) {
- DS.abort();
DeclPtrTy TheDecl = ParseLinkage(DS, Declarator::FileContext);
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
@@ -738,11 +742,11 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
// Handle the full declarator list.
while (1) {
- Action::AttrTy *AttrList;
// If attributes are present, parse them.
+ llvm::OwningPtr<AttributeList> AttrList;
if (Tok.is(tok::kw___attribute))
// FIXME: attach attributes too.
- AttrList = ParseGNUAttributes();
+ AttrList.reset(ParseGNUAttributes());
// Ask the actions module to compute the type for this declarator.
Action::DeclPtrTy Param =
@@ -835,6 +839,16 @@ Parser::OwningExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
assert(Tok.is(tok::kw_asm) && "Not an asm!");
SourceLocation Loc = ConsumeToken();
+ if (Tok.is(tok::kw_volatile)) {
+ // Remove from the end of 'asm' to the end of 'volatile'.
+ SourceRange RemovalRange(PP.getLocForEndOfToken(Loc),
+ PP.getLocForEndOfToken(Tok.getLocation()));
+
+ Diag(Tok, diag::warn_file_asm_volatile)
+ << CodeModificationHint::CreateRemoval(RemovalRange);
+ ConsumeToken();
+ }
+
if (Tok.isNot(tok::l_paren)) {
Diag(Tok, diag::err_expected_lparen_after) << "asm";
return ExprError();
@@ -930,9 +944,10 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
return false;
}
+ SourceLocation EndLoc = Tok.getLastLoc();
Tok.setKind(tok::annot_typename);
Tok.setAnnotationValue(Ty.isInvalid()? 0 : Ty.get());
- Tok.setAnnotationEndLoc(Tok.getLocation());
+ Tok.setAnnotationEndLoc(EndLoc);
Tok.setLocation(TypenameLoc);
PP.AnnotateCachedTokens(Tok);
return true;
diff --git a/lib/Rewrite/Makefile b/lib/Rewrite/Makefile
index 61fdf4006f86..a6d3f7725689 100644
--- a/lib/Rewrite/Makefile
+++ b/lib/Rewrite/Makefile
@@ -14,7 +14,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangRewrite
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index bff47519a743..b09526e097b6 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -14,8 +14,6 @@
#include "IdentifierResolver.h"
#include "clang/Basic/LangOptions.h"
-#include <list>
-#include <vector>
using namespace clang;
@@ -27,14 +25,31 @@ using namespace clang;
/// Allocates 'pools' (vectors of IdDeclInfos) to avoid allocating each
/// individual IdDeclInfo to heap.
class IdentifierResolver::IdDeclInfoMap {
- static const unsigned int VECTOR_SIZE = 512;
- // Holds vectors of IdDeclInfos that serve as 'pools'.
- // New vectors are added when the current one is full.
- std::list< std::vector<IdDeclInfo> > IDIVecs;
+ static const unsigned int POOL_SIZE = 512;
+
+ /// We use our own linked-list implementation because it is sadly
+ /// impossible to add something to a pre-C++0x STL container without
+ /// a completely unnecessary copy.
+ struct IdDeclInfoPool {
+ IdDeclInfoPool(IdDeclInfoPool *Next) : Next(Next) {}
+
+ IdDeclInfoPool *Next;
+ IdDeclInfo Pool[POOL_SIZE];
+ };
+
+ IdDeclInfoPool *CurPool;
unsigned int CurIndex;
public:
- IdDeclInfoMap() : CurIndex(VECTOR_SIZE) {}
+ IdDeclInfoMap() : CurPool(0), CurIndex(POOL_SIZE) {}
+
+ ~IdDeclInfoMap() {
+ IdDeclInfoPool *Cur = CurPool;
+ while (IdDeclInfoPool *P = Cur) {
+ Cur = Cur->Next;
+ delete P;
+ }
+ }
/// Returns the IdDeclInfo associated to the DeclarationName.
/// It creates a new IdDeclInfo if one was not created before for this id.
@@ -235,14 +250,11 @@ IdentifierResolver::IdDeclInfoMap::operator[](DeclarationName Name) {
if (Ptr) return *toIdDeclInfo(Ptr);
- if (CurIndex == VECTOR_SIZE) {
- // Add a IdDeclInfo vector 'pool'
- IDIVecs.push_back(std::vector<IdDeclInfo>());
- // Fill the vector
- IDIVecs.back().resize(VECTOR_SIZE);
+ if (CurIndex == POOL_SIZE) {
+ CurPool = new IdDeclInfoPool(CurPool);
CurIndex = 0;
}
- IdDeclInfo *IDI = &IDIVecs.back()[CurIndex];
+ IdDeclInfo *IDI = &CurPool->Pool[CurIndex];
Name.setFETokenInfo(reinterpret_cast<void*>(
reinterpret_cast<uintptr_t>(IDI) | 0x1)
);
diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h
index f4cea2e88a6d..6b2694591f52 100644
--- a/lib/Sema/Lookup.h
+++ b/lib/Sema/Lookup.h
@@ -224,6 +224,10 @@ public:
return Ambiguity;
}
+ const UnresolvedSetImpl &asUnresolvedSet() const {
+ return Decls;
+ }
+
iterator begin() const { return iterator(Decls.begin()); }
iterator end() const { return iterator(Decls.end()); }
@@ -499,7 +503,7 @@ private:
if (isAmbiguous())
SemaRef.DiagnoseAmbiguousLookup(*this);
else if (isClassLookup() && SemaRef.getLangOptions().AccessControl)
- SemaRef.CheckAccess(*this);
+ SemaRef.CheckLookupAccess(*this);
}
void setAmbiguous(AmbiguityKind AK) {
@@ -583,6 +587,44 @@ private:
virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
bool InBaseClass) = 0;
};
+
+/// \brief A class for storing results from argument-dependent lookup.
+class ADLResult {
+private:
+ /// A map from canonical decls to the 'most recent' decl.
+ llvm::DenseMap<NamedDecl*, NamedDecl*> Decls;
+
+public:
+ /// Adds a new ADL candidate to this map.
+ void insert(NamedDecl *D);
+
+ /// Removes any data associated with a given decl.
+ void erase(NamedDecl *D) {
+ Decls.erase(cast<NamedDecl>(D->getCanonicalDecl()));
+ }
+
+ class iterator {
+ typedef llvm::DenseMap<NamedDecl*,NamedDecl*>::iterator inner_iterator;
+ inner_iterator iter;
+
+ friend class ADLResult;
+ iterator(const inner_iterator &iter) : iter(iter) {}
+ public:
+ iterator() {}
+
+ iterator &operator++() { ++iter; return *this; }
+ iterator operator++(int) { return iterator(iter++); }
+
+ NamedDecl *operator*() const { return iter->second; }
+
+ bool operator==(const iterator &other) const { return iter == other.iter; }
+ bool operator!=(const iterator &other) const { return iter != other.iter; }
+ };
+
+ iterator begin() { return iterator(Decls.begin()); }
+ iterator end() { return iterator(Decls.end()); }
+};
+
}
#endif
diff --git a/lib/Sema/Makefile b/lib/Sema/Makefile
index 0f4c7965dca2..158f1af213d4 100644
--- a/lib/Sema/Makefile
+++ b/lib/Sema/Makefile
@@ -15,7 +15,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangSema
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 171101bb96de..38c842eede57 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -15,260 +15,18 @@
#include "Sema.h"
#include "TargetAttributesSema.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/APFloat.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
using namespace clang;
-
-/// Determines whether we should have an a.k.a. clause when
-/// pretty-printing a type. There are three main criteria:
-///
-/// 1) Some types provide very minimal sugar that doesn't impede the
-/// user's understanding --- for example, elaborated type
-/// specifiers. If this is all the sugar we see, we don't want an
-/// a.k.a. clause.
-/// 2) Some types are technically sugared but are much more familiar
-/// when seen in their sugared form --- for example, va_list,
-/// vector types, and the magic Objective C types. We don't
-/// want to desugar these, even if we do produce an a.k.a. clause.
-/// 3) Some types may have already been desugared previously in this diagnostic.
-/// if this is the case, doing another "aka" would just be clutter.
-///
-static bool ShouldAKA(ASTContext &Context, QualType QT,
- const Diagnostic::ArgumentValue *PrevArgs,
- unsigned NumPrevArgs,
- QualType &DesugaredQT) {
- QualType InputTy = QT;
-
- bool AKA = false;
- QualifierCollector Qc;
-
- while (true) {
- const Type *Ty = Qc.strip(QT);
-
- // Don't aka just because we saw an elaborated type...
- if (isa<ElaboratedType>(Ty)) {
- QT = cast<ElaboratedType>(Ty)->desugar();
- continue;
- }
-
- // ...or a qualified name type...
- if (isa<QualifiedNameType>(Ty)) {
- QT = cast<QualifiedNameType>(Ty)->desugar();
- continue;
- }
-
- // ...or a substituted template type parameter.
- if (isa<SubstTemplateTypeParmType>(Ty)) {
- QT = cast<SubstTemplateTypeParmType>(Ty)->desugar();
- continue;
- }
-
- // Don't desugar template specializations.
- if (isa<TemplateSpecializationType>(Ty))
- break;
-
- // Don't desugar magic Objective-C types.
- if (QualType(Ty,0) == Context.getObjCIdType() ||
- QualType(Ty,0) == Context.getObjCClassType() ||
- QualType(Ty,0) == Context.getObjCSelType() ||
- QualType(Ty,0) == Context.getObjCProtoType())
- break;
-
- // Don't desugar va_list.
- if (QualType(Ty,0) == Context.getBuiltinVaListType())
- break;
-
- // Otherwise, do a single-step desugar.
- QualType Underlying;
- bool IsSugar = false;
- switch (Ty->getTypeClass()) {
-#define ABSTRACT_TYPE(Class, Base)
-#define TYPE(Class, Base) \
- case Type::Class: { \
- const Class##Type *CTy = cast<Class##Type>(Ty); \
- if (CTy->isSugared()) { \
- IsSugar = true; \
- Underlying = CTy->desugar(); \
- } \
- break; \
- }
-#include "clang/AST/TypeNodes.def"
- }
-
- // If it wasn't sugared, we're done.
- if (!IsSugar)
- break;
-
- // If the desugared type is a vector type, we don't want to expand
- // it, it will turn into an attribute mess. People want their "vec4".
- if (isa<VectorType>(Underlying))
- break;
-
- // Don't desugar through the primary typedef of an anonymous type.
- if (isa<TagType>(Underlying) && isa<TypedefType>(QT))
- if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() ==
- cast<TypedefType>(QT)->getDecl())
- break;
-
- // Otherwise, we're tearing through something opaque; note that
- // we'll eventually need an a.k.a. clause and keep going.
- AKA = true;
- QT = Underlying;
- continue;
- }
-
- // If we never tore through opaque sugar, don't print aka.
- if (!AKA) return false;
-
- // If we did, check to see if we already desugared this type in this
- // diagnostic. If so, don't do it again.
- for (unsigned i = 0; i != NumPrevArgs; ++i) {
- // TODO: Handle ak_declcontext case.
- if (PrevArgs[i].first == Diagnostic::ak_qualtype) {
- void *Ptr = (void*)PrevArgs[i].second;
- QualType PrevTy(QualType::getFromOpaquePtr(Ptr));
- if (PrevTy == InputTy)
- return false;
- }
- }
-
- DesugaredQT = Qc.apply(QT);
- return true;
-}
-
-/// \brief Convert the given type to a string suitable for printing as part of
-/// a diagnostic.
-///
-/// \param Context the context in which the type was allocated
-/// \param Ty the type to print
-static std::string
-ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
- const Diagnostic::ArgumentValue *PrevArgs,
- unsigned NumPrevArgs) {
- // FIXME: Playing with std::string is really slow.
- std::string S = Ty.getAsString(Context.PrintingPolicy);
-
- // Consider producing an a.k.a. clause if removing all the direct
- // sugar gives us something "significantly different".
-
- QualType DesugaredTy;
- if (ShouldAKA(Context, Ty, PrevArgs, NumPrevArgs, DesugaredTy)) {
- S = "'"+S+"' (aka '";
- S += DesugaredTy.getAsString(Context.PrintingPolicy);
- S += "')";
- return S;
- }
-
- S = "'" + S + "'";
- return S;
-}
-/// ConvertQualTypeToStringFn - This function is used to pretty print the
-/// specified QualType as a string in diagnostics.
-static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
- const char *Modifier, unsigned ModLen,
- const char *Argument, unsigned ArgLen,
- const Diagnostic::ArgumentValue *PrevArgs,
- unsigned NumPrevArgs,
- llvm::SmallVectorImpl<char> &Output,
- void *Cookie) {
- ASTContext &Context = *static_cast<ASTContext*>(Cookie);
-
- std::string S;
- bool NeedQuotes = true;
-
- switch (Kind) {
- default: assert(0 && "unknown ArgumentKind");
- case Diagnostic::ak_qualtype: {
- assert(ModLen == 0 && ArgLen == 0 &&
- "Invalid modifier for QualType argument");
-
- QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
- S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs);
- NeedQuotes = false;
- break;
- }
- case Diagnostic::ak_declarationname: {
- DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
- S = N.getAsString();
-
- if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0)
- S = '+' + S;
- else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12) && ArgLen==0)
- S = '-' + S;
- else
- assert(ModLen == 0 && ArgLen == 0 &&
- "Invalid modifier for DeclarationName argument");
- break;
- }
- case Diagnostic::ak_nameddecl: {
- bool Qualified;
- if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
- Qualified = true;
- else {
- assert(ModLen == 0 && ArgLen == 0 &&
- "Invalid modifier for NamedDecl* argument");
- Qualified = false;
- }
- reinterpret_cast<NamedDecl*>(Val)->
- getNameForDiagnostic(S, Context.PrintingPolicy, Qualified);
- break;
- }
- case Diagnostic::ak_nestednamespec: {
- llvm::raw_string_ostream OS(S);
- reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS,
- Context.PrintingPolicy);
- NeedQuotes = false;
- break;
- }
- case Diagnostic::ak_declcontext: {
- DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
- assert(DC && "Should never have a null declaration context");
-
- if (DC->isTranslationUnit()) {
- // FIXME: Get these strings from some localized place
- if (Context.getLangOptions().CPlusPlus)
- S = "the global namespace";
- else
- S = "the global scope";
- } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
- S = ConvertTypeToDiagnosticString(Context, Context.getTypeDeclType(Type),
- PrevArgs, NumPrevArgs);
- } else {
- // FIXME: Get these strings from some localized place
- NamedDecl *ND = cast<NamedDecl>(DC);
- if (isa<NamespaceDecl>(ND))
- S += "namespace ";
- else if (isa<ObjCMethodDecl>(ND))
- S += "method ";
- else if (isa<FunctionDecl>(ND))
- S += "function ";
-
- S += "'";
- ND->getNameForDiagnostic(S, Context.PrintingPolicy, true);
- S += "'";
- }
- NeedQuotes = false;
- break;
- }
- }
-
- if (NeedQuotes)
- Output.push_back('\'');
-
- Output.append(S.begin(), S.end());
-
- if (NeedQuotes)
- Output.push_back('\'');
-}
-
-
static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) {
if (C.getLangOptions().CPlusPlus)
return CXXRecordDecl::Create(C, TagDecl::TK_struct,
@@ -363,14 +121,15 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
GlobalNewDeleteDeclared(false),
CompleteTranslationUnit(CompleteTranslationUnit),
NumSFINAEErrors(0), NonInstantiationEntries(0),
- CurrentInstantiationScope(0)
+ CurrentInstantiationScope(0), TyposCorrected(0)
{
TUScope = 0;
if (getLangOptions().CPlusPlus)
FieldCollector.reset(new CXXFieldCollector());
// Tell diagnostics how to render things from the AST library.
- PP.getDiagnostics().SetArgToStringFn(ConvertArgToStringFn, &Context);
+ PP.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
+ &Context);
ExprEvalContexts.push_back(
ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0));
@@ -426,6 +185,12 @@ void Sema::DeleteStmt(StmtTy *S) {
/// popped.
void Sema::ActOnEndOfTranslationUnit() {
+ // Remove functions that turned out to be used.
+ UnusedStaticFuncs.erase(std::remove_if(UnusedStaticFuncs.begin(),
+ UnusedStaticFuncs.end(),
+ std::mem_fun(&FunctionDecl::isUsed)),
+ UnusedStaticFuncs.end());
+
while (1) {
// C++: Perform implicit template instantiations.
//
@@ -472,12 +237,14 @@ void Sema::ActOnEndOfTranslationUnit() {
// translation unit contains a file scope declaration of that
// identifier, with the composite type as of the end of the
// translation unit, with an initializer equal to 0.
- for (unsigned i = 0, e = TentativeDefinitionList.size(); i != e; ++i) {
- VarDecl *VD = TentativeDefinitions.lookup(TentativeDefinitionList[i]);
-
- // If the tentative definition was completed, it will be in the list, but
- // not the map.
- if (VD == 0 || VD->isInvalidDecl() || !VD->isTentativeDefinition(Context))
+ llvm::SmallSet<VarDecl *, 32> Seen;
+ for (unsigned i = 0, e = TentativeDefinitions.size(); i != e; ++i) {
+ VarDecl *VD = TentativeDefinitions[i]->getActingDefinition();
+
+ // If the tentative definition was completed, getActingDefinition() returns
+ // null. If we've already seen this variable before, insert()'s second
+ // return value is false.
+ if (VD == 0 || VD->isInvalidDecl() || !Seen.insert(VD))
continue;
if (const IncompleteArrayType *ArrayT
@@ -504,6 +271,15 @@ void Sema::ActOnEndOfTranslationUnit() {
Consumer.CompleteTentativeDefinition(VD);
}
+
+ // Output warning for unused functions.
+ for (std::vector<FunctionDecl*>::iterator
+ F = UnusedStaticFuncs.begin(),
+ FEnd = UnusedStaticFuncs.end();
+ F != FEnd;
+ ++F)
+ Diag((*F)->getLocation(), diag::warn_unused_function) << (*F)->getDeclName();
+
}
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 06e9e3ae9e64..3c7492af6108 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -60,6 +60,7 @@ namespace clang {
class CallExpr;
class DeclRefExpr;
class UnresolvedLookupExpr;
+ class UnresolvedMemberExpr;
class VarDecl;
class ParmVarDecl;
class TypedefDecl;
@@ -95,6 +96,7 @@ namespace clang {
class ObjCPropertyDecl;
class ObjCContainerDecl;
class FunctionProtoType;
+ class CXXBasePath;
class CXXBasePaths;
class CXXTemporary;
class LookupResult;
@@ -103,6 +105,7 @@ namespace clang {
class InitializationSequence;
class VisibleDeclConsumer;
class TargetAttributesSema;
+ class ADLResult;
/// BlockSemaInfo - When a block is being parsed, this contains information
/// about the block. It is pointed to from Sema::CurBlock.
@@ -150,7 +153,7 @@ class LocInfoType : public Type {
enum {
// The last number that can fit in Type's TC.
// Avoids conflict with an existing Type class.
- LocInfo = (1 << TypeClassBitSize) - 1
+ LocInfo = Type::TypeLast + 1
};
TypeSourceInfo *DeclInfo;
@@ -270,18 +273,124 @@ public:
/// not visible.
llvm::DenseMap<DeclarationName, NamedDecl *> LocallyScopedExternalDecls;
- /// \brief The set of tentative declarations seen so far in this
- /// translation unit for which no definition has been seen.
- ///
- /// The tentative declarations are indexed by the name of the
- /// declaration, and only the most recent tentative declaration for
- /// a given variable will be recorded here.
- llvm::DenseMap<DeclarationName, VarDecl *> TentativeDefinitions;
- std::vector<DeclarationName> TentativeDefinitionList;
+ /// \brief All the tentative definitions encountered in the TU.
+ std::vector<VarDecl *> TentativeDefinitions;
+
+ /// \brief The set of static functions seen so far that have not been used.
+ std::vector<FunctionDecl*> UnusedStaticFuncs;
+
+ /// An enum describing the kind of diagnostics to use when checking
+ /// access.
+ enum AccessDiagnosticsKind {
+ /// Suppress diagnostics.
+ ADK_quiet,
+
+ /// Use the normal diagnostics.
+ ADK_normal,
+
+ /// Use the diagnostics appropriate for checking a covariant
+ /// return type.
+ ADK_covariance
+ };
+
+ class AccessedEntity {
+ public:
+ enum Kind {
+ /// A member declaration found through lookup. The target is the
+ /// member.
+ Member,
+
+ /// A base-to-derived conversion. The target is the base class.
+ BaseToDerivedConversion,
+
+ /// A derived-to-base conversion. The target is the base class.
+ DerivedToBaseConversion
+ };
+
+ bool isMemberAccess() const { return K == Member; }
+
+ static AccessedEntity makeMember(CXXRecordDecl *NamingClass,
+ AccessSpecifier Access,
+ NamedDecl *Target) {
+ AccessedEntity E;
+ E.K = Member;
+ E.Access = Access;
+ E.Target = Target;
+ E.NamingClass = NamingClass;
+ return E;
+ }
+
+ static AccessedEntity makeBaseClass(bool BaseToDerived,
+ CXXRecordDecl *BaseClass,
+ CXXRecordDecl *DerivedClass,
+ AccessSpecifier Access) {
+ AccessedEntity E;
+ E.K = BaseToDerived ? BaseToDerivedConversion : DerivedToBaseConversion;
+ E.Access = Access;
+ E.Target = BaseClass;
+ E.NamingClass = DerivedClass;
+ return E;
+ }
+
+ Kind getKind() const { return Kind(K); }
+ AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
+
+ // These apply to member decls...
+ NamedDecl *getTargetDecl() const { return Target; }
+ CXXRecordDecl *getNamingClass() const { return NamingClass; }
+
+ // ...and these apply to hierarchy conversions.
+ CXXRecordDecl *getBaseClass() const { return cast<CXXRecordDecl>(Target); }
+ CXXRecordDecl *getDerivedClass() const { return NamingClass; }
+
+ private:
+ unsigned K : 2;
+ unsigned Access : 2;
+ NamedDecl *Target;
+ CXXRecordDecl *NamingClass;
+ };
- /// \brief The collection of delayed deprecation warnings.
- llvm::SmallVector<std::pair<SourceLocation,NamedDecl*>, 8>
- DelayedDeprecationWarnings;
+ struct DelayedDiagnostic {
+ enum DDKind { Deprecation, Access };
+
+ unsigned char Kind; // actually a DDKind
+ bool Triggered;
+
+ SourceLocation Loc;
+
+ union {
+ /// Deprecation.
+ struct { NamedDecl *Decl; } DeprecationData;
+
+ /// Access control.
+ AccessedEntity AccessData;
+ };
+
+ static DelayedDiagnostic makeDeprecation(SourceLocation Loc,
+ NamedDecl *D) {
+ DelayedDiagnostic DD;
+ DD.Kind = Deprecation;
+ DD.Triggered = false;
+ DD.Loc = Loc;
+ DD.DeprecationData.Decl = D;
+ return DD;
+ }
+
+ static DelayedDiagnostic makeAccess(SourceLocation Loc,
+ const AccessedEntity &Entity) {
+ DelayedDiagnostic DD;
+ DD.Kind = Access;
+ DD.Triggered = false;
+ DD.Loc = Loc;
+ DD.AccessData = Entity;
+ return DD;
+ }
+
+ };
+
+ /// \brief The stack of diagnostics that were delayed due to being
+ /// produced during the parsing of a declaration.
+ llvm::SmallVector<DelayedDiagnostic, 8> DelayedDiagnostics;
/// \brief The depth of the current ParsingDeclaration stack.
/// If nonzero, we are currently parsing a declaration (and
@@ -517,8 +626,8 @@ public:
//===--------------------------------------------------------------------===//
// Type Analysis / Processing: SemaType.cpp.
//
+
QualType adjustParameterType(QualType T);
- void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL);
QualType BuildPointerType(QualType T, unsigned Quals,
SourceLocation Loc, DeclarationName Entity);
QualType BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
@@ -548,13 +657,15 @@ public:
static QualType GetTypeFromParser(TypeTy *Ty, TypeSourceInfo **TInfo = 0);
bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
bool CheckDistantExceptionSpec(QualType T);
+ bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New);
bool CheckEquivalentExceptionSpec(
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc);
bool CheckEquivalentExceptionSpec(
const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
const FunctionProtoType *Old, SourceLocation OldLoc,
- const FunctionProtoType *New, SourceLocation NewLoc);
+ const FunctionProtoType *New, SourceLocation NewLoc,
+ bool *MissingEmptyExceptionSpecification = 0);
bool CheckExceptionSpecSubset(
const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
const FunctionProtoType *Superset, SourceLocation SuperLoc,
@@ -634,6 +745,7 @@ public:
bool &OverloadableAttrRequired);
void CheckMain(FunctionDecl *FD);
virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D);
+ virtual void ActOnObjCCatchParam(DeclPtrTy D);
virtual void ActOnParamDefaultArgument(DeclPtrTy param,
SourceLocation EqualLoc,
ExprArg defarg);
@@ -950,31 +1062,38 @@ public:
// Members have to be NamespaceDecl* or TranslationUnitDecl*.
// TODO: make this is a typesafe union.
typedef llvm::SmallPtrSet<DeclContext *, 16> AssociatedNamespaceSet;
-
- typedef llvm::SmallPtrSet<AnyFunctionDecl, 16> FunctionSet;
typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet;
+ void AddOverloadCandidate(NamedDecl *Function,
+ AccessSpecifier Access,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet &CandidateSet);
+
void AddOverloadCandidate(FunctionDecl *Function,
+ AccessSpecifier Access,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool ForceRValue = false,
bool PartialOverloading = false);
- void AddFunctionCandidates(const FunctionSet &Functions,
+ void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false);
- void AddMethodCandidate(NamedDecl *Decl,
- QualType ObjectType, Expr **Args, unsigned NumArgs,
+ void AddMethodCandidate(NamedDecl *Decl, AccessSpecifier Access,
+ QualType ObjectType,
+ Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversion = false,
bool ForceRValue = false);
- void AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
- QualType ObjectType, Expr **Args, unsigned NumArgs,
+ void AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access,
+ CXXRecordDecl *ActingContext, QualType ObjectType,
+ Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool ForceRValue = false);
void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
+ AccessSpecifier Access,
CXXRecordDecl *ActingContext,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
@@ -983,20 +1102,24 @@ public:
bool SuppressUserConversions = false,
bool ForceRValue = false);
void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
+ AccessSpecifier Access,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool ForceRValue = false);
void AddConversionCandidate(CXXConversionDecl *Conversion,
+ AccessSpecifier Access,
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet);
void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
+ AccessSpecifier Access,
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet);
void AddSurrogateCandidate(CXXConversionDecl *Conversion,
+ AccessSpecifier Access,
CXXRecordDecl *ActingContext,
const FunctionProtoType *Proto,
QualType ObjectTy, Expr **Args, unsigned NumArgs,
@@ -1021,12 +1144,14 @@ public:
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet);
void AddArgumentDependentLookupCandidates(DeclarationName Name,
+ bool Operator,
Expr **Args, unsigned NumArgs,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
bool PartialOverloading = false);
bool isBetterOverloadCandidate(const OverloadCandidate& Cand1,
- const OverloadCandidate& Cand2);
+ const OverloadCandidate& Cand2,
+ SourceLocation Loc);
OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet,
SourceLocation Loc,
OverloadCandidateSet::iterator& Best);
@@ -1072,12 +1197,12 @@ public:
OwningExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc,
unsigned Opc,
- FunctionSet &Functions,
+ const UnresolvedSetImpl &Fns,
ExprArg input);
OwningExprResult CreateOverloadedBinOp(SourceLocation OpLoc,
unsigned Opc,
- FunctionSet &Functions,
+ const UnresolvedSetImpl &Fns,
Expr *LHS, Expr *RHS);
OwningExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
@@ -1217,16 +1342,15 @@ public:
bool LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
bool AllowBuiltinCreation = false,
bool EnteringContext = false);
-
ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II);
void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
QualType T1, QualType T2,
- FunctionSet &Functions);
+ UnresolvedSetImpl &Functions);
void ArgumentDependentLookup(DeclarationName Name, bool Operator,
Expr **Args, unsigned NumArgs,
- FunctionSet &Functions);
+ ADLResult &Functions);
void LookupVisibleDecls(Scope *S, LookupNameKind Kind,
VisibleDeclConsumer &Consumer);
@@ -1302,6 +1426,14 @@ public:
void CollectImmediateProperties(ObjCContainerDecl *CDecl,
llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap);
+ /// LookupPropertyDecl - Looks up a property in the current class and all
+ /// its protocols.
+ ObjCPropertyDecl *LookupPropertyDecl(const ObjCContainerDecl *CDecl,
+ IdentifierInfo *II);
+
+ ObjCIvarDecl *SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl,
+ IdentifierInfo *NameII);
+
/// AtomicPropertySetterGetterRules - This routine enforces the rule (via
/// warning) when atomic property has one but not the other user-declared
/// setter or getter.
@@ -1373,6 +1505,8 @@ public:
SourceLocation ElseLoc, StmtArg ElseVal);
virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond,
DeclPtrTy CondVar);
+ virtual void ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch,
+ StmtArg Body);
virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
StmtArg Switch, StmtArg Body);
virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
@@ -1416,7 +1550,7 @@ public:
bool IsVolatile,
unsigned NumOutputs,
unsigned NumInputs,
- std::string *Names,
+ IdentifierInfo **Names,
MultiExprArg Constraints,
MultiExprArg Exprs,
ExprArg AsmString,
@@ -1466,6 +1600,8 @@ public:
void PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy D);
void EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc);
+ void HandleDelayedDeprecationCheck(DelayedDiagnostic &DD, Decl *Ctx);
+
//===--------------------------------------------------------------------===//
// Expression Parsing Callbacks: SemaExpr.cpp.
@@ -1770,7 +1906,8 @@ public:
// Act on C++ namespaces
virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc,
IdentifierInfo *Ident,
- SourceLocation LBrace);
+ SourceLocation LBrace,
+ AttributeList *AttrList);
virtual void ActOnFinishNamespaceDef(DeclPtrTy Dcl, SourceLocation RBrace);
virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope,
@@ -1847,7 +1984,8 @@ public:
QualType DeclInitType,
CXXConstructorDecl *Constructor,
MultiExprArg Exprs,
- bool RequiresZeroInit = false);
+ bool RequiresZeroInit = false,
+ bool BaseInitialization = false);
// FIXME: Can re remove this and have the above BuildCXXConstructExpr check if
// the constructor can be elidable?
@@ -1856,13 +1994,8 @@ public:
CXXConstructorDecl *Constructor,
bool Elidable,
MultiExprArg Exprs,
- bool RequiresZeroInit = false);
-
- OwningExprResult BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Cons,
- QualType writtenTy,
- SourceLocation tyBeginLoc,
- MultiExprArg Args,
- SourceLocation rParenLoc);
+ bool RequiresZeroInit = false,
+ bool BaseInitialization = false);
OwningExprResult BuildCXXCastArgument(SourceLocation CastLoc,
QualType Ty,
@@ -1878,7 +2011,7 @@ public:
/// FinalizeVarWithDestructor - Prepare for calling destructor on the
/// constructed variable.
- void FinalizeVarWithDestructor(VarDecl *VD, QualType DeclInitType);
+ void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType);
/// DefineImplicitDefaultConstructor - Checks for feasibility of
/// defining this constructor as the default constructor.
@@ -1917,14 +2050,6 @@ public:
Expr **Args, unsigned NumArgs,
SourceLocation Loc,
InitializationKind Kind);
-
- CXXConstructorDecl *
- PerformInitializationByConstructor(QualType ClassType,
- MultiExprArg ArgsPtr,
- SourceLocation Loc, SourceRange Range,
- DeclarationName InitEntity,
- InitializationKind Kind,
- ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs);
bool CompleteConstructorCall(CXXConstructorDecl *Constructor,
MultiExprArg ArgsPtr,
@@ -2218,9 +2343,10 @@ public:
CXXRecordDecl *ClassDecl);
bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
- CXXBaseOrMemberInitializer **Initializers,
- unsigned NumInitializers,
- bool IsImplicitConstructor);
+ CXXBaseOrMemberInitializer **Initializers,
+ unsigned NumInitializers,
+ bool IsImplicitConstructor,
+ bool AnyErrors);
/// MarkBaseAndMemberDestructorsReferenced - Given a destructor decl,
/// mark all its non-trivial member and base destructor declarations
@@ -2252,7 +2378,8 @@ public:
virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
- MemInitTy **MemInits, unsigned NumMemInits);
+ MemInitTy **MemInits, unsigned NumMemInits,
+ bool AnyErrors);
void CheckCompletedCXXClass(CXXRecordDecl *Record);
virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
@@ -2326,7 +2453,7 @@ public:
SourceLocation Loc, SourceRange Range,
bool IgnoreAccess = false);
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
- unsigned InaccessibleBaseID,
+ AccessDiagnosticsKind ADK,
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
DeclarationName Name);
@@ -2353,22 +2480,43 @@ public:
// C++ Access Control
//
+ enum AccessResult {
+ AR_accessible,
+ AR_inaccessible,
+ AR_dependent,
+ AR_delayed
+ };
+
bool SetMemberAccessSpecifier(NamedDecl *MemberDecl,
NamedDecl *PrevMemberDecl,
AccessSpecifier LexicalAS);
- const CXXBaseSpecifier *FindInaccessibleBase(QualType Derived, QualType Base,
- CXXBasePaths &Paths,
- bool NoPrivileges = false);
-
- void CheckAccess(const LookupResult &R);
- bool CheckAccess(const LookupResult &R, NamedDecl *D, AccessSpecifier Access);
-
- bool CheckBaseClassAccess(QualType Derived, QualType Base,
- unsigned InaccessibleBaseID,
- CXXBasePaths& Paths, SourceLocation AccessLoc,
- DeclarationName Name);
-
+ AccessResult CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
+ NamedDecl *D,
+ AccessSpecifier Access);
+ AccessResult CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
+ NamedDecl *D,
+ AccessSpecifier Access);
+ AccessResult CheckConstructorAccess(SourceLocation Loc,
+ CXXConstructorDecl *D,
+ AccessSpecifier Access);
+ AccessResult CheckDestructorAccess(SourceLocation Loc,
+ const RecordType *Record);
+ AccessResult CheckMemberOperatorAccess(SourceLocation Loc,
+ Expr *ObjectExpr,
+ NamedDecl *D,
+ AccessSpecifier Access);
+ AccessResult CheckBaseClassAccess(SourceLocation AccessLoc,
+ bool IsBaseToDerived,
+ QualType Base, QualType Derived,
+ const CXXBasePath &Path,
+ bool ForceCheck = false,
+ bool ForceUnprivileged = false,
+ AccessDiagnosticsKind ADK = ADK_normal);
+
+ void CheckLookupAccess(const LookupResult &R);
+
+ void HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx);
enum AbstractDiagSelID {
AbstractNone = -1,
@@ -2758,17 +2906,28 @@ public:
///
TemplateArgumentList *Deduced;
+ /// \brief The source location at which template argument
+ /// deduction is occurring.
+ SourceLocation Loc;
+
// do not implement these
TemplateDeductionInfo(const TemplateDeductionInfo&);
TemplateDeductionInfo &operator=(const TemplateDeductionInfo&);
public:
- TemplateDeductionInfo(ASTContext &Context) : Context(Context), Deduced(0) { }
+ TemplateDeductionInfo(ASTContext &Context, SourceLocation Loc)
+ : Context(Context), Deduced(0), Loc(Loc) { }
~TemplateDeductionInfo() {
// FIXME: if (Deduced) Deduced->Destroy(Context);
}
+ /// \brief Returns the location at which template argument is
+ /// occuring.
+ SourceLocation getLocation() const {
+ return Loc;
+ }
+
/// \brief Take ownership of the deduced template argument list.
TemplateArgumentList *take() {
TemplateArgumentList *Result = Deduced;
@@ -2866,20 +3025,21 @@ public:
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
+ SourceLocation Loc,
TemplatePartialOrderingContext TPOC);
- FunctionDecl *getMostSpecialized(FunctionDecl **Specializations,
- unsigned NumSpecializations,
- TemplatePartialOrderingContext TPOC,
- SourceLocation Loc,
- const PartialDiagnostic &NoneDiag,
- const PartialDiagnostic &AmbigDiag,
- const PartialDiagnostic &CandidateDiag,
- unsigned *Index = 0);
+ UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin,
+ UnresolvedSetIterator SEnd,
+ TemplatePartialOrderingContext TPOC,
+ SourceLocation Loc,
+ const PartialDiagnostic &NoneDiag,
+ const PartialDiagnostic &AmbigDiag,
+ const PartialDiagnostic &CandidateDiag);
ClassTemplatePartialSpecializationDecl *
getMoreSpecializedPartialSpecialization(
ClassTemplatePartialSpecializationDecl *PS1,
- ClassTemplatePartialSpecializationDecl *PS2);
+ ClassTemplatePartialSpecializationDecl *PS2,
+ SourceLocation Loc);
void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
bool OnlyDeduced,
@@ -2893,7 +3053,8 @@ public:
//
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D,
- const TemplateArgumentList *Innermost = 0);
+ const TemplateArgumentList *Innermost = 0,
+ bool RelativeToPrimary = false);
/// \brief A template instantiation that is currently in progress.
struct ActiveTemplateInstantiation {
@@ -3243,6 +3404,9 @@ public:
/// variables.
LocalInstantiationScope *CurrentInstantiationScope;
+ /// \brief The number of typos corrected by CorrectTypo.
+ unsigned TyposCorrected;
+
/// \brief An entity for which implicit template instantiation is required.
///
/// The source location associated with the declaration is the first place in
@@ -3550,6 +3714,11 @@ public:
// to their respective pointers (C99 6.3.2.1).
void DefaultFunctionArrayConversion(Expr *&expr);
+ // DefaultFunctionArrayLvalueConversion - converts functions and
+ // arrays to their respective pointers and performs the
+ // lvalue-to-rvalue conversion.
+ void DefaultFunctionArrayLvalueConversion(Expr *&expr);
+
// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that
// do not have a prototype. Integer promotions are performed on each
// argument, and arguments that have type float are promoted to double.
@@ -3944,12 +4113,15 @@ public:
//===--------------------------------------------------------------------===//
// Extra semantic analysis beyond the C type system
+
+public:
+ SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL,
+ unsigned ByteNo) const;
+
private:
bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall);
- SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL,
- unsigned ByteNo) const;
bool CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall);
bool CheckObjCString(Expr *Arg);
@@ -3957,7 +4129,7 @@ private:
CallExpr *TheCall);
bool SemaBuiltinVAStart(CallExpr *TheCall);
bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);
- bool SemaBuiltinUnaryFP(CallExpr *TheCall);
+ bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned LastArg=1);
bool SemaBuiltinStackAddress(CallExpr *TheCall);
public:
@@ -3987,7 +4159,6 @@ private:
const PartialDiagnostic &PD,
bool Equality = false);
void CheckImplicitConversion(Expr *E, QualType Target);
-
};
//===--------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 51f9e300ef90..eca8bb4c2a9b 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -16,6 +16,8 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+
using namespace clang;
/// SetMemberAccessSpecifier - Set the access specifier of a member.
@@ -47,192 +49,500 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
return false;
}
-/// Find a class on the derivation path between Derived and Base that is
-/// inaccessible. If @p NoPrivileges is true, special access rights (members
-/// and friends) are not considered.
-const CXXBaseSpecifier *Sema::FindInaccessibleBase(
- QualType Derived, QualType Base, CXXBasePaths &Paths, bool NoPrivileges) {
- Base = Context.getCanonicalType(Base).getUnqualifiedType();
- assert(!Paths.isAmbiguous(Base) &&
- "Can't check base class access if set of paths is ambiguous");
- assert(Paths.isRecordingPaths() &&
- "Can't check base class access without recorded paths");
-
-
- const CXXBaseSpecifier *InaccessibleBase = 0;
-
- const CXXRecordDecl *CurrentClassDecl = 0;
- if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl()))
- CurrentClassDecl = MD->getParent();
-
- for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end();
- Path != PathsEnd; ++Path) {
-
- bool FoundInaccessibleBase = false;
-
- for (CXXBasePath::const_iterator Element = Path->begin(),
- ElementEnd = Path->end(); Element != ElementEnd; ++Element) {
- const CXXBaseSpecifier *Base = Element->Base;
-
- switch (Base->getAccessSpecifier()) {
- default:
- assert(0 && "invalid access specifier");
- case AS_public:
- // Nothing to do.
- break;
- case AS_private:
- // FIXME: Check if the current function/class is a friend.
- if (NoPrivileges || CurrentClassDecl != Element->Class)
- FoundInaccessibleBase = true;
- break;
- case AS_protected:
- // FIXME: Implement
- break;
- }
+namespace {
+struct EffectiveContext {
+ EffectiveContext() : Record(0), Function(0) {}
+
+ explicit EffectiveContext(DeclContext *DC) {
+ if (isa<FunctionDecl>(DC)) {
+ Function = cast<FunctionDecl>(DC);
+ DC = Function->getDeclContext();
+ } else
+ Function = 0;
+
+ if (isa<CXXRecordDecl>(DC))
+ Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
+ else
+ Record = 0;
+ }
+
+ bool isClass(const CXXRecordDecl *R) const {
+ return R->getCanonicalDecl() == Record;
+ }
+
+ CXXRecordDecl *Record;
+ FunctionDecl *Function;
+};
+}
+
+static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
+ CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
+ while (DeclaringClass->isAnonymousStructOrUnion())
+ DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
+ return DeclaringClass;
+}
+
+static Sema::AccessResult GetFriendKind(Sema &S,
+ const EffectiveContext &EC,
+ const CXXRecordDecl *Class) {
+ if (EC.isClass(Class))
+ return Sema::AR_accessible;
+
+ // FIXME: implement
+ return Sema::AR_inaccessible;
+}
- if (FoundInaccessibleBase) {
- InaccessibleBase = Base;
- break;
+/// Finds the best path from the naming class to the declaring class,
+/// taking friend declarations into account.
+///
+/// \return null if friendship is dependent
+static CXXBasePath *FindBestPath(Sema &S,
+ const EffectiveContext &EC,
+ CXXRecordDecl *Derived,
+ CXXRecordDecl *Base,
+ CXXBasePaths &Paths) {
+ // Derive the paths to the desired base.
+ bool isDerived = Derived->isDerivedFrom(Base, Paths);
+ assert(isDerived && "derived class not actually derived from base");
+ (void) isDerived;
+
+ CXXBasePath *BestPath = 0;
+
+ // Derive the friend-modified access along each path.
+ for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
+ PI != PE; ++PI) {
+
+ // Walk through the path backwards.
+ AccessSpecifier PathAccess = AS_public;
+ CXXBasePath::iterator I = PI->end(), E = PI->begin();
+ while (I != E) {
+ --I;
+
+ AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
+ if (BaseAccess != AS_public) {
+ switch (GetFriendKind(S, EC, I->Class)) {
+ case Sema::AR_inaccessible: break;
+ case Sema::AR_accessible: BaseAccess = AS_public; break;
+ case Sema::AR_dependent: return 0;
+ case Sema::AR_delayed:
+ llvm_unreachable("friend resolution is never delayed"); break;
+ }
}
+
+ PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess);
}
- if (!FoundInaccessibleBase) {
- // We found a path to the base, our work here is done.
- return 0;
+ // Note that we modify the path's Access field to the
+ // friend-modified access.
+ if (BestPath == 0 || PathAccess < BestPath->Access) {
+ BestPath = &*PI;
+ BestPath->Access = PathAccess;
}
}
- assert(InaccessibleBase && "no path found, but no inaccessible base");
- return InaccessibleBase;
+ return BestPath;
}
-/// CheckBaseClassAccess - Check that a derived class can access its base class
-/// and report an error if it can't. [class.access.base]
-bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base,
- unsigned InaccessibleBaseID,
- CXXBasePaths &Paths, SourceLocation AccessLoc,
- DeclarationName Name) {
+/// Diagnose the path which caused the given declaration or base class
+/// to become inaccessible.
+static void DiagnoseAccessPath(Sema &S,
+ const EffectiveContext &EC,
+ CXXRecordDecl *NamingClass,
+ CXXRecordDecl *DeclaringClass,
+ NamedDecl *D, AccessSpecifier Access) {
+ // Easy case: the decl's natural access determined its path access.
+ // We have to check against AS_private here in case Access is AS_none,
+ // indicating a non-public member of a private base class.
+ //
+ // DependentFriend should be impossible here.
+ if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
+ switch (GetFriendKind(S, EC, DeclaringClass)) {
+ case Sema::AR_inaccessible: {
+ S.Diag(D->getLocation(), diag::note_access_natural)
+ << (unsigned) (Access == AS_protected)
+ << /*FIXME: not implicitly*/ 0;
+ return;
+ }
- if (!getLangOptions().AccessControl)
- return false;
- const CXXBaseSpecifier *InaccessibleBase = FindInaccessibleBase(
- Derived, Base, Paths);
+ case Sema::AR_accessible: break;
- if (InaccessibleBase) {
- Diag(AccessLoc, InaccessibleBaseID)
- << Derived << Base << Name;
+ case Sema::AR_dependent:
+ case Sema::AR_delayed:
+ llvm_unreachable("dependent/delayed not allowed");
+ return;
+ }
+ }
- AccessSpecifier AS = InaccessibleBase->getAccessSpecifierAsWritten();
+ CXXBasePaths Paths;
+ CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, Paths);
- // If there's no written access specifier, then the inheritance specifier
- // is implicitly private.
- if (AS == AS_none)
- Diag(InaccessibleBase->getSourceRange().getBegin(),
- diag::note_inheritance_implicitly_private_here);
- else
- Diag(InaccessibleBase->getSourceRange().getBegin(),
- diag::note_inheritance_specifier_here) << AS;
+ CXXBasePath::iterator I = Path.end(), E = Path.begin();
+ while (I != E) {
+ --I;
- return true;
+ const CXXBaseSpecifier *BS = I->Base;
+ AccessSpecifier BaseAccess = BS->getAccessSpecifier();
+
+ // If this is public inheritance, or the derived class is a friend,
+ // skip this step.
+ if (BaseAccess == AS_public)
+ continue;
+
+ switch (GetFriendKind(S, EC, I->Class)) {
+ case Sema::AR_accessible: continue;
+ case Sema::AR_inaccessible: break;
+
+ case Sema::AR_dependent:
+ case Sema::AR_delayed:
+ llvm_unreachable("dependent friendship, should not be diagnosing");
+ }
+
+ // Check whether this base specifier is the tighest point
+ // constraining access. We have to check against AS_private for
+ // the same reasons as above.
+ if (BaseAccess == AS_private || BaseAccess >= Access) {
+
+ // We're constrained by inheritance, but we want to say
+ // "declared private here" if we're diagnosing a hierarchy
+ // conversion and this is the final step.
+ unsigned diagnostic;
+ if (D) diagnostic = diag::note_access_constrained_by_path;
+ else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural;
+ else diagnostic = diag::note_access_constrained_by_path;
+
+ S.Diag(BS->getSourceRange().getBegin(), diagnostic)
+ << BS->getSourceRange()
+ << (BaseAccess == AS_protected)
+ << (BS->getAccessSpecifierAsWritten() == AS_none);
+ return;
+ }
}
- return false;
+ llvm_unreachable("access not apparently constrained by path");
}
-/// Diagnose the path which caused the given declaration to become
-/// inaccessible.
-static void DiagnoseAccessPath(Sema &S, const LookupResult &R, NamedDecl *D,
- AccessSpecifier Access) {
- // Easy case: the decl's natural access determined its path access.
- if (Access == D->getAccess() || D->getAccess() == AS_private) {
- S.Diag(D->getLocation(), diag::note_access_natural)
- << (unsigned) (Access == AS_protected);
- return;
+/// Diagnose an inaccessible class member.
+static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc,
+ const EffectiveContext &EC,
+ CXXRecordDecl *NamingClass,
+ AccessSpecifier Access,
+ const Sema::AccessedEntity &Entity) {
+ NamedDecl *D = Entity.getTargetDecl();
+ CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
+
+ if (isa<CXXConstructorDecl>(D)) {
+ unsigned DiagID = (Access == AS_protected ? diag::err_access_ctor_protected
+ : diag::err_access_ctor_private);
+ S.Diag(Loc, DiagID)
+ << S.Context.getTypeDeclType(DeclaringClass);
+ } else {
+ unsigned DiagID = (Access == AS_protected ? diag::err_access_protected
+ : diag::err_access_private);
+ S.Diag(Loc, DiagID)
+ << D->getDeclName()
+ << S.Context.getTypeDeclType(DeclaringClass);
}
+ DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access);
+}
- // TODO: flesh this out
- S.Diag(D->getLocation(), diag::note_access_constrained_by_path)
- << (unsigned) (Access == AS_protected);
+/// Diagnose an inaccessible hierarchy conversion.
+static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc,
+ const EffectiveContext &EC,
+ AccessSpecifier Access,
+ const Sema::AccessedEntity &Entity,
+ Sema::AccessDiagnosticsKind ADK) {
+ if (ADK == Sema::ADK_covariance) {
+ S.Diag(Loc, diag::err_covariant_return_inaccessible_base)
+ << S.Context.getTypeDeclType(Entity.getDerivedClass())
+ << S.Context.getTypeDeclType(Entity.getBaseClass())
+ << (Access == AS_protected);
+ } else if (Entity.getKind() == Sema::AccessedEntity::BaseToDerivedConversion) {
+ S.Diag(Loc, diag::err_downcast_from_inaccessible_base)
+ << S.Context.getTypeDeclType(Entity.getDerivedClass())
+ << S.Context.getTypeDeclType(Entity.getBaseClass())
+ << (Access == AS_protected);
+ } else {
+ S.Diag(Loc, diag::err_upcast_to_inaccessible_base)
+ << S.Context.getTypeDeclType(Entity.getDerivedClass())
+ << S.Context.getTypeDeclType(Entity.getBaseClass())
+ << (Access == AS_protected);
+ }
+ DiagnoseAccessPath(S, EC, Entity.getDerivedClass(),
+ Entity.getBaseClass(), 0, Access);
}
-/// Checks access to the given declaration in the current context.
-///
-/// \param R the means via which the access was made; must have a naming
-/// class set
-/// \param D the declaration accessed
-/// \param Access the best access along any inheritance path from the
-/// naming class to the declaration. AS_none means the path is impossible
-bool Sema::CheckAccess(const LookupResult &R, NamedDecl *D,
- AccessSpecifier Access) {
- assert(R.getNamingClass() && "performing access check without naming class");
+static void DiagnoseBadAccess(Sema &S,
+ SourceLocation Loc,
+ const EffectiveContext &EC,
+ CXXRecordDecl *NamingClass,
+ AccessSpecifier Access,
+ const Sema::AccessedEntity &Entity,
+ Sema::AccessDiagnosticsKind ADK) {
+ if (Entity.isMemberAccess())
+ DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity);
+ else
+ DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity, ADK);
+}
- // If the access path is public, it's accessible everywhere.
- if (Access == AS_public)
- return false;
- // Otherwise, derive the current class context.
- DeclContext *DC = CurContext;
- while (isa<CXXRecordDecl>(DC) &&
- cast<CXXRecordDecl>(DC)->isAnonymousStructOrUnion())
- DC = DC->getParent();
-
- CXXRecordDecl *CurRecord;
- if (isa<CXXRecordDecl>(DC))
- CurRecord = cast<CXXRecordDecl>(DC);
- else if (isa<CXXMethodDecl>(DC))
- CurRecord = cast<CXXMethodDecl>(DC)->getParent();
- else {
- Diag(R.getNameLoc(), diag::err_access_outside_class)
- << (Access == AS_protected);
- DiagnoseAccessPath(*this, R, D, Access);
- return true;
+/// Try to elevate access using friend declarations. This is
+/// potentially quite expensive.
+static void TryElevateAccess(Sema &S,
+ const EffectiveContext &EC,
+ const Sema::AccessedEntity &Entity,
+ AccessSpecifier &Access) {
+ CXXRecordDecl *DeclaringClass;
+ if (Entity.isMemberAccess()) {
+ DeclaringClass = FindDeclaringClass(Entity.getTargetDecl());
+ } else {
+ DeclaringClass = Entity.getBaseClass();
}
+ CXXRecordDecl *NamingClass = Entity.getNamingClass();
+
+ // Adjust the declaration of the referred entity.
+ AccessSpecifier DeclAccess = AS_none;
+ if (Entity.isMemberAccess()) {
+ NamedDecl *Target = Entity.getTargetDecl();
+
+ DeclAccess = Target->getAccess();
+ if (DeclAccess != AS_public) {
+ switch (GetFriendKind(S, EC, DeclaringClass)) {
+ case Sema::AR_accessible: DeclAccess = AS_public; break;
+ case Sema::AR_inaccessible: break;
+ case Sema::AR_dependent: /* FIXME: delay dependent friendship */ return;
+ case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
+ }
+ }
+
+ if (DeclaringClass == NamingClass) {
+ Access = DeclAccess;
+ return;
+ }
+ }
+
+ assert(DeclaringClass != NamingClass);
- CXXRecordDecl *NamingClass = R.getNamingClass();
+ // Append the declaration's access if applicable.
+ CXXBasePaths Paths;
+ CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(),
+ DeclaringClass, Paths);
+ if (!Path) {
+ // FIXME: delay dependent friendship
+ return;
+ }
+
+ // Grab the access along the best path.
+ AccessSpecifier NewAccess = Path->Access;
+ if (Entity.isMemberAccess())
+ NewAccess = CXXRecordDecl::MergeAccess(NewAccess, DeclAccess);
+
+ assert(NewAccess <= Access && "access along best path worse than direct?");
+ Access = NewAccess;
+}
+
+/// Checks access to an entity from the given effective context.
+static Sema::AccessResult CheckEffectiveAccess(Sema &S,
+ const EffectiveContext &EC,
+ SourceLocation Loc,
+ Sema::AccessedEntity const &Entity,
+ Sema::AccessDiagnosticsKind ADK) {
+ AccessSpecifier Access = Entity.getAccess();
+ assert(Access != AS_public);
+
+ CXXRecordDecl *NamingClass = Entity.getNamingClass();
while (NamingClass->isAnonymousStructOrUnion())
// This should be guaranteed by the fact that the decl has
// non-public access. If not, we should make it guaranteed!
NamingClass = cast<CXXRecordDecl>(NamingClass);
+ if (!EC.Record) {
+ TryElevateAccess(S, EC, Entity, Access);
+ if (Access == AS_public) return Sema::AR_accessible;
+
+ if (ADK != Sema::ADK_quiet)
+ DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK);
+ return Sema::AR_inaccessible;
+ }
+
// White-list accesses from within the declaring class.
- if (Access != AS_none &&
- CurRecord->getCanonicalDecl() == NamingClass->getCanonicalDecl())
- return false;
+ if (Access != AS_none && EC.isClass(NamingClass))
+ return Sema::AR_accessible;
+
+ // If the access is worse than 'protected', try to promote to it using
+ // friend declarations.
+ bool TriedElevation = false;
+ if (Access != AS_protected) {
+ TryElevateAccess(S, EC, Entity, Access);
+ if (Access == AS_public) return Sema::AR_accessible;
+ TriedElevation = true;
+ }
// Protected access.
if (Access == AS_protected) {
// FIXME: implement [class.protected]p1
- if (CurRecord->isDerivedFrom(NamingClass))
- return false;
+ if (EC.Record->isDerivedFrom(NamingClass))
+ return Sema::AR_accessible;
- // FIXME: dependent classes
+ // FIXME: delay dependent classes
}
- // FIXME: friends
+ // We're about to reject; one last chance to promote access.
+ if (!TriedElevation) {
+ TryElevateAccess(S, EC, Entity, Access);
+ if (Access == AS_public) return Sema::AR_accessible;
+ }
+
+ // Okay, that's it, reject it.
+ if (ADK != Sema::ADK_quiet)
+ DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK);
+ return Sema::AR_inaccessible;
+}
- // Okay, it's a bad access, reject it.
+static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
+ const Sema::AccessedEntity &Entity,
+ Sema::AccessDiagnosticsKind ADK
+ = Sema::ADK_normal) {
+ // If the access path is public, it's accessible everywhere.
+ if (Entity.getAccess() == AS_public)
+ return Sema::AR_accessible;
+
+ // If we're currently parsing a top-level declaration, delay
+ // diagnostics. This is the only case where parsing a declaration
+ // can actually change our effective context for the purposes of
+ // access control.
+ if (S.CurContext->isFileContext() && S.ParsingDeclDepth) {
+ assert(ADK == Sema::ADK_normal && "delaying abnormal access check");
+ S.DelayedDiagnostics.push_back(
+ Sema::DelayedDiagnostic::makeAccess(Loc, Entity));
+ return Sema::AR_delayed;
+ }
-
- CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
+ return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
+ Loc, Entity, ADK);
+}
- if (Access == AS_protected) {
- Diag(R.getNameLoc(), diag::err_access_protected)
- << Context.getTypeDeclType(DeclaringClass)
- << Context.getTypeDeclType(CurRecord);
- DiagnoseAccessPath(*this, R, D, Access);
- return true;
- }
+void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
+ // Pretend we did this from the context of the newly-parsed
+ // declaration.
+ EffectiveContext EC(Ctx->getDeclContext());
+
+ if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.AccessData, ADK_normal))
+ DD.Triggered = true;
+}
+
+Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
+ NamedDecl *D,
+ AccessSpecifier Access) {
+ if (!getLangOptions().AccessControl || !E->getNamingClass())
+ return AR_accessible;
- assert(Access == AS_private || Access == AS_none);
- Diag(R.getNameLoc(), diag::err_access_private)
- << Context.getTypeDeclType(DeclaringClass)
- << Context.getTypeDeclType(CurRecord);
- DiagnoseAccessPath(*this, R, D, Access);
- return true;
+ return CheckAccess(*this, E->getNameLoc(),
+ AccessedEntity::makeMember(E->getNamingClass(), Access, D));
+}
+
+/// Perform access-control checking on a previously-unresolved member
+/// access which has now been resolved to a member.
+Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
+ NamedDecl *D,
+ AccessSpecifier Access) {
+ if (!getLangOptions().AccessControl)
+ return AR_accessible;
+
+ return CheckAccess(*this, E->getMemberLoc(),
+ AccessedEntity::makeMember(E->getNamingClass(), Access, D));
+}
+
+Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
+ const RecordType *RT) {
+ if (!getLangOptions().AccessControl)
+ return AR_accessible;
+
+ CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
+ CXXDestructorDecl *Dtor = NamingClass->getDestructor(Context);
+
+ AccessSpecifier Access = Dtor->getAccess();
+ if (Access == AS_public)
+ return AR_accessible;
+
+ return CheckAccess(*this, Loc,
+ AccessedEntity::makeMember(NamingClass, Access, Dtor));
+}
+
+/// Checks access to a constructor.
+Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
+ CXXConstructorDecl *Constructor,
+ AccessSpecifier Access) {
+ if (!getLangOptions().AccessControl)
+ return AR_accessible;
+
+ CXXRecordDecl *NamingClass = Constructor->getParent();
+ return CheckAccess(*this, UseLoc,
+ AccessedEntity::makeMember(NamingClass, Access, Constructor));
+}
+
+/// Checks access to an overloaded member operator, including
+/// conversion operators.
+Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
+ Expr *ObjectExpr,
+ NamedDecl *MemberOperator,
+ AccessSpecifier Access) {
+ if (!getLangOptions().AccessControl)
+ return AR_accessible;
+
+ const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>();
+ assert(RT && "found member operator but object expr not of record type");
+ CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
+
+ return CheckAccess(*this, OpLoc,
+ AccessedEntity::makeMember(NamingClass, Access, MemberOperator));
+}
+
+/// Checks access for a hierarchy conversion.
+///
+/// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
+/// or a derived-to-base conversion (false)
+/// \param ForceCheck true if this check should be performed even if access
+/// control is disabled; some things rely on this for semantics
+/// \param ForceUnprivileged true if this check should proceed as if the
+/// context had no special privileges
+/// \param ADK controls the kind of diagnostics that are used
+Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
+ bool IsBaseToDerived,
+ QualType Base,
+ QualType Derived,
+ const CXXBasePath &Path,
+ bool ForceCheck,
+ bool ForceUnprivileged,
+ AccessDiagnosticsKind ADK) {
+ if (!ForceCheck && !getLangOptions().AccessControl)
+ return AR_accessible;
+
+ if (Path.Access == AS_public)
+ return AR_accessible;
+
+ // TODO: preserve the information about which types exactly were used.
+ CXXRecordDecl *BaseD, *DerivedD;
+ BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
+ DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
+ AccessedEntity Entity = AccessedEntity::makeBaseClass(IsBaseToDerived,
+ BaseD, DerivedD,
+ Path.Access);
+
+ if (ForceUnprivileged)
+ return CheckEffectiveAccess(*this, EffectiveContext(),
+ AccessLoc, Entity, ADK);
+ return CheckAccess(*this, AccessLoc, Entity, ADK);
}
/// Checks access to all the declarations in the given result set.
-void Sema::CheckAccess(const LookupResult &R) {
+void Sema::CheckLookupAccess(const LookupResult &R) {
+ assert(getLangOptions().AccessControl
+ && "performing access check without access control");
+ assert(R.getNamingClass() && "performing access check without naming class");
+
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
- CheckAccess(R, *I, I.getAccess());
+ if (I.getAccess() != AS_public)
+ CheckAccess(*this, R.getNameLoc(),
+ AccessedEntity::makeMember(R.getNamingClass(),
+ I.getAccess(), *I));
}
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 57c4f9bc2a27..0097cd363c8c 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -204,7 +204,30 @@ bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) {
T2 = T2PtrType->getPointeeType();
return true;
}
-
+ const ObjCObjectPointerType *T1ObjCPtrType =
+ T1->getAs<ObjCObjectPointerType>(),
+ *T2ObjCPtrType =
+ T2->getAs<ObjCObjectPointerType>();
+ if (T1ObjCPtrType) {
+ if (T2ObjCPtrType) {
+ T1 = T1ObjCPtrType->getPointeeType();
+ T2 = T2ObjCPtrType->getPointeeType();
+ return true;
+ }
+ else if (T2PtrType) {
+ T1 = T1ObjCPtrType->getPointeeType();
+ T2 = T2PtrType->getPointeeType();
+ return true;
+ }
+ }
+ else if (T2ObjCPtrType) {
+ if (T1PtrType) {
+ T2 = T2ObjCPtrType->getPointeeType();
+ T1 = T1PtrType->getPointeeType();
+ return true;
+ }
+ }
+
const MemberPointerType *T1MPType = T1->getAs<MemberPointerType>(),
*T2MPType = T2->getAs<MemberPointerType>();
if (T1MPType && T2MPType) {
@@ -225,9 +248,9 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
// C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since
// the rules are non-trivial. So first we construct Tcv *...cv* as described
// in C++ 5.2.11p8.
- assert((SrcType->isPointerType() || SrcType->isMemberPointerType()) &&
+ assert((SrcType->isAnyPointerType() || SrcType->isMemberPointerType()) &&
"Source type is not pointer or pointer to member.");
- assert((DestType->isPointerType() || DestType->isMemberPointerType()) &&
+ assert((DestType->isAnyPointerType() || DestType->isMemberPointerType()) &&
"Destination type is not pointer or pointer to member.");
QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType),
@@ -368,7 +391,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
}
// C++ 5.2.7p6: Otherwise, v shall be [polymorphic].
- const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition(Self.Context);
+ const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition();
assert(SrcDecl && "Definition missing");
if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic)
@@ -388,7 +411,7 @@ void
CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const SourceRange &OpRange, const SourceRange &DestRange) {
if (!DestType->isLValueReferenceType())
- Self.DefaultFunctionArrayConversion(SrcExpr);
+ Self.DefaultFunctionArrayLvalueConversion(SrcExpr);
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryConstCast(Self, SrcExpr, DestType, /*CStyle*/false, msg) != TC_Success
@@ -407,7 +430,7 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const SourceRange &OpRange, const SourceRange &DestRange,
CastExpr::CastKind &Kind) {
if (!DestType->isLValueReferenceType())
- Self.DefaultFunctionArrayConversion(SrcExpr);
+ Self.DefaultFunctionArrayLvalueConversion(SrcExpr);
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange,
@@ -434,7 +457,7 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
}
if (!DestType->isLValueReferenceType() && !DestType->isRecordType())
- Self.DefaultFunctionArrayConversion(SrcExpr);
+ Self.DefaultFunctionArrayLvalueConversion(SrcExpr);
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
@@ -755,9 +778,10 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
return TC_Failed;
}
- if (!CStyle && Self.CheckBaseClassAccess(DestType, SrcType,
- diag::err_downcast_from_inaccessible_base, Paths,
- OpRange.getBegin(), DeclarationName())) {
+ if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(),
+ /*IsBaseToDerived*/ true,
+ SrcType, DestType,
+ Paths.front())) {
msg = 0;
return TC_Failed;
}
@@ -821,9 +845,10 @@ TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType,
return TC_Failed;
}
- if (!CStyle && Self.CheckBaseClassAccess(DestType, SrcType,
- diag::err_downcast_from_inaccessible_base, Paths,
- OpRange.getBegin(), DeclarationName())) {
+ if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(),
+ /*IsBaseToDerived*/ false,
+ DestType, SrcType,
+ Paths.front())) {
msg = 0;
return TC_Failed;
}
@@ -1083,10 +1108,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
return TC_Failed;
}
- bool destIsPtr =
- CStyle? DestType->isAnyPointerType() : DestType->isPointerType();
- bool srcIsPtr =
- CStyle ? SrcType->isAnyPointerType() : SrcType->isPointerType();
+ bool destIsPtr = DestType->isAnyPointerType();
+ bool srcIsPtr = SrcType->isAnyPointerType();
if (!destIsPtr && !srcIsPtr) {
// Except for std::nullptr_t->integer and lvalue->reference, which are
// handled above, at least one of the two arguments must be a pointer.
@@ -1197,7 +1220,7 @@ bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
return false;
if (!CastTy->isLValueReferenceType() && !CastTy->isRecordType())
- DefaultFunctionArrayConversion(CastExpr);
+ DefaultFunctionArrayLvalueConversion(CastExpr);
// C++ [expr.cast]p5: The conversions performed by
// - a const_cast,
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 7a0b6252064d..52e9e9bc87ef 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -241,6 +241,10 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
DeclContext *DC = computeDeclContext(SS, true);
if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
+ // If this is a dependent type, then we consider it complete.
+ if (Tag->isDependentContext())
+ return false;
+
// If we're currently defining this type, then lookup into the
// type is okay: don't complain that it isn't complete yet.
const TagType *TagT = Context.getTypeDeclType(Tag)->getAs<TagType>();
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 6ff8b1d75371..b62cd19a0b25 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -14,7 +14,8 @@
#include "Sema.h"
#include "clang/Analysis/CFG.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/Analyses/PrintfFormatString.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
@@ -140,12 +141,16 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (SemaBuiltinUnorderedCompare(TheCall))
return ExprError();
break;
+ case Builtin::BI__builtin_fpclassify:
+ if (SemaBuiltinFPClassification(TheCall, 6))
+ return ExprError();
+ break;
case Builtin::BI__builtin_isfinite:
case Builtin::BI__builtin_isinf:
case Builtin::BI__builtin_isinf_sign:
case Builtin::BI__builtin_isnan:
case Builtin::BI__builtin_isnormal:
- if (SemaBuiltinUnaryFP(TheCall))
+ if (SemaBuiltinFPClassification(TheCall))
return ExprError();
break;
case Builtin::BI__builtin_return_address:
@@ -583,20 +588,21 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
return false;
}
-/// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isnan and
-/// friends. This is declared to take (...), so we have to check everything.
-bool Sema::SemaBuiltinUnaryFP(CallExpr *TheCall) {
- if (TheCall->getNumArgs() < 1)
+/// SemaBuiltinSemaBuiltinFPClassification - Handle functions like
+/// __builtin_isnan and friends. This is declared to take (...), so we have
+/// to check everything.
+bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned LastArg) {
+ if (TheCall->getNumArgs() < LastArg)
return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
<< 0 /*function call*/;
- if (TheCall->getNumArgs() > 1)
- return Diag(TheCall->getArg(1)->getLocStart(),
+ if (TheCall->getNumArgs() > LastArg)
+ return Diag(TheCall->getArg(LastArg)->getLocStart(),
diag::err_typecheck_call_too_many_args)
<< 0 /*function call*/
- << SourceRange(TheCall->getArg(1)->getLocStart(),
+ << SourceRange(TheCall->getArg(LastArg)->getLocStart(),
(*(TheCall->arg_end()-1))->getLocEnd());
- Expr *OrigArg = TheCall->getArg(0);
+ Expr *OrigArg = TheCall->getArg(LastArg-1);
if (OrigArg->isTypeDependent())
return false;
@@ -748,7 +754,7 @@ bool Sema::SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall) {
if (!TheCall->getArg(0)->isIntegerConstantExpr(Result, Context))
return Diag(TheCall->getLocStart(), diag::err_expr_not_ice)
<< TheCall->getArg(0)->getSourceRange();
-
+
return false;
}
@@ -845,8 +851,7 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
}
if (isConstant) {
- const VarDecl *Def = 0;
- if (const Expr *Init = VD->getDefinition(Def))
+ if (const Expr *Init = VD->getAnyInitializer())
return SemaCheckStringLiteral(Init, TheCall,
HasVAListArg, format_idx, firstDataArg);
}
@@ -925,7 +930,7 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull,
for (NonNullAttr::iterator i = NonNull->begin(), e = NonNull->end();
i != e; ++i) {
const Expr *ArgExpr = TheCall->getArg(*i);
- if (ArgExpr->isNullPointerConstant(Context,
+ if (ArgExpr->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNotNull))
Diag(TheCall->getCallee()->getLocStart(), diag::warn_null_arg)
<< ArgExpr->getSourceRange();
@@ -1032,248 +1037,309 @@ Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg,
<< OrigFormatExpr->getSourceRange();
}
-void Sema::CheckPrintfString(const StringLiteral *FExpr,
- const Expr *OrigFormatExpr,
- const CallExpr *TheCall, bool HasVAListArg,
- unsigned format_idx, unsigned firstDataArg) {
-
- const ObjCStringLiteral *ObjCFExpr =
- dyn_cast<ObjCStringLiteral>(OrigFormatExpr);
-
- // CHECK: is the format string a wide literal?
- if (FExpr->isWide()) {
- Diag(FExpr->getLocStart(),
- diag::warn_printf_format_string_is_wide_literal)
- << OrigFormatExpr->getSourceRange();
- return;
- }
+namespace {
+class CheckPrintfHandler : public analyze_printf::FormatStringHandler {
+ Sema &S;
+ const StringLiteral *FExpr;
+ const Expr *OrigFormatExpr;
+ unsigned NumConversions;
+ const unsigned NumDataArgs;
+ const bool IsObjCLiteral;
+ const char *Beg; // Start of format string.
+ const bool HasVAListArg;
+ const CallExpr *TheCall;
+ unsigned FormatIdx;
+public:
+ CheckPrintfHandler(Sema &s, const StringLiteral *fexpr,
+ const Expr *origFormatExpr,
+ unsigned numDataArgs, bool isObjCLiteral,
+ const char *beg, bool hasVAListArg,
+ const CallExpr *theCall, unsigned formatIdx)
+ : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
+ NumConversions(0), NumDataArgs(numDataArgs),
+ IsObjCLiteral(isObjCLiteral), Beg(beg),
+ HasVAListArg(hasVAListArg),
+ TheCall(theCall), FormatIdx(formatIdx) {}
+
+ void DoneProcessing();
+
+ void HandleIncompleteFormatSpecifier(const char *startSpecifier,
+ unsigned specifierLen);
+
+ void
+ HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS,
+ const char *startSpecifier,
+ unsigned specifierLen);
+
+ void HandleNullChar(const char *nullCharacter);
+
+ bool HandleFormatSpecifier(const analyze_printf::FormatSpecifier &FS,
+ const char *startSpecifier,
+ unsigned specifierLen);
+private:
+ SourceRange getFormatStringRange();
+ SourceRange getFormatSpecifierRange(const char *startSpecifier,
+ unsigned specifierLen);
+ SourceLocation getLocationOfByte(const char *x);
+
+ bool HandleAmount(const analyze_printf::OptionalAmount &Amt,
+ unsigned MissingArgDiag, unsigned BadTypeDiag,
+ const char *startSpecifier, unsigned specifierLen);
+ void HandleFlags(const analyze_printf::FormatSpecifier &FS,
+ llvm::StringRef flag, llvm::StringRef cspec,
+ const char *startSpecifier, unsigned specifierLen);
+
+ const Expr *getDataArg(unsigned i) const;
+};
+}
- // Str - The format string. NOTE: this is NOT null-terminated!
- const char *Str = FExpr->getStrData();
+SourceRange CheckPrintfHandler::getFormatStringRange() {
+ return OrigFormatExpr->getSourceRange();
+}
- // CHECK: empty format string?
- unsigned StrLen = FExpr->getByteLength();
+SourceRange CheckPrintfHandler::
+getFormatSpecifierRange(const char *startSpecifier, unsigned specifierLen) {
+ return SourceRange(getLocationOfByte(startSpecifier),
+ getLocationOfByte(startSpecifier+specifierLen-1));
+}
- if (StrLen == 0) {
- Diag(FExpr->getLocStart(), diag::warn_printf_empty_format_string)
- << OrigFormatExpr->getSourceRange();
- return;
- }
+SourceLocation CheckPrintfHandler::getLocationOfByte(const char *x) {
+ return S.getLocationOfStringLiteralByte(FExpr, x - Beg);
+}
- // We process the format string using a binary state machine. The
- // current state is stored in CurrentState.
- enum {
- state_OrdChr,
- state_Conversion
- } CurrentState = state_OrdChr;
+void CheckPrintfHandler::
+HandleIncompleteFormatSpecifier(const char *startSpecifier,
+ unsigned specifierLen) {
+ SourceLocation Loc = getLocationOfByte(startSpecifier);
+ S.Diag(Loc, diag::warn_printf_incomplete_specifier)
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
+}
- // numConversions - The number of conversions seen so far. This is
- // incremented as we traverse the format string.
- unsigned numConversions = 0;
+void CheckPrintfHandler::
+HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS,
+ const char *startSpecifier,
+ unsigned specifierLen) {
+
+ ++NumConversions;
+ const analyze_printf::ConversionSpecifier &CS =
+ FS.getConversionSpecifier();
+ SourceLocation Loc = getLocationOfByte(CS.getStart());
+ S.Diag(Loc, diag::warn_printf_invalid_conversion)
+ << llvm::StringRef(CS.getStart(), CS.getLength())
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
+}
- // numDataArgs - The number of data arguments after the format
- // string. This can only be determined for non vprintf-like
- // functions. For those functions, this value is 1 (the sole
- // va_arg argument).
- unsigned numDataArgs = TheCall->getNumArgs()-firstDataArg;
+void CheckPrintfHandler::HandleNullChar(const char *nullCharacter) {
+ // The presence of a null character is likely an error.
+ S.Diag(getLocationOfByte(nullCharacter),
+ diag::warn_printf_format_string_contains_null_char)
+ << getFormatStringRange();
+}
- // Inspect the format string.
- unsigned StrIdx = 0;
+const Expr *CheckPrintfHandler::getDataArg(unsigned i) const {
+ return TheCall->getArg(FormatIdx + i);
+}
- // LastConversionIdx - Index within the format string where we last saw
- // a '%' character that starts a new format conversion.
- unsigned LastConversionIdx = 0;
- for (; StrIdx < StrLen; ++StrIdx) {
- // Is the number of detected conversion conversions greater than
- // the number of matching data arguments? If so, stop.
- if (!HasVAListArg && numConversions > numDataArgs) break;
+void CheckPrintfHandler::HandleFlags(const analyze_printf::FormatSpecifier &FS,
+ llvm::StringRef flag,
+ llvm::StringRef cspec,
+ const char *startSpecifier,
+ unsigned specifierLen) {
+ const analyze_printf::ConversionSpecifier &CS = FS.getConversionSpecifier();
+ S.Diag(getLocationOfByte(CS.getStart()), diag::warn_printf_nonsensical_flag)
+ << flag << cspec << getFormatSpecifierRange(startSpecifier, specifierLen);
+}
- // Handle "\0"
- if (Str[StrIdx] == '\0') {
- // The string returned by getStrData() is not null-terminated,
- // so the presence of a null character is likely an error.
- Diag(getLocationOfStringLiteralByte(FExpr, StrIdx),
- diag::warn_printf_format_string_contains_null_char)
- << OrigFormatExpr->getSourceRange();
- return;
- }
+bool
+CheckPrintfHandler::HandleAmount(const analyze_printf::OptionalAmount &Amt,
+ unsigned MissingArgDiag,
+ unsigned BadTypeDiag,
+ const char *startSpecifier,
+ unsigned specifierLen) {
+
+ if (Amt.hasDataArgument()) {
+ ++NumConversions;
+ if (!HasVAListArg) {
+ if (NumConversions > NumDataArgs) {
+ S.Diag(getLocationOfByte(Amt.getStart()), MissingArgDiag)
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
+ // Don't do any more checking. We will just emit
+ // spurious errors.
+ return false;
+ }
- // Ordinary characters (not processing a format conversion).
- if (CurrentState == state_OrdChr) {
- if (Str[StrIdx] == '%') {
- CurrentState = state_Conversion;
- LastConversionIdx = StrIdx;
+ // Type check the data argument. It should be an 'int'.
+ // Although not in conformance with C99, we also allow the argument to be
+ // an 'unsigned int' as that is a reasonably safe case. GCC also
+ // doesn't emit a warning for that case.
+ const Expr *Arg = getDataArg(NumConversions);
+ QualType T = Arg->getType();
+
+ const analyze_printf::ArgTypeResult &ATR = Amt.getArgType(S.Context);
+ assert(ATR.isValid());
+
+ if (!ATR.matchesType(S.Context, T)) {
+ S.Diag(getLocationOfByte(Amt.getStart()), BadTypeDiag)
+ << ATR.getRepresentativeType(S.Context) << T
+ << getFormatSpecifierRange(startSpecifier, specifierLen)
+ << Arg->getSourceRange();
+ // Don't do any more checking. We will just emit
+ // spurious errors.
+ return false;
}
- continue;
}
+ }
+ return true;
+}
- // Seen '%'. Now processing a format conversion.
- switch (Str[StrIdx]) {
- // Handle dynamic precision or width specifier.
- case '*': {
- ++numConversions;
-
- if (!HasVAListArg) {
- if (numConversions > numDataArgs) {
- SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, StrIdx);
-
- if (Str[StrIdx-1] == '.')
- Diag(Loc, diag::warn_printf_asterisk_precision_missing_arg)
- << OrigFormatExpr->getSourceRange();
- else
- Diag(Loc, diag::warn_printf_asterisk_width_missing_arg)
- << OrigFormatExpr->getSourceRange();
-
- // Don't do any more checking. We'll just emit spurious errors.
- return;
- }
+bool
+CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier
+ &FS,
+ const char *startSpecifier,
+ unsigned specifierLen) {
+
+ using namespace analyze_printf;
+ const ConversionSpecifier &CS = FS.getConversionSpecifier();
+
+ // First check if the field width, precision, and conversion specifier
+ // have matching data arguments.
+ if (!HandleAmount(FS.getFieldWidth(),
+ diag::warn_printf_asterisk_width_missing_arg,
+ diag::warn_printf_asterisk_width_wrong_type,
+ startSpecifier, specifierLen)) {
+ return false;
+ }
- // Perform type checking on width/precision specifier.
- const Expr *E = TheCall->getArg(format_idx+numConversions);
- if (const BuiltinType *BT = E->getType()->getAs<BuiltinType>())
- if (BT->getKind() == BuiltinType::Int)
- break;
+ if (!HandleAmount(FS.getPrecision(),
+ diag::warn_printf_asterisk_precision_missing_arg,
+ diag::warn_printf_asterisk_precision_wrong_type,
+ startSpecifier, specifierLen)) {
+ return false;
+ }
- SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, StrIdx);
+ // Check for using an Objective-C specific conversion specifier
+ // in a non-ObjC literal.
+ if (!IsObjCLiteral && CS.isObjCArg()) {
+ HandleInvalidConversionSpecifier(FS, startSpecifier, specifierLen);
- if (Str[StrIdx-1] == '.')
- Diag(Loc, diag::warn_printf_asterisk_precision_wrong_type)
- << E->getType() << E->getSourceRange();
- else
- Diag(Loc, diag::warn_printf_asterisk_width_wrong_type)
- << E->getType() << E->getSourceRange();
+ // Continue checking the other format specifiers.
+ return true;
+ }
- break;
- }
- }
+ if (!CS.consumesDataArgument()) {
+ // FIXME: Technically specifying a precision or field width here
+ // makes no sense. Worth issuing a warning at some point.
+ return true;
+ }
- // Characters which can terminate a format conversion
- // (e.g. "%d"). Characters that specify length modifiers or
- // other flags are handled by the default case below.
- //
- // FIXME: additional checks will go into the following cases.
- case 'i':
- case 'd':
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- case 'D':
- case 'O':
- case 'U':
- case 'e':
- case 'E':
- case 'f':
- case 'F':
- case 'g':
- case 'G':
- case 'a':
- case 'A':
- case 'c':
- case 'C':
- case 'S':
- case 's':
- case 'p':
- ++numConversions;
- CurrentState = state_OrdChr;
- break;
+ ++NumConversions;
- case 'm':
- // FIXME: Warn in situations where this isn't supported!
- CurrentState = state_OrdChr;
- break;
+ // Are we using '%n'? Issue a warning about this being
+ // a possible security issue.
+ if (CS.getKind() == ConversionSpecifier::OutIntPtrArg) {
+ S.Diag(getLocationOfByte(CS.getStart()), diag::warn_printf_write_back)
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
+ // Continue checking the other format specifiers.
+ return true;
+ }
- // CHECK: Are we using "%n"? Issue a warning.
- case 'n': {
- ++numConversions;
- CurrentState = state_OrdChr;
- SourceLocation Loc = getLocationOfStringLiteralByte(FExpr,
- LastConversionIdx);
+ if (CS.getKind() == ConversionSpecifier::VoidPtrArg) {
+ if (FS.getPrecision().getHowSpecified() != OptionalAmount::NotSpecified)
+ S.Diag(getLocationOfByte(CS.getStart()),
+ diag::warn_printf_nonsensical_precision)
+ << CS.getCharacters()
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
+ }
+ if (CS.getKind() == ConversionSpecifier::VoidPtrArg ||
+ CS.getKind() == ConversionSpecifier::CStrArg) {
+ // FIXME: Instead of using "0", "+", etc., eventually get them from
+ // the FormatSpecifier.
+ if (FS.hasLeadingZeros())
+ HandleFlags(FS, "0", CS.getCharacters(), startSpecifier, specifierLen);
+ if (FS.hasPlusPrefix())
+ HandleFlags(FS, "+", CS.getCharacters(), startSpecifier, specifierLen);
+ if (FS.hasSpacePrefix())
+ HandleFlags(FS, " ", CS.getCharacters(), startSpecifier, specifierLen);
+ }
- Diag(Loc, diag::warn_printf_write_back)<<OrigFormatExpr->getSourceRange();
- break;
- }
+ // The remaining checks depend on the data arguments.
+ if (HasVAListArg)
+ return true;
- // Handle "%@"
- case '@':
- // %@ is allowed in ObjC format strings only.
- if (ObjCFExpr != NULL)
- CurrentState = state_OrdChr;
- else {
- // Issue a warning: invalid format conversion.
- SourceLocation Loc =
- getLocationOfStringLiteralByte(FExpr, LastConversionIdx);
-
- Diag(Loc, diag::warn_printf_invalid_conversion)
- << std::string(Str+LastConversionIdx,
- Str+std::min(LastConversionIdx+2, StrLen))
- << OrigFormatExpr->getSourceRange();
- }
- ++numConversions;
- break;
+ if (NumConversions > NumDataArgs) {
+ S.Diag(getLocationOfByte(CS.getStart()),
+ diag::warn_printf_insufficient_data_args)
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
+ // Don't do any more checking.
+ return false;
+ }
- // Handle "%%"
- case '%':
- // Sanity check: Was the first "%" character the previous one?
- // If not, we will assume that we have a malformed format
- // conversion, and that the current "%" character is the start
- // of a new conversion.
- if (StrIdx - LastConversionIdx == 1)
- CurrentState = state_OrdChr;
- else {
- // Issue a warning: invalid format conversion.
- SourceLocation Loc =
- getLocationOfStringLiteralByte(FExpr, LastConversionIdx);
-
- Diag(Loc, diag::warn_printf_invalid_conversion)
- << std::string(Str+LastConversionIdx, Str+StrIdx)
- << OrigFormatExpr->getSourceRange();
-
- // This conversion is broken. Advance to the next format
- // conversion.
- LastConversionIdx = StrIdx;
- ++numConversions;
- }
- break;
+ // Now type check the data expression that matches the
+ // format specifier.
+ const Expr *Ex = getDataArg(NumConversions);
+ const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context);
+ if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) {
+ // Check if we didn't match because of an implicit cast from a 'char'
+ // or 'short' to an 'int'. This is done because printf is a varargs
+ // function.
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Ex))
+ if (ICE->getType() == S.Context.IntTy)
+ if (ATR.matchesType(S.Context, ICE->getSubExpr()->getType()))
+ return true;
- default:
- // This case catches all other characters: flags, widths, etc.
- // We should eventually process those as well.
- break;
- }
+ S.Diag(getLocationOfByte(CS.getStart()),
+ diag::warn_printf_conversion_argument_type_mismatch)
+ << ATR.getRepresentativeType(S.Context) << Ex->getType()
+ << getFormatSpecifierRange(startSpecifier, specifierLen)
+ << Ex->getSourceRange();
}
- if (CurrentState == state_Conversion) {
- // Issue a warning: invalid format conversion.
- SourceLocation Loc =
- getLocationOfStringLiteralByte(FExpr, LastConversionIdx);
+ return true;
+}
- Diag(Loc, diag::warn_printf_invalid_conversion)
- << std::string(Str+LastConversionIdx,
- Str+std::min(LastConversionIdx+2, StrLen))
- << OrigFormatExpr->getSourceRange();
+void CheckPrintfHandler::DoneProcessing() {
+ // Does the number of data arguments exceed the number of
+ // format conversions in the format string?
+ if (!HasVAListArg && NumConversions < NumDataArgs)
+ S.Diag(getDataArg(NumConversions+1)->getLocStart(),
+ diag::warn_printf_too_many_data_args)
+ << getFormatStringRange();
+}
+
+void Sema::CheckPrintfString(const StringLiteral *FExpr,
+ const Expr *OrigFormatExpr,
+ const CallExpr *TheCall, bool HasVAListArg,
+ unsigned format_idx, unsigned firstDataArg) {
+
+ // CHECK: is the format string a wide literal?
+ if (FExpr->isWide()) {
+ Diag(FExpr->getLocStart(),
+ diag::warn_printf_format_string_is_wide_literal)
+ << OrigFormatExpr->getSourceRange();
return;
}
- if (!HasVAListArg) {
- // CHECK: Does the number of format conversions exceed the number
- // of data arguments?
- if (numConversions > numDataArgs) {
- SourceLocation Loc =
- getLocationOfStringLiteralByte(FExpr, LastConversionIdx);
-
- Diag(Loc, diag::warn_printf_insufficient_data_args)
- << OrigFormatExpr->getSourceRange();
- }
- // CHECK: Does the number of data arguments exceed the number of
- // format conversions in the format string?
- else if (numConversions < numDataArgs)
- Diag(TheCall->getArg(format_idx+numConversions+1)->getLocStart(),
- diag::warn_printf_too_many_data_args)
- << OrigFormatExpr->getSourceRange();
+ // Str - The format string. NOTE: this is NOT null-terminated!
+ const char *Str = FExpr->getStrData();
+
+ // CHECK: empty format string?
+ unsigned StrLen = FExpr->getByteLength();
+
+ if (StrLen == 0) {
+ Diag(FExpr->getLocStart(), diag::warn_printf_empty_format_string)
+ << OrigFormatExpr->getSourceRange();
+ return;
}
+
+ CheckPrintfHandler H(*this, FExpr, OrigFormatExpr,
+ TheCall->getNumArgs() - firstDataArg,
+ isa<ObjCStringLiteral>(OrigFormatExpr), Str,
+ HasVAListArg, TheCall, format_idx);
+
+ if (!analyze_printf::ParseFormatString(H, Str, Str + StrLen))
+ H.DoneProcessing();
}
//===--- CHECK: Return Address of Stack Variable --------------------------===//
@@ -1300,11 +1366,11 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
if (C->hasBlockDeclRefExprs())
Diag(C->getLocStart(), diag::err_ret_local_block)
<< C->getSourceRange();
-
+
if (AddrLabelExpr *ALE = dyn_cast<AddrLabelExpr>(RetValExp))
Diag(ALE->getLocStart(), diag::warn_ret_addr_label)
<< ALE->getSourceRange();
-
+
} else if (lhsType->isReferenceType()) {
// Perform checking for stack values returned by reference.
// Check for a reference to the stack
@@ -1780,7 +1846,7 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
if (BO->getLHS()->getType()->isPointerType())
return IntRange::forType(C, E->getType());
// fallthrough
-
+
default:
break;
}
@@ -2221,7 +2287,7 @@ void Sema::CheckUnreachable(AnalysisContext &AC) {
CFG *cfg = AC.getCFG();
if (cfg == 0)
return;
-
+
llvm::BitVector live(cfg->getNumBlockIDs());
// Mark all live things first.
count = MarkLive(&cfg->getEntry(), live);
@@ -2268,7 +2334,9 @@ void Sema::CheckUnreachable(AnalysisContext &AC) {
CFGBlock &b = **I;
if (!live[b.getBlockID()])
// Avoid excessive errors by marking everything reachable from here
- lines.push_back(ErrLoc(MarkLiveTop(&b, live, Context.getSourceManager()), SourceRange(), SourceRange()));
+ lines.push_back(ErrLoc(MarkLiveTop(&b, live,
+ Context.getSourceManager()),
+ SourceRange(), SourceRange()));
}
}
@@ -2418,17 +2486,19 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body,
// which this code would then warn about.
if (getDiagnostics().hasErrorOccurred())
return;
-
+
bool ReturnsVoid = false;
bool HasNoReturn = false;
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- // If the result type of the function is a dependent type, we don't know
- // whether it will be void or not, so don't
- if (FD->getResultType()->isDependentType())
+ // For function templates, class templates and member function templates
+ // we'll do the analysis at instantiation time.
+ if (FD->isDependentContext())
return;
+
if (FD->getResultType()->isVoidType())
ReturnsVoid = true;
- if (FD->hasAttr<NoReturnAttr>())
+ if (FD->hasAttr<NoReturnAttr>() ||
+ FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
HasNoReturn = true;
} else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (MD->getResultType()->isVoidType())
@@ -2552,6 +2622,24 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) {
!Param->isImplicit() &&
!getLangOptions().CPlusPlus)
Diag(Param->getLocation(), diag::err_parameter_name_omitted);
+
+ // C99 6.7.5.3p12:
+ // If the function declarator is not part of a definition of that
+ // function, parameters may have incomplete type and may use the [*]
+ // notation in their sequences of declarator specifiers to specify
+ // variable length array types.
+ QualType PType = Param->getOriginalType();
+ if (const ArrayType *AT = Context.getAsArrayType(PType)) {
+ if (AT->getSizeModifier() == ArrayType::Star) {
+ // FIXME: This diagnosic should point the the '[*]' if source-location
+ // information is added for it.
+ Diag(Param->getLocation(), diag::err_array_star_in_function_definition);
+ }
+ }
+
+ if (getLangOptions().CPlusPlus)
+ if (const RecordType *RT = Param->getType()->getAs<RecordType>())
+ FinalizeVarWithDestructor(Param, RT);
}
return HasInvalidParm;
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index fcd419bb10fb..a86294971861 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -2196,13 +2196,15 @@ void Sema::CodeCompleteCase(Scope *S) {
namespace {
struct IsBetterOverloadCandidate {
Sema &S;
+ SourceLocation Loc;
public:
- explicit IsBetterOverloadCandidate(Sema &S) : S(S) { }
+ explicit IsBetterOverloadCandidate(Sema &S, SourceLocation Loc)
+ : S(S), Loc(Loc) { }
bool
operator()(const OverloadCandidate &X, const OverloadCandidate &Y) const {
- return S.isBetterOverloadCandidate(X, Y);
+ return S.isBetterOverloadCandidate(X, Y, Loc);
}
};
}
@@ -2228,7 +2230,8 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
}
// Build an overload candidate set based on the functions we find.
- OverloadCandidateSet CandidateSet;
+ SourceLocation Loc = Fn->getExprLoc();
+ OverloadCandidateSet CandidateSet(Loc);
// FIXME: What if we're calling something that isn't a function declaration?
// FIXME: What if we're calling a pseudo-destructor?
@@ -2247,7 +2250,8 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
if (!FDecl->getType()->getAs<FunctionProtoType>())
Results.push_back(ResultCandidate(FDecl));
else
- AddOverloadCandidate(FDecl, Args, NumArgs, CandidateSet,
+ // FIXME: access?
+ AddOverloadCandidate(FDecl, AS_none, Args, NumArgs, CandidateSet,
false, false, /*PartialOverloading*/ true);
}
}
@@ -2255,7 +2259,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
if (!CandidateSet.empty()) {
// Sort the overload candidate set by placing the best overloads first.
std::stable_sort(CandidateSet.begin(), CandidateSet.end(),
- IsBetterOverloadCandidate(*this));
+ IsBetterOverloadCandidate(*this, Loc));
// Add the remaining viable overload candidates as code-completion reslults.
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
@@ -2977,7 +2981,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
// If necessary, apply function/array conversion to the receiver.
// C99 6.7.5.3p[7,8].
- DefaultFunctionArrayConversion(RecExpr);
+ DefaultFunctionArrayLvalueConversion(RecExpr);
QualType ReceiverType = RecExpr->getType();
if (ReceiverType->isObjCIdType() || ReceiverType->isBlockPointerType()) {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index fbe02894ace5..1fc08ce03197 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -14,7 +14,7 @@
#include "Sema.h"
#include "SemaInit.h"
#include "Lookup.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -135,6 +135,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
case LookupResult::NotFoundInCurrentInstantiation:
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
+ Result.suppressDiagnostics();
return 0;
case LookupResult::Ambiguous:
@@ -509,9 +510,18 @@ static void RemoveUsingDecls(LookupResult &R) {
}
static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
+ if (D->isInvalidDecl())
+ return false;
+
if (D->isUsed() || D->hasAttr<UnusedAttr>())
return false;
-
+
+ // White-list anything that isn't a local variable.
+ if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) ||
+ !D->getDeclContext()->isFunctionOrMethod())
+ return false;
+
+ // Types of valid local variables should be complete, so this should succeed.
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())) {
@@ -523,9 +533,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
}
}
- return (isa<VarDecl>(D) && !isa<ParmVarDecl>(D) &&
- !isa<ImplicitParamDecl>(D) &&
- D->getDeclContext()->isFunctionOrMethod());
+ return true;
}
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
@@ -690,7 +698,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0,
FT->getArgType(i), /*TInfo=*/0,
VarDecl::None, 0));
- New->setParams(Context, Params.data(), Params.size());
+ New->setParams(Params.data(), Params.size());
}
AddKnownFunctionAttributes(New);
@@ -957,6 +965,44 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
return true;
}
+ // If a function is first declared with a calling convention, but is
+ // later declared or defined without one, the second decl assumes the
+ // calling convention of the first.
+ //
+ // For the new decl, we have to look at the NON-canonical type to tell the
+ // difference between a function that really doesn't have a calling
+ // convention and one that is declared cdecl. That's because in
+ // canonicalization (see ASTContext.cpp), cdecl is canonicalized away
+ // because it is the default calling convention.
+ //
+ // Note also that we DO NOT return at this point, because we still have
+ // other tests to run.
+ const FunctionType *OldType = OldQType->getAs<FunctionType>();
+ const FunctionType *NewType = New->getType()->getAs<FunctionType>();
+ if (OldType->getCallConv() != CC_Default &&
+ NewType->getCallConv() == CC_Default) {
+ NewQType = Context.getCallConvType(NewQType, OldType->getCallConv());
+ New->setType(NewQType);
+ NewQType = Context.getCanonicalType(NewQType);
+ } else if (!Context.isSameCallConv(OldType->getCallConv(),
+ NewType->getCallConv())) {
+ // Calling conventions really aren't compatible, so complain.
+ Diag(New->getLocation(), diag::err_cconv_change)
+ << FunctionType::getNameForCallConv(NewType->getCallConv())
+ << (OldType->getCallConv() == CC_Default)
+ << (OldType->getCallConv() == CC_Default ? "" :
+ FunctionType::getNameForCallConv(OldType->getCallConv()));
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ return true;
+ }
+
+ // FIXME: diagnose the other way around?
+ if (OldType->getNoReturnAttr() && !NewType->getNoReturnAttr()) {
+ NewQType = Context.getNoReturnType(NewQType);
+ New->setType(NewQType);
+ assert(NewQType.isCanonical());
+ }
+
if (getLangOptions().CPlusPlus) {
// (C++98 13.1p2):
// Certain function declarations cannot be overloaded:
@@ -1061,7 +1107,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
Params.push_back(Param);
}
- New->setParams(Context, Params.data(), Params.size());
+ New->setParams(Params.data(), Params.size());
}
return MergeCompatibleFunctionDecls(New, Old);
@@ -1297,6 +1343,18 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
Diag(Old->getLocation(), diag::note_previous_definition);
}
+ // C++ doesn't have tentative definitions, so go right ahead and check here.
+ const VarDecl *Def;
+ if (getLangOptions().CPlusPlus &&
+ New->isThisDeclarationADefinition() == VarDecl::Definition &&
+ (Def = Old->getDefinition())) {
+ Diag(New->getLocation(), diag::err_redefinition)
+ << New->getDeclName();
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ New->setInvalidDecl();
+ return;
+ }
+
// Keep a chain of previous declarations.
New->setPreviousDeclaration(Old);
@@ -1855,6 +1913,13 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
if (!DC->isDependentContext() &&
RequireCompleteDeclContext(D.getCXXScopeSpec()))
return DeclPtrTy();
+
+ if (isa<CXXRecordDecl>(DC) && !cast<CXXRecordDecl>(DC)->hasDefinition()) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_member_def_undefined_record)
+ << Name << DC << D.getCXXScopeSpec().getRange();
+ D.setInvalidType();
+ }
LookupQualifiedName(Previous, DC);
@@ -2322,7 +2387,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (Expr *E = (Expr*) D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
- NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getString()));
+ NewVD->addAttr(::new (Context) AsmLabelAttr(Context, SE->getString()));
}
// Don't consider existing declarations that are in a different
@@ -2359,9 +2424,9 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// attributes declared post-definition are currently ignored
if (Previous.isSingleResult()) {
- const VarDecl *Def = 0;
- VarDecl *PrevDecl = dyn_cast<VarDecl>(Previous.getFoundDecl());
- if (PrevDecl && PrevDecl->getDefinition(Def) && D.hasAttributes()) {
+ VarDecl *Def = dyn_cast<VarDecl>(Previous.getFoundDecl());
+ if (Def && (Def = Def->getDefinition()) &&
+ Def != NewVD && D.hasAttributes()) {
Diag(NewVD->getLocation(), diag::warn_attribute_precede_definition);
Diag(Def->getLocation(), diag::note_previous_definition);
}
@@ -2675,7 +2740,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// (The parser checks for a return type and makes the declarator a
// constructor if it has no return type).
// must have an invalid constructor that has a return type
- if (Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){
+ if (Name.getAsIdentifierInfo() &&
+ Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){
Diag(D.getIdentifierLoc(), diag::err_constructor_return_type)
<< SourceRange(D.getDeclSpec().getTypeSpecTypeLoc())
<< SourceRange(D.getIdentifierLoc());
@@ -2783,6 +2849,28 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
}
+ // C++ [dcl.fct.spec]p6:
+ // The explicit specifier shall be used only in the declaration of a
+ // constructor or conversion function within its class definition; see 12.3.1
+ // and 12.3.2.
+ if (isExplicit && !NewFD->isInvalidDecl()) {
+ if (!CurContext->isRecord()) {
+ // 'explicit' was specified outside of the class.
+ Diag(D.getDeclSpec().getExplicitSpecLoc(),
+ diag::err_explicit_out_of_class)
+ << CodeModificationHint::CreateRemoval(
+ D.getDeclSpec().getExplicitSpecLoc());
+ } else if (!isa<CXXConstructorDecl>(NewFD) &&
+ !isa<CXXConversionDecl>(NewFD)) {
+ // 'explicit' was specified on a function that wasn't a constructor
+ // or conversion function.
+ Diag(D.getDeclSpec().getExplicitSpecLoc(),
+ diag::err_explicit_non_ctor_or_conv_function)
+ << CodeModificationHint::CreateRemoval(
+ D.getDeclSpec().getExplicitSpecLoc());
+ }
+ }
+
// Filter out previous declarations that don't match the scope.
FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage());
@@ -2822,7 +2910,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (Expr *E = (Expr*) D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
- NewFD->addAttr(::new (Context) AsmLabelAttr(SE->getString()));
+ NewFD->addAttr(::new (Context) AsmLabelAttr(Context, SE->getString()));
}
// Copy the parameter declarations from the declarator D to the function
@@ -2882,7 +2970,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
"Should not need args for typedef of non-prototype fn");
}
// Finally, we know we have the right number of parameters, install them.
- NewFD->setParams(Context, Params.data(), Params.size());
+ NewFD->setParams(Params.data(), Params.size());
// If the declarator is a template-id, translate the parser's template
// argument list into our AST format.
@@ -2950,7 +3038,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) {
// Fake up an access specifier if it's supposed to be a class member.
- if (isa<CXXRecordDecl>(NewFD->getDeclContext()))
+ if (!Redeclaration && isa<CXXRecordDecl>(NewFD->getDeclContext()))
NewFD->setAccess(AS_public);
// An out-of-line member function declaration must also be a
@@ -3041,6 +3129,15 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (FunctionTemplate)
return FunctionTemplate;
+
+ // Keep track of static, non-inlined function definitions that
+ // have not been used. We will warn later.
+ // FIXME: Also include static functions declared but not defined.
+ if (!NewFD->isInvalidDecl() && IsFunctionDefinition
+ && !NewFD->isInlined() && NewFD->getLinkage() == InternalLinkage
+ && !NewFD->isUsed())
+ UnusedStaticFuncs.push_back(NewFD);
+
return NewFD;
}
@@ -3412,8 +3509,8 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
AbstractVariableType))
VDecl->setInvalidDecl();
- const VarDecl *Def = 0;
- if (VDecl->getDefinition(Def)) {
+ const VarDecl *Def;
+ if ((Def = VDecl->getDefinition()) && Def != VDecl) {
Diag(VDecl->getLocation(), diag::err_redefinition)
<< VDecl->getDeclName();
Diag(Def->getLocation(), diag::note_previous_definition);
@@ -3473,7 +3570,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
// };
// Attach the initializer
- VDecl->setInit(Context, Init);
+ VDecl->setInit(Init);
// C++ [class.mem]p4:
// A member-declarator can contain a constant-initializer only
@@ -3545,23 +3642,15 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
Init = MaybeCreateCXXExprWithTemporaries(Init);
// Attach the initializer to the decl.
- VDecl->setInit(Context, Init);
-
- // If the previous declaration of VDecl was a tentative definition,
- // remove it from the set of tentative definitions.
- if (VDecl->getPreviousDeclaration() &&
- VDecl->getPreviousDeclaration()->isTentativeDefinition(Context)) {
- bool Deleted = TentativeDefinitions.erase(VDecl->getDeclName());
- assert(Deleted && "Unrecorded tentative definition?"); Deleted=Deleted;
- }
+ VDecl->setInit(Init);
if (getLangOptions().CPlusPlus) {
// Make sure we mark the destructor as used if necessary.
QualType InitType = VDecl->getType();
while (const ArrayType *Array = Context.getAsArrayType(InitType))
InitType = Context.getBaseElementType(Array);
- if (InitType->isRecordType())
- FinalizeVarWithDestructor(VDecl, InitType);
+ if (const RecordType *Record = InitType->getAs<RecordType>())
+ FinalizeVarWithDestructor(VDecl, Record);
}
return;
@@ -3578,136 +3667,140 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl,
if (VarDecl *Var = dyn_cast<VarDecl>(RealDecl)) {
QualType Type = Var->getType();
- // Record tentative definitions.
- if (Var->isTentativeDefinition(Context)) {
- std::pair<llvm::DenseMap<DeclarationName, VarDecl *>::iterator, bool>
- InsertPair =
- TentativeDefinitions.insert(std::make_pair(Var->getDeclName(), Var));
+ // C++0x [dcl.spec.auto]p3
+ if (TypeContainsUndeducedAuto) {
+ Diag(Var->getLocation(), diag::err_auto_var_requires_init)
+ << Var->getDeclName() << Type;
+ Var->setInvalidDecl();
+ return;
+ }
+
+ switch (Var->isThisDeclarationADefinition()) {
+ case VarDecl::Definition:
+ if (!Var->isStaticDataMember() || !Var->getAnyInitializer())
+ break;
- // Keep the latest definition in the map. If we see 'int i; int i;' we
- // want the second one in the map.
- InsertPair.first->second = Var;
+ // We have an out-of-line definition of a static data member
+ // that has an in-class initializer, so we type-check this like
+ // a declaration.
+ //
+ // Fall through
+
+ case VarDecl::DeclarationOnly:
+ // It's only a declaration.
+
+ // Block scope. C99 6.7p7: If an identifier for an object is
+ // declared with no linkage (C99 6.2.2p6), the type for the
+ // object shall be complete.
+ if (!Type->isDependentType() && Var->isBlockVarDecl() &&
+ !Var->getLinkage() && !Var->isInvalidDecl() &&
+ RequireCompleteType(Var->getLocation(), Type,
+ diag::err_typecheck_decl_incomplete_type))
+ Var->setInvalidDecl();
- // However, for the list, we don't care about the order, just make sure
- // that there are no dupes for a given declaration name.
- if (InsertPair.second)
- TentativeDefinitionList.push_back(Var->getDeclName());
+ // Make sure that the type is not abstract.
+ if (!Type->isDependentType() && !Var->isInvalidDecl() &&
+ RequireNonAbstractType(Var->getLocation(), Type,
+ diag::err_abstract_type_in_decl,
+ AbstractVariableType))
+ Var->setInvalidDecl();
+ return;
+
+ case VarDecl::TentativeDefinition:
+ // File scope. C99 6.9.2p2: A declaration of an identifier for an
+ // object that has file scope without an initializer, and without a
+ // storage-class specifier or with the storage-class specifier "static",
+ // constitutes a tentative definition. Note: A tentative definition with
+ // external linkage is valid (C99 6.2.2p5).
+ if (!Var->isInvalidDecl()) {
+ if (const IncompleteArrayType *ArrayT
+ = Context.getAsIncompleteArrayType(Type)) {
+ if (RequireCompleteType(Var->getLocation(),
+ ArrayT->getElementType(),
+ diag::err_illegal_decl_array_incomplete_type))
+ Var->setInvalidDecl();
+ } else if (Var->getStorageClass() == VarDecl::Static) {
+ // C99 6.9.2p3: If the declaration of an identifier for an object is
+ // a tentative definition and has internal linkage (C99 6.2.2p3), the
+ // declared type shall not be an incomplete type.
+ // NOTE: code such as the following
+ // static struct s;
+ // struct s { int a; };
+ // is accepted by gcc. Hence here we issue a warning instead of
+ // an error and we do not invalidate the static declaration.
+ // NOTE: to avoid multiple warnings, only check the first declaration.
+ if (Var->getPreviousDeclaration() == 0)
+ RequireCompleteType(Var->getLocation(), Type,
+ diag::ext_typecheck_decl_incomplete_type);
+ }
+ }
+
+ // Record the tentative definition; we're done.
+ if (!Var->isInvalidDecl())
+ TentativeDefinitions.push_back(Var);
+ return;
}
- // C++ [dcl.init.ref]p3:
- // The initializer can be omitted for a reference only in a
- // parameter declaration (8.3.5), in the declaration of a
- // function return type, in the declaration of a class member
- // within its class declaration (9.2), and where the extern
- // specifier is explicitly used.
- if (Type->isReferenceType() && !Var->hasExternalStorage()) {
- Diag(Var->getLocation(), diag::err_reference_var_requires_init)
- << Var->getDeclName()
- << SourceRange(Var->getLocation(), Var->getLocation());
+ // Provide a specific diagnostic for uninitialized variable
+ // definitions with incomplete array type.
+ if (Type->isIncompleteArrayType()) {
+ Diag(Var->getLocation(),
+ diag::err_typecheck_incomplete_array_needs_initializer);
Var->setInvalidDecl();
return;
}
- // C++0x [dcl.spec.auto]p3
- if (TypeContainsUndeducedAuto) {
- Diag(Var->getLocation(), diag::err_auto_var_requires_init)
- << Var->getDeclName() << Type;
+ // Provide a specific diagnostic for uninitialized variable
+ // definitions with reference type.
+ if (Type->isReferenceType()) {
+ Diag(Var->getLocation(), diag::err_reference_var_requires_init)
+ << Var->getDeclName()
+ << SourceRange(Var->getLocation(), Var->getLocation());
+ Var->setInvalidDecl();
+ return;
+ }
+
+ // Do not attempt to type-check the default initializer for a
+ // variable with dependent type.
+ if (Type->isDependentType())
+ return;
+
+ if (Var->isInvalidDecl())
+ return;
+
+ if (RequireCompleteType(Var->getLocation(),
+ Context.getBaseElementType(Type),
+ diag::err_typecheck_decl_incomplete_type)) {
Var->setInvalidDecl();
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);
+ // The variable can not have an abstract class type.
+ if (RequireNonAbstractType(Var->getLocation(), Type,
+ diag::err_abstract_type_in_decl,
+ AbstractVariableType)) {
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
- // is a declaration.
- if (Var->isStaticDataMember() &&
- Var->getInstantiatedFromStaticDataMember() &&
- Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
- return;
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(Var);
+ InitializationKind Kind
+ = InitializationKind::CreateDefault(Var->getLocation());
- // C++ [dcl.init]p9:
- // If no initializer is specified for an object, and the object
- // is of (possibly cv-qualified) non-POD class type (or array
- // thereof), the object shall be default-initialized; if the
- // object is of const-qualified type, the underlying class type
- // shall have a user-declared default constructor.
- //
- // FIXME: Diagnose the "user-declared default constructor" bit.
- if (getLangOptions().CPlusPlus) {
- QualType InitType = Type;
- if (const ArrayType *Array = Context.getAsArrayType(Type))
- InitType = Context.getBaseElementType(Array);
- if ((!Var->hasExternalStorage() && !Var->isExternC()) &&
- InitType->isRecordType() && !InitType->isDependentType()) {
- if (!RequireCompleteType(Var->getLocation(), InitType,
- diag::err_invalid_incomplete_type_use)) {
- InitializedEntity Entity
- = InitializedEntity::InitializeVariable(Var);
- InitializationKind Kind
- = InitializationKind::CreateDefault(Var->getLocation());
-
- InitializationSequence InitSeq(*this, Entity, Kind, 0, 0);
- OwningExprResult Init = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, 0, 0));
- if (Init.isInvalid())
- Var->setInvalidDecl();
- else {
- Var->setInit(Context,
- MaybeCreateCXXExprWithTemporaries(Init.takeAs<Expr>()));
- FinalizeVarWithDestructor(Var, InitType);
- }
- } else {
- Var->setInvalidDecl();
- }
- }
+ InitializationSequence InitSeq(*this, Entity, Kind, 0, 0);
+ OwningExprResult Init = InitSeq.Perform(*this, Entity, Kind,
+ MultiExprArg(*this, 0, 0));
+ if (Init.isInvalid())
+ Var->setInvalidDecl();
+ else {
+ if (Init.get())
+ Var->setInit(MaybeCreateCXXExprWithTemporaries(Init.takeAs<Expr>()));
- // The variable can not have an abstract class type.
- if (RequireNonAbstractType(Var->getLocation(), Type,
- diag::err_abstract_type_in_decl,
- AbstractVariableType))
- Var->setInvalidDecl();
+ if (getLangOptions().CPlusPlus)
+ if (const RecordType *Record
+ = Context.getBaseElementType(Type)->getAs<RecordType>())
+ FinalizeVarWithDestructor(Var, Record);
}
-
-#if 0
- // FIXME: Temporarily disabled because we are not properly parsing
- // linkage specifications on declarations, e.g.,
- //
- // extern "C" const CGPoint CGPointerZero;
- //
- // C++ [dcl.init]p9:
- //
- // If no initializer is specified for an object, and the
- // object is of (possibly cv-qualified) non-POD class type (or
- // array thereof), the object shall be default-initialized; if
- // the object is of const-qualified type, the underlying class
- // type shall have a user-declared default
- // constructor. Otherwise, if no initializer is specified for
- // an object, the object and its subobjects, if any, have an
- // indeterminate initial value; if the object or any of its
- // subobjects are of const-qualified type, the program is
- // ill-formed.
- //
- // This isn't technically an error in C, so we don't diagnose it.
- //
- // FIXME: Actually perform the POD/user-defined default
- // constructor check.
- if (getLangOptions().CPlusPlus &&
- Context.getCanonicalType(Type).isConstQualified() &&
- !Var->hasExternalStorage())
- Diag(Var->getLocation(), diag::err_const_var_requires_init)
- << Var->getName()
- << SourceRange(Var->getLocation(), Var->getLocation());
-#endif
}
}
@@ -3723,77 +3816,6 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
if (Decl *D = Group[i].getAs<Decl>())
Decls.push_back(D);
- // Perform semantic analysis that depends on having fully processed both
- // the declarator and initializer.
- for (unsigned i = 0, e = Decls.size(); i != e; ++i) {
- VarDecl *IDecl = dyn_cast<VarDecl>(Decls[i]);
- if (!IDecl)
- continue;
- QualType T = IDecl->getType();
-
- // Block scope. C99 6.7p7: If an identifier for an object is declared with
- // no linkage (C99 6.2.2p6), the type for the object shall be complete...
- if (IDecl->isBlockVarDecl() && !IDecl->hasExternalStorage()) {
- if (T->isDependentType()) {
- // If T is dependent, we should not require a complete type.
- // (RequireCompleteType shouldn't be called with dependent types.)
- // But we still can at least check if we've got an array of unspecified
- // size without an initializer.
- if (!IDecl->isInvalidDecl() && T->isIncompleteArrayType() &&
- !IDecl->getInit()) {
- Diag(IDecl->getLocation(), diag::err_typecheck_decl_incomplete_type)
- << T;
- IDecl->setInvalidDecl();
- }
- } else if (!IDecl->isInvalidDecl()) {
- // If T is an incomplete array type with an initializer list that is
- // dependent on something, its size has not been fixed. We could attempt
- // to fix the size for such arrays, but we would still have to check
- // here for initializers containing a C++0x vararg expansion, e.g.
- // template <typename... Args> void f(Args... args) {
- // int vals[] = { args };
- // }
- const IncompleteArrayType *IAT = Context.getAsIncompleteArrayType(T);
- Expr *Init = IDecl->getInit();
- if (IAT && Init &&
- (Init->isTypeDependent() || Init->isValueDependent())) {
- // Check that the member type of the array is complete, at least.
- if (RequireCompleteType(IDecl->getLocation(), IAT->getElementType(),
- diag::err_typecheck_decl_incomplete_type))
- IDecl->setInvalidDecl();
- } else if (RequireCompleteType(IDecl->getLocation(), T,
- diag::err_typecheck_decl_incomplete_type))
- IDecl->setInvalidDecl();
- }
- }
- // File scope. C99 6.9.2p2: A declaration of an identifier for an
- // object that has file scope without an initializer, and without a
- // storage-class specifier or with the storage-class specifier "static",
- // constitutes a tentative definition. Note: A tentative definition with
- // external linkage is valid (C99 6.2.2p5).
- if (IDecl->isTentativeDefinition(Context) && !IDecl->isInvalidDecl()) {
- if (const IncompleteArrayType *ArrayT
- = Context.getAsIncompleteArrayType(T)) {
- if (RequireCompleteType(IDecl->getLocation(),
- ArrayT->getElementType(),
- diag::err_illegal_decl_array_incomplete_type))
- IDecl->setInvalidDecl();
- } else if (IDecl->getStorageClass() == VarDecl::Static) {
- // C99 6.9.2p3: If the declaration of an identifier for an object is
- // a tentative definition and has internal linkage (C99 6.2.2p3), the
- // declared type shall not be an incomplete type.
- // NOTE: code such as the following
- // static struct s;
- // struct s { int a; };
- // is accepted by gcc. Hence here we issue a warning instead of
- // an error and we do not invalidate the static declaration.
- // NOTE: to avoid multiple warnings, only check the first declaration.
- if (IDecl->getPreviousDeclaration() == 0)
- RequireCompleteType(IDecl->getLocation(), T,
- diag::ext_typecheck_decl_incomplete_type);
- }
- }
- }
return DeclGroupPtrTy::make(DeclGroupRef::Create(Context,
Decls.data(), Decls.size()));
}
@@ -3853,6 +3875,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// Recover by removing the name
II = 0;
D.SetIdentifier(0, D.getIdentifierLoc());
+ D.setInvalidType(true);
}
}
}
@@ -3919,6 +3942,11 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
return DeclPtrTy::make(New);
}
+void Sema::ActOnObjCCatchParam(DeclPtrTy D) {
+ ParmVarDecl *Param = cast<ParmVarDecl>(D.getAs<Decl>());
+ Param->setDeclContext(CurContext);
+}
+
void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
SourceLocation LocAfterDecls) {
assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
@@ -4297,8 +4325,8 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
bool HasVAListArg;
if (Context.BuiltinInfo.isPrintfLike(BuiltinID, FormatIdx, HasVAListArg)) {
if (!FD->getAttr<FormatAttr>())
- FD->addAttr(::new (Context) FormatAttr("printf", FormatIdx + 1,
- HasVAListArg ? 0 : FormatIdx + 2));
+ FD->addAttr(::new (Context) FormatAttr(Context, "printf", FormatIdx+1,
+ HasVAListArg ? 0 : FormatIdx+2));
}
// Mark const if we don't care about errno and that is the only
@@ -4311,7 +4339,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
}
if (Context.BuiltinInfo.isNoReturn(BuiltinID))
- FD->addAttr(::new (Context) NoReturnAttr());
+ FD->setType(Context.getNoReturnType(FD->getType()));
if (Context.BuiltinInfo.isNoThrow(BuiltinID))
FD->addAttr(::new (Context) NoThrowAttr());
if (Context.BuiltinInfo.isConst(BuiltinID))
@@ -4335,15 +4363,15 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
// FIXME: NSLog and NSLogv should be target specific
if (const FormatAttr *Format = FD->getAttr<FormatAttr>()) {
// FIXME: We known better than our headers.
- const_cast<FormatAttr *>(Format)->setType("printf");
+ const_cast<FormatAttr *>(Format)->setType(Context, "printf");
} else
- FD->addAttr(::new (Context) FormatAttr("printf", 1,
+ FD->addAttr(::new (Context) FormatAttr(Context, "printf", 1,
Name->isStr("NSLogv") ? 0 : 2));
} else if (Name->isStr("asprintf") || Name->isStr("vasprintf")) {
// FIXME: asprintf and vasprintf aren't C99 functions. Should they be
// target-specific builtins, perhaps?
if (!FD->getAttr<FormatAttr>())
- FD->addAttr(::new (Context) FormatAttr("printf", 2,
+ FD->addAttr(::new (Context) FormatAttr(Context, "printf", 2,
Name->isStr("vasprintf") ? 0 : 3));
}
}
@@ -4614,7 +4642,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Diagnose attempts to redefine a tag.
if (TUK == TUK_Definition) {
- if (TagDecl *Def = PrevTagDecl->getDefinition(Context)) {
+ if (TagDecl *Def = PrevTagDecl->getDefinition()) {
// If we're defining a specialization and the previous definition
// is from an implicit instantiation, don't emit an error
// here; we'll catch this in the general case below.
@@ -4927,9 +4955,17 @@ RecordDynamicClassesWithNoKeyFunction(Sema &S, CXXRecordDecl *Record,
if (Record->isDependentContext() || !Record->isDefinition())
return;
- if (Record->isDynamicClass() && !S.Context.getKeyFunction(Record))
- S.ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record, Loc));
+ if (Record->isDynamicClass()) {
+ const CXXMethodDecl *KeyFunction = S.Context.getKeyFunction(Record);
+ if (!KeyFunction)
+ S.ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record,
+ Loc));
+
+ if ((!KeyFunction || (KeyFunction->getBody() && KeyFunction->isInlined()))
+ && Record->getLinkage() == ExternalLinkage)
+ S.Diag(Record->getLocation(), diag::warn_weak_vtable) << Record;
+ }
for (DeclContext::decl_iterator D = Record->decls_begin(),
DEnd = Record->decls_end();
D != DEnd; ++D) {
@@ -5156,7 +5192,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
NewFD->setInvalidDecl();
}
- if (getLangOptions().CPlusPlus) {
+ if (!InvalidDecl && getLangOptions().CPlusPlus) {
CXXRecordDecl* CXXRecord = cast<CXXRecordDecl>(Record);
if (!T->isPODType())
@@ -5584,7 +5620,7 @@ void Sema::ActOnFields(Scope* S,
// Okay, we successfully defined 'Record'.
if (Record) {
- Record->completeDefinition(Context);
+ Record->completeDefinition();
} else {
ObjCIvarDecl **ClsFields =
reinterpret_cast<ObjCIvarDecl**>(RecFields.data());
@@ -5628,6 +5664,45 @@ void Sema::ActOnFields(Scope* S,
ProcessDeclAttributeList(S, Record, Attr);
}
+/// \brief Determine whether the given integral value is representable within
+/// the given type T.
+static bool isRepresentableIntegerValue(ASTContext &Context,
+ llvm::APSInt &Value,
+ QualType T) {
+ assert(T->isIntegralType() && "Integral type required!");
+ unsigned BitWidth = Context.getTypeSize(T);
+
+ if (Value.isUnsigned() || Value.isNonNegative())
+ return Value.getActiveBits() < BitWidth;
+
+ return Value.getMinSignedBits() <= BitWidth;
+}
+
+// \brief Given an integral type, return the next larger integral type
+// (or a NULL type of no such type exists).
+static QualType getNextLargerIntegralType(ASTContext &Context, QualType T) {
+ // FIXME: Int128/UInt128 support, which also needs to be introduced into
+ // enum checking below.
+ assert(T->isIntegralType() && "Integral type required!");
+ const unsigned NumTypes = 4;
+ QualType SignedIntegralTypes[NumTypes] = {
+ Context.ShortTy, Context.IntTy, Context.LongTy, Context.LongLongTy
+ };
+ QualType UnsignedIntegralTypes[NumTypes] = {
+ Context.UnsignedShortTy, Context.UnsignedIntTy, Context.UnsignedLongTy,
+ Context.UnsignedLongLongTy
+ };
+
+ unsigned BitWidth = Context.getTypeSize(T);
+ QualType *Types = T->isSignedIntegerType()? SignedIntegralTypes
+ : UnsignedIntegralTypes;
+ for (unsigned I = 0; I != NumTypes; ++I)
+ if (Context.getTypeSize(Types[I]) > BitWidth)
+ return Types[I];
+
+ return QualType();
+}
+
EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
EnumConstantDecl *LastEnumConst,
SourceLocation IdLoc,
@@ -5635,24 +5710,45 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
ExprArg val) {
Expr *Val = (Expr *)val.get();
- llvm::APSInt EnumVal(32);
+ unsigned IntWidth = Context.Target.getIntWidth();
+ llvm::APSInt EnumVal(IntWidth);
QualType EltTy;
if (Val) {
if (Enum->isDependentType())
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 (VerifyIntegerConstantExpression(Val, &EnumVal)) {
Val = 0;
- } else {
+ } else {
+ if (!getLangOptions().CPlusPlus) {
+ // C99 6.7.2.2p2:
+ // The expression that defines the value of an enumeration constant
+ // shall be an integer constant expression that has a value
+ // representable as an int.
+
+ // Complain if the value is not representable in an int.
+ if (!isRepresentableIntegerValue(Context, EnumVal, Context.IntTy))
+ Diag(IdLoc, diag::ext_enum_value_not_int)
+ << EnumVal.toString(10) << Val->getSourceRange()
+ << EnumVal.isNonNegative();
+ else if (!Context.hasSameType(Val->getType(), Context.IntTy)) {
+ // Force the type of the expression to 'int'.
+ ImpCastExprToType(Val, Context.IntTy, CastExpr::CK_IntegralCast);
+
+ if (Val != val.get()) {
+ val.release();
+ val = Val;
+ }
+ }
+ }
+
+ // C++0x [dcl.enum]p5:
+ // If the underlying type is not fixed, the type of each enumerator
+ // is the type of its initializing value:
+ // - If an initializer is specified for an enumerator, the
+ // initializing value has the same type as the expression.
EltTy = Val->getType();
}
}
@@ -5661,25 +5757,76 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
if (!Val) {
if (Enum->isDependentType())
EltTy = Context.DependentTy;
- else if (LastEnumConst) {
+ else if (!LastEnumConst) {
+ // C++0x [dcl.enum]p5:
+ // If the underlying type is not fixed, the type of each enumerator
+ // is the type of its initializing value:
+ // - If no initializer is specified for the first enumerator, the
+ // initializing value has an unspecified integral type.
+ //
+ // GCC uses 'int' for its unspecified integral type, as does
+ // C99 6.7.2.2p3.
+ EltTy = Context.IntTy;
+ } else {
// Assign the last value + 1.
EnumVal = LastEnumConst->getInitVal();
++EnumVal;
+ EltTy = LastEnumConst->getType();
// Check for overflow on increment.
- if (EnumVal < LastEnumConst->getInitVal())
- Diag(IdLoc, diag::warn_enum_value_overflow);
-
- EltTy = LastEnumConst->getType();
- } else {
- // First value, set to zero.
- EltTy = Context.IntTy;
- EnumVal.zextOrTrunc(static_cast<uint32_t>(Context.getTypeSize(EltTy)));
- EnumVal.setIsSigned(true);
+ if (EnumVal < LastEnumConst->getInitVal()) {
+ // C++0x [dcl.enum]p5:
+ // If the underlying type is not fixed, the type of each enumerator
+ // is the type of its initializing value:
+ //
+ // - Otherwise the type of the initializing value is the same as
+ // the type of the initializing value of the preceding enumerator
+ // unless the incremented value is not representable in that type,
+ // in which case the type is an unspecified integral type
+ // sufficient to contain the incremented value. If no such type
+ // exists, the program is ill-formed.
+ QualType T = getNextLargerIntegralType(Context, EltTy);
+ if (T.isNull()) {
+ // There is no integral type larger enough to represent this
+ // value. Complain, then allow the value to wrap around.
+ EnumVal = LastEnumConst->getInitVal();
+ EnumVal.zext(EnumVal.getBitWidth() * 2);
+ Diag(IdLoc, diag::warn_enumerator_too_large)
+ << EnumVal.toString(10);
+ } else {
+ EltTy = T;
+ }
+
+ // Retrieve the last enumerator's value, extent that type to the
+ // type that is supposed to be large enough to represent the incremented
+ // value, then increment.
+ EnumVal = LastEnumConst->getInitVal();
+ EnumVal.setIsSigned(EltTy->isSignedIntegerType());
+ EnumVal.zextOrTrunc(Context.getTypeSize(EltTy));
+ ++EnumVal;
+
+ // If we're not in C++, diagnose the overflow of enumerator values,
+ // which in C99 means that the enumerator value is not representable in
+ // an int (C99 6.7.2.2p2). However, we support GCC's extension that
+ // permits enumerator values that are representable in some larger
+ // integral type.
+ if (!getLangOptions().CPlusPlus && !T.isNull())
+ Diag(IdLoc, diag::warn_enum_value_overflow);
+ } else if (!getLangOptions().CPlusPlus &&
+ !isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
+ // Enforce C99 6.7.2.2p2 even when we compute the next value.
+ Diag(IdLoc, diag::ext_enum_value_not_int)
+ << EnumVal.toString(10) << 1;
+ }
}
}
- assert(!EltTy.isNull() && "Enum constant with NULL type");
+ if (!Enum->isDependentType()) {
+ // Make the enumerator value match the signedness and size of the
+ // enumerator's type.
+ EnumVal.zextOrTrunc(Context.getTypeSize(EltTy));
+ EnumVal.setIsSigned(EltTy->isSignedIntegerType());
+ }
val.release();
return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy,
@@ -5759,7 +5906,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
ECD->setType(EnumType);
}
- Enum->completeDefinition(Context, Context.DependentTy, Context.DependentTy);
+ Enum->completeDefinition(Context.DependentTy, Context.DependentTy);
return;
}
@@ -5783,18 +5930,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
cast_or_null<EnumConstantDecl>(Elements[i].getAs<Decl>());
if (!ECD) continue; // Already issued a diagnostic.
- // If the enum value doesn't fit in an int, emit an extension warning.
const llvm::APSInt &InitVal = ECD->getInitVal();
- assert(InitVal.getBitWidth() >= IntWidth &&
- "Should have promoted value to int");
- if (!getLangOptions().CPlusPlus && InitVal.getBitWidth() > IntWidth) {
- llvm::APSInt V(InitVal);
- V.trunc(IntWidth);
- V.extend(InitVal.getBitWidth());
- if (V != InitVal)
- Diag(ECD->getLocation(), diag::ext_enum_value_not_int)
- << InitVal.toString(10);
- }
// Keep track of the size of positive and negative values.
if (InitVal.isUnsigned() || InitVal.isNonNegative())
@@ -5856,8 +5992,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
}
BestPromotionType = (BestWidth <= IntWidth ? Context.IntTy : BestType);
} else {
- // If there is no negative value, figure out which of uint, ulong, ulonglong
- // fits.
+ // If there is no negative value, figure out the smallest type that fits
+ // all of the enumerator values.
// If it's packed, check also if it fits a char or a short.
if (Packed && NumPositiveBits <= CharWidth) {
BestType = Context.UnsignedCharTy;
@@ -5870,30 +6006,26 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
} else if (NumPositiveBits <= IntWidth) {
BestType = Context.UnsignedIntTy;
BestWidth = IntWidth;
- BestPromotionType = (NumPositiveBits == BestWidth
- ? Context.UnsignedIntTy : Context.IntTy);
+ BestPromotionType
+ = (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus)
+ ? Context.UnsignedIntTy : Context.IntTy;
} else if (NumPositiveBits <=
(BestWidth = Context.Target.getLongWidth())) {
BestType = Context.UnsignedLongTy;
- BestPromotionType = (NumPositiveBits == BestWidth
- ? Context.UnsignedLongTy : Context.LongTy);
+ BestPromotionType
+ = (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus)
+ ? Context.UnsignedLongTy : Context.LongTy;
} else {
BestWidth = Context.Target.getLongLongWidth();
assert(NumPositiveBits <= BestWidth &&
"How could an initializer get larger than ULL?");
BestType = Context.UnsignedLongLongTy;
- BestPromotionType = (NumPositiveBits == BestWidth
- ? Context.UnsignedLongLongTy : Context.LongLongTy);
+ BestPromotionType
+ = (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus)
+ ? Context.UnsignedLongLongTy : Context.LongLongTy;
}
}
- // If we're in C and the promotion type is larger than an int, just
- // use the underlying type, which is generally the unsigned integer
- // type of the same rank as the promotion type. This is how the gcc
- // extension works.
- if (!getLangOptions().CPlusPlus && BestPromotionType != Context.IntTy)
- BestPromotionType = BestType;
-
// Loop over all of the enumerator constants, changing their types to match
// the type of the enum if needed.
for (unsigned i = 0; i != NumElements; ++i) {
@@ -5906,23 +6038,17 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
// enumerator value fits in an int, type it as an int, otherwise type it the
// same as the enumerator decl itself. This means that in "enum { X = 1U }"
// that X has type 'int', not 'unsigned'.
- if (!getLangOptions().CPlusPlus && ECD->getType() == Context.IntTy)
- continue;
// Determine whether the value fits into an int.
llvm::APSInt InitVal = ECD->getInitVal();
- bool FitsInInt;
- if (InitVal.isUnsigned() || !InitVal.isNegative())
- FitsInInt = InitVal.getActiveBits() < IntWidth;
- else
- FitsInInt = InitVal.getMinSignedBits() <= IntWidth;
// If it fits into an integer type, force it. Otherwise force it to match
// the enum decl type.
QualType NewTy;
unsigned NewWidth;
bool NewSign;
- if (FitsInInt && !getLangOptions().CPlusPlus) {
+ if (!getLangOptions().CPlusPlus &&
+ isRepresentableIntegerValue(Context, InitVal, Context.IntTy)) {
NewTy = Context.IntTy;
NewWidth = IntWidth;
NewSign = true;
@@ -5960,7 +6086,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
ECD->setType(NewTy);
}
- Enum->completeDefinition(Context, BestType, BestPromotionType);
+ Enum->completeDefinition(BestType, BestPromotionType);
}
Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc,
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 1a12208e5a94..cba1e9e1cd50 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -307,7 +307,7 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
unsigned* start = &NonNullArgs[0];
unsigned size = NonNullArgs.size();
std::sort(start, start + size);
- d->addAttr(::new (S.Context) NonNullAttr(start, size));
+ d->addAttr(::new (S.Context) NonNullAttr(S.Context, start, size));
}
static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -329,7 +329,7 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// FIXME: check if target symbol exists in current file
- d->addAttr(::new (S.Context) AliasAttr(Str->getString()));
+ d->addAttr(::new (S.Context) AliasAttr(S.Context, Str->getString()));
}
static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
@@ -391,6 +391,11 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
}
static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // Don't apply as a decl attribute to ValueDecl.
+ // FIXME: probably ought to diagnose this.
+ if (isa<ValueDecl>(d))
+ return;
+
if (HandleCommonNoReturnAttr(d, Attr, S))
d->addAttr(::new (S.Context) NoReturnAttr());
}
@@ -404,7 +409,7 @@ static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!isFunctionOrMethod(d) && !isa<ParmVarDecl>(d)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName() << 8; /*function, method, or parameter*/
+ << Attr.getName() << 8 /*function, method, or parameter*/;
return;
}
// FIXME: Actually store the attribute on the declaration
@@ -542,17 +547,16 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- const char *TypeStr = Str->getStrData();
- unsigned TypeLen = Str->getByteLength();
+ llvm::StringRef TypeStr = Str->getString();
VisibilityAttr::VisibilityTypes type;
- if (TypeLen == 7 && !memcmp(TypeStr, "default", 7))
+ if (TypeStr == "default")
type = VisibilityAttr::DefaultVisibility;
- else if (TypeLen == 6 && !memcmp(TypeStr, "hidden", 6))
+ else if (TypeStr == "hidden")
type = VisibilityAttr::HiddenVisibility;
- else if (TypeLen == 8 && !memcmp(TypeStr, "internal", 8))
+ else if (TypeStr == "internal")
type = VisibilityAttr::HiddenVisibility; // FIXME
- else if (TypeLen == 9 && !memcmp(TypeStr, "protected", 9))
+ else if (TypeStr == "protected")
type = VisibilityAttr::ProtectedVisibility;
else {
S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_visibility) << TypeStr;
@@ -938,105 +942,9 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
- D->addAttr(::new (S.Context) SectionAttr(SE->getString()));
-}
-
-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) {
- 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;
- }
-
- // stdcall and fastcall attributes are mutually incompatible.
- if (d->getAttr<FastCallAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
- << "stdcall" << "fastcall";
- return;
- }
-
- d->addAttr(::new (S.Context) StdCallAttr());
-}
-
-/// Diagnose the use of a non-standard calling convention on the given
-/// function.
-static void DiagnoseCConv(FunctionDecl *D, const char *CConv,
- SourceLocation Loc, Sema &S) {
- if (!D->hasPrototype()) {
- S.Diag(Loc, diag::err_cconv_knr) << CConv;
- return;
- }
-
- const FunctionProtoType *T = D->getType()->getAs<FunctionProtoType>();
- if (T->isVariadic()) {
- S.Diag(Loc, diag::err_cconv_varargs) << CConv;
- return;
- }
+ D->addAttr(::new (S.Context) SectionAttr(S.Context, SE->getString()));
}
-static void HandleFastCallAttr(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;
- }
-
- if (!isa<FunctionDecl>(d)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
- return;
- }
-
- DiagnoseCConv(cast<FunctionDecl>(d), "fastcall", Attr.getLoc(), S);
-
- // stdcall and fastcall attributes are mutually incompatible.
- if (d->getAttr<StdCallAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
- << "fastcall" << "stdcall";
- return;
- }
-
- d->addAttr(::new (S.Context) FastCallAttr());
-}
static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
@@ -1349,7 +1257,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) FormatAttr(Format, Idx.getZExtValue(),
+ d->addAttr(::new (S.Context) FormatAttr(S.Context, Format, Idx.getZExtValue(),
FirstArg.getZExtValue()));
}
@@ -1435,7 +1343,7 @@ static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate";
return;
}
- d->addAttr(::new (S.Context) AnnotateAttr(SE->getString()));
+ d->addAttr(::new (S.Context) AnnotateAttr(S.Context, SE->getString()));
}
static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -1608,9 +1516,15 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
if (!IntegerMode)
NewTy = S.Context.DoubleTy;
else if (OldTy->isSignedIntegerType())
- NewTy = S.Context.LongLongTy;
+ if (S.Context.Target.getLongWidth() == 64)
+ NewTy = S.Context.LongTy;
+ else
+ NewTy = S.Context.LongLongTy;
else
- NewTy = S.Context.UnsignedLongLongTy;
+ if (S.Context.Target.getLongWidth() == 64)
+ NewTy = S.Context.UnsignedLongTy;
+ else
+ NewTy = S.Context.UnsignedLongLongTy;
break;
case 96:
NewTy = S.Context.LongDoubleTy;
@@ -1903,7 +1817,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_base_check: HandleBaseCheckAttr (D, Attr, S); break;
case AttributeList::AT_carries_dependency:
HandleDependencyAttr (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;
@@ -1912,7 +1825,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_ext_vector_type:
HandleExtVectorTypeAttr(scope, D, Attr, S);
break;
- case AttributeList::AT_fastcall: HandleFastCallAttr (D, Attr, S); break;
case AttributeList::AT_final: HandleFinalAttr (D, Attr, S); break;
case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break;
case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break;
@@ -1935,7 +1847,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break;
case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break;
- case AttributeList::AT_stdcall: HandleStdCallAttr (D, Attr, S); break;
case AttributeList::AT_unavailable: HandleUnavailableAttr (D, Attr, S); break;
case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break;
case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break;
@@ -1964,6 +1875,11 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_no_instrument_function: // Interacts with -pg.
// Just ignore
break;
+ case AttributeList::AT_stdcall:
+ case AttributeList::AT_cdecl:
+ case AttributeList::AT_fastcall:
+ // These are all treated as type attributes.
+ break;
default:
// Ask target about the attribute.
const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema();
@@ -2008,7 +1924,7 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
IdentifierInfo *NDId = ND->getIdentifier();
NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias());
- NewD->addAttr(::new (Context) AliasAttr(NDId->getName()));
+ NewD->addAttr(::new (Context) AliasAttr(Context, NDId->getName()));
NewD->addAttr(::new (Context) WeakAttr());
WeakTopLevelDecl.push_back(NewD);
// FIXME: "hideous" code from Sema::LazilyCreateBuiltin
@@ -2062,48 +1978,71 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
/// on the warning stack.
Action::ParsingDeclStackState Sema::PushParsingDeclaration() {
ParsingDeclDepth++;
- return (ParsingDeclStackState) DelayedDeprecationWarnings.size();
-}
-
-static bool isDeclDeprecated(Decl *D) {
- do {
- if (D->hasAttr<DeprecatedAttr>())
- return true;
- } while ((D = cast_or_null<Decl>(D->getDeclContext())));
- return false;
+ return (ParsingDeclStackState) DelayedDiagnostics.size();
}
void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) {
assert(ParsingDeclDepth > 0 && "empty ParsingDeclaration stack");
ParsingDeclDepth--;
- if (DelayedDeprecationWarnings.empty())
+ if (DelayedDiagnostics.empty())
return;
unsigned SavedIndex = (unsigned) S;
- assert(SavedIndex <= DelayedDeprecationWarnings.size() &&
+ assert(SavedIndex <= DelayedDiagnostics.size() &&
"saved index is out of bounds");
- if (Ctx && !isDeclDeprecated(Ctx.getAs<Decl>())) {
- for (unsigned I = 0, E = DelayedDeprecationWarnings.size(); I != E; ++I) {
- SourceLocation Loc = DelayedDeprecationWarnings[I].first;
- NamedDecl *&ND = DelayedDeprecationWarnings[I].second;
- if (ND) {
- Diag(Loc, diag::warn_deprecated) << ND->getDeclName();
-
- // Prevent this from triggering multiple times.
- ND = 0;
+ // We only want to actually emit delayed diagnostics when we
+ // successfully parsed a decl.
+ Decl *D = Ctx ? Ctx.getAs<Decl>() : 0;
+ if (D) {
+ // We really do want to start with 0 here. We get one push for a
+ // decl spec and another for each declarator; in a decl group like:
+ // deprecated_typedef foo, *bar, baz();
+ // only the declarator pops will be passed decls. This is correct;
+ // we really do need to consider delayed diagnostics from the decl spec
+ // for each of the different declarations.
+ for (unsigned I = 0, E = DelayedDiagnostics.size(); I != E; ++I) {
+ if (DelayedDiagnostics[I].Triggered)
+ continue;
+
+ switch (DelayedDiagnostics[I].Kind) {
+ case DelayedDiagnostic::Deprecation:
+ HandleDelayedDeprecationCheck(DelayedDiagnostics[I], D);
+ break;
+
+ case DelayedDiagnostic::Access:
+ HandleDelayedAccessCheck(DelayedDiagnostics[I], D);
+ break;
}
}
}
- DelayedDeprecationWarnings.set_size(SavedIndex);
+ DelayedDiagnostics.set_size(SavedIndex);
+}
+
+static bool isDeclDeprecated(Decl *D) {
+ do {
+ if (D->hasAttr<DeprecatedAttr>())
+ return true;
+ } while ((D = cast_or_null<Decl>(D->getDeclContext())));
+ return false;
+}
+
+void Sema::HandleDelayedDeprecationCheck(Sema::DelayedDiagnostic &DD,
+ Decl *Ctx) {
+ if (isDeclDeprecated(Ctx))
+ return;
+
+ DD.Triggered = true;
+ Diag(DD.Loc, diag::warn_deprecated)
+ << DD.DeprecationData.Decl->getDeclName();
}
void Sema::EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc) {
// Delay if we're currently parsing a declaration.
if (ParsingDeclDepth) {
- DelayedDeprecationWarnings.push_back(std::make_pair(Loc, D));
+ DelayedDiagnostics.push_back(DelayedDiagnostic::makeDeprecation(Loc, D));
return;
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 9ec95f3d170d..9defcca7e565 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -356,9 +356,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
}
}
- if (CheckEquivalentExceptionSpec(
- Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
- New->getType()->getAs<FunctionProtoType>(), New->getLocation()))
+ if (CheckEquivalentExceptionSpec(Old, New))
Invalid = true;
return Invalid;
@@ -433,7 +431,7 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
} else
CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext);
- if (CurDecl)
+ if (CurDecl && CurDecl->getIdentifier())
return &II == CurDecl->getIdentifier();
else
return false;
@@ -486,7 +484,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
// If the base class is polymorphic or isn't empty, the new one is/isn't, too.
RecordDecl *BaseDecl = BaseType->getAs<RecordType>()->getDecl();
assert(BaseDecl && "Record type has no declaration");
- BaseDecl = BaseDecl->getDefinition(Context);
+ BaseDecl = BaseDecl->getDefinition();
assert(BaseDecl && "Base type is not incomplete, but has no definition");
CXXRecordDecl * CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl);
assert(CXXBaseDecl && "Base type is not a C++ type");
@@ -641,7 +639,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
}
// Attach the remaining base class specifiers to the derived class.
- Class->setBases(Context, Bases, NumGoodBases);
+ Class->setBases(Bases, NumGoodBases);
// Delete the remaining (good) base class specifiers, since their
// data has been copied into the CXXRecordDecl.
@@ -680,7 +678,8 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base) {
CXXRecordDecl *DerivedRD = cast<CXXRecordDecl>(DerivedRT->getDecl());
CXXRecordDecl *BaseRD = cast<CXXRecordDecl>(BaseRT->getDecl());
- return DerivedRD->isDerivedFrom(BaseRD);
+ // FIXME: instantiate DerivedRD if necessary. We need a PoI for this.
+ return DerivedRD->hasDefinition() && DerivedRD->isDerivedFrom(BaseRD);
}
/// \brief Determine whether the type \p Derived is a C++ class that is
@@ -712,7 +711,7 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) {
/// if there is an error.
bool
Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
- unsigned InaccessibleBaseID,
+ AccessDiagnosticsKind ADK,
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
DeclarationName Name) {
@@ -728,11 +727,20 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
(void)DerivationOkay;
if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
- if (InaccessibleBaseID == 0)
+ if (ADK == ADK_quiet)
return false;
+
// Check that the base class can be accessed.
- return CheckBaseClassAccess(Derived, Base, InaccessibleBaseID, Paths, Loc,
- Name);
+ switch (CheckBaseClassAccess(Loc, /*IsBaseToDerived*/ false,
+ Base, Derived, Paths.front(),
+ /*force*/ false,
+ /*unprivileged*/ false,
+ ADK)) {
+ case AR_accessible: return false;
+ case AR_inaccessible: return true;
+ case AR_dependent: return false;
+ case AR_delayed: return false;
+ }
}
// We know that the derived-to-base conversion is ambiguous, and
@@ -763,8 +771,7 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
SourceLocation Loc, SourceRange Range,
bool IgnoreAccess) {
return CheckDerivedToBaseConversion(Derived, Base,
- IgnoreAccess ? 0 :
- diag::err_conv_to_inaccessible_base,
+ IgnoreAccess ? ADK_quiet : ADK_normal,
diag::err_ambiguous_derived_to_base_conv,
Loc, Range, DeclarationName());
}
@@ -1195,10 +1202,6 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
unsigned NumArgs, SourceLocation IdLoc,
SourceLocation LParenLoc,
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.
@@ -1220,65 +1223,80 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
for (unsigned i = 0; i < NumArgs; i++)
HasDependentArg |= Args[i]->isTypeDependent();
- CXXConstructorDecl *C = 0;
QualType FieldType = Member->getType();
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
- if (FieldType->isDependentType()) {
- // Can't check init for dependent type.
- } else if (FieldType->isRecordType()) {
- // Member is a record (struct/union/class), so pass the initializer
- // arguments down to the record's constructor.
- if (!HasDependentArg) {
- C = PerformInitializationByConstructor(FieldType,
- MultiExprArg(*this,
- (void**)Args,
- NumArgs),
- IdLoc,
- SourceRange(IdLoc, RParenLoc),
- Member->getDeclName(),
- InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc),
- ConstructorArgs);
-
- if (C) {
- // Take over the constructor arguments as our own.
- NumArgs = ConstructorArgs.size();
- Args = (Expr **)ConstructorArgs.take();
- }
- }
- } else if (NumArgs != 1 && NumArgs != 0) {
- // The member type is not a record type (or an array of record
- // types), so it can be only be default- or copy-initialized.
- return Diag(IdLoc, diag::err_mem_initializer_mismatch)
- << Member->getDeclName() << SourceRange(IdLoc, RParenLoc);
- } else if (!HasDependentArg) {
- Expr *NewExp;
- if (NumArgs == 0) {
- if (FieldType->isReferenceType()) {
- Diag(IdLoc, diag::err_null_intialized_reference_member)
- << Member->getDeclName();
- return Diag(Member->getLocation(), diag::note_declared_at);
- }
- NewExp = new (Context) CXXZeroInitValueExpr(FieldType, IdLoc, RParenLoc);
- NumArgs = 1;
- }
- else
- NewExp = (Expr*)Args[0];
- if (!Member->isInvalidDecl() &&
- PerformCopyInitialization(NewExp, FieldType, AA_Passing))
- return true;
- Args[0] = NewExp;
+ if (FieldType->isDependentType() || HasDependentArg) {
+ // Can't check initialization for a member of dependent type or when
+ // any of the arguments are type-dependent expressions.
+ OwningExprResult Init
+ = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
+ RParenLoc));
+
+ // Erase any temporaries within this evaluation context; we're not
+ // going to track them in the AST, since we'll be rebuilding the
+ // ASTs during template instantiation.
+ ExprTemporaries.erase(
+ ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
+ ExprTemporaries.end());
+
+ return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc,
+ LParenLoc,
+ Init.takeAs<Expr>(),
+ RParenLoc);
+
}
- // FIXME: CXXBaseOrMemberInitializer should only contain a single
- // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
- ExprTemporaries.clear();
+ if (Member->isInvalidDecl())
+ return true;
+
+ // Initialize the member.
+ InitializedEntity MemberEntity =
+ InitializedEntity::InitializeMember(Member, 0);
+ InitializationKind Kind =
+ InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc);
- // FIXME: Perform direct initialization of the member.
+ InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs);
+
+ OwningExprResult MemberInit =
+ InitSeq.Perform(*this, MemberEntity, Kind,
+ MultiExprArg(*this, (void**)Args, NumArgs), 0);
+ if (MemberInit.isInvalid())
+ return true;
+
+ // C++0x [class.base.init]p7:
+ // The initialization of each base and member constitutes a
+ // full-expression.
+ MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit));
+ if (MemberInit.isInvalid())
+ return true;
+
+ // If we are in a dependent context, template instantiation will
+ // perform this type-checking again. Just save the arguments that we
+ // received in a ParenListExpr.
+ // FIXME: This isn't quite ideal, since our ASTs don't capture all
+ // of the information that we have about the member
+ // initializer. However, deconstructing the ASTs is a dicey process,
+ // and this approach is far more likely to get the corner cases right.
+ if (CurContext->isDependentContext()) {
+ // Bump the reference count of all of the arguments.
+ for (unsigned I = 0; I != NumArgs; ++I)
+ Args[I]->Retain();
+
+ OwningExprResult Init
+ = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
+ RParenLoc));
+ return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc,
+ LParenLoc,
+ Init.takeAs<Expr>(),
+ RParenLoc);
+ }
+
return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc,
- C, LParenLoc, (Expr **)Args,
- NumArgs, RParenLoc);
+ LParenLoc,
+ MemberInit.takeAs<Expr>(),
+ RParenLoc);
}
Sema::MemInitResult
@@ -1291,76 +1309,118 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
HasDependentArg |= Args[i]->isTypeDependent();
SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getSourceRange().getBegin();
- if (!BaseType->isDependentType()) {
- if (!BaseType->isRecordType())
- return Diag(BaseLoc, diag::err_base_init_does_not_name_class)
- << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
-
- // C++ [class.base.init]p2:
- // [...] Unless the mem-initializer-id names a nonstatic data
- // member of the constructor’s class or a direct or virtual base
- // of that class, the mem-initializer is ill-formed. A
- // mem-initializer-list can initialize a base class using any
- // name that denotes that base class type.
-
- // Check for direct and virtual base classes.
- const CXXBaseSpecifier *DirectBaseSpec = 0;
- const CXXBaseSpecifier *VirtualBaseSpec = 0;
- FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
- VirtualBaseSpec);
-
- // C++ [base.class.init]p2:
- // If a mem-initializer-id is ambiguous because it designates both
- // a direct non-virtual base class and an inherited virtual base
- // class, the mem-initializer is ill-formed.
- if (DirectBaseSpec && VirtualBaseSpec)
- return Diag(BaseLoc, diag::err_base_init_direct_and_virtual)
- << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
- // C++ [base.class.init]p2:
- // Unless the mem-initializer-id names a nonstatic data membeer of the
- // constructor's class ot a direst or virtual base of that class, the
- // mem-initializer is ill-formed.
- if (!DirectBaseSpec && !VirtualBaseSpec)
- return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
- << BaseType << ClassDecl->getNameAsCString()
- << BaseTInfo->getTypeLoc().getSourceRange();
- }
-
- CXXConstructorDecl *C = 0;
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
- if (!BaseType->isDependentType() && !HasDependentArg) {
- DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(BaseType).getUnqualifiedType());
-
- C = PerformInitializationByConstructor(BaseType,
- MultiExprArg(*this,
- (void**)Args, NumArgs),
- BaseLoc,
- SourceRange(BaseLoc, RParenLoc),
- Name,
- InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc),
- ConstructorArgs);
- if (C) {
- // Take over the constructor arguments as our own.
- NumArgs = ConstructorArgs.size();
- Args = (Expr **)ConstructorArgs.take();
- }
+ if (BaseType->isDependentType() || HasDependentArg) {
+ // Can't check initialization for a base of dependent type or when
+ // any of the arguments are type-dependent expressions.
+ OwningExprResult BaseInit
+ = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
+ RParenLoc));
+
+ // Erase any temporaries within this evaluation context; we're not
+ // going to track them in the AST, since we'll be rebuilding the
+ // ASTs during template instantiation.
+ ExprTemporaries.erase(
+ ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
+ ExprTemporaries.end());
+
+ return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ LParenLoc,
+ BaseInit.takeAs<Expr>(),
+ RParenLoc);
}
+
+ if (!BaseType->isRecordType())
+ return Diag(BaseLoc, diag::err_base_init_does_not_name_class)
+ << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
- // FIXME: CXXBaseOrMemberInitializer should only contain a single
- // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
- ExprTemporaries.clear();
+ // C++ [class.base.init]p2:
+ // [...] Unless the mem-initializer-id names a nonstatic data
+ // member of the constructor’s class or a direct or virtual base
+ // of that class, the mem-initializer is ill-formed. A
+ // mem-initializer-list can initialize a base class using any
+ // name that denotes that base class type.
+
+ // Check for direct and virtual base classes.
+ const CXXBaseSpecifier *DirectBaseSpec = 0;
+ const CXXBaseSpecifier *VirtualBaseSpec = 0;
+ FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
+ VirtualBaseSpec);
+
+ // C++ [base.class.init]p2:
+ // If a mem-initializer-id is ambiguous because it designates both
+ // a direct non-virtual base class and an inherited virtual base
+ // class, the mem-initializer is ill-formed.
+ if (DirectBaseSpec && VirtualBaseSpec)
+ return Diag(BaseLoc, diag::err_base_init_direct_and_virtual)
+ << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
+ // C++ [base.class.init]p2:
+ // Unless the mem-initializer-id names a nonstatic data membeer of the
+ // constructor's class ot a direst or virtual base of that class, the
+ // mem-initializer is ill-formed.
+ if (!DirectBaseSpec && !VirtualBaseSpec)
+ return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
+ << BaseType << ClassDecl->getNameAsCString()
+ << BaseTInfo->getTypeLoc().getSourceRange();
+
+ CXXBaseSpecifier *BaseSpec
+ = const_cast<CXXBaseSpecifier *>(DirectBaseSpec);
+ if (!BaseSpec)
+ BaseSpec = const_cast<CXXBaseSpecifier *>(VirtualBaseSpec);
+
+ // Initialize the base.
+ InitializedEntity BaseEntity =
+ InitializedEntity::InitializeBase(Context, BaseSpec);
+ InitializationKind Kind =
+ InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc);
+
+ InitializationSequence InitSeq(*this, BaseEntity, Kind, Args, NumArgs);
+
+ OwningExprResult BaseInit =
+ InitSeq.Perform(*this, BaseEntity, Kind,
+ MultiExprArg(*this, (void**)Args, NumArgs), 0);
+ if (BaseInit.isInvalid())
+ return true;
- return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, C,
- LParenLoc, (Expr **)Args,
- NumArgs, RParenLoc);
+ // C++0x [class.base.init]p7:
+ // The initialization of each base and member constitutes a
+ // full-expression.
+ BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.isInvalid())
+ return true;
+
+ // If we are in a dependent context, template instantiation will
+ // perform this type-checking again. Just save the arguments that we
+ // received in a ParenListExpr.
+ // FIXME: This isn't quite ideal, since our ASTs don't capture all
+ // of the information that we have about the base
+ // initializer. However, deconstructing the ASTs is a dicey process,
+ // and this approach is far more likely to get the corner cases right.
+ if (CurContext->isDependentContext()) {
+ // Bump the reference count of all of the arguments.
+ for (unsigned I = 0; I != NumArgs; ++I)
+ Args[I]->Retain();
+
+ OwningExprResult Init
+ = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
+ RParenLoc));
+ return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ LParenLoc,
+ Init.takeAs<Expr>(),
+ RParenLoc);
+ }
+
+ return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ LParenLoc,
+ BaseInit.takeAs<Expr>(),
+ RParenLoc);
}
bool
Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
- CXXBaseOrMemberInitializer **Initializers,
- unsigned NumInitializers,
- bool IsImplicitConstructor) {
+ CXXBaseOrMemberInitializer **Initializers,
+ unsigned NumInitializers,
+ bool IsImplicitConstructor,
+ bool AnyErrors) {
// 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());
@@ -1403,6 +1463,8 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
AllToInit.push_back(Member);
}
} else {
+ llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit;
+
// Push virtual bases before others.
for (CXXRecordDecl::base_class_iterator VBase =
ClassDecl->vbases_begin(),
@@ -1412,44 +1474,34 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
if (CXXBaseOrMemberInitializer *Value
= AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
AllToInit.push_back(Value);
- }
- else {
- CXXRecordDecl *VBaseDecl =
- cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
- assert(VBaseDecl && "SetBaseOrMemberInitializers - VBaseDecl null");
- CXXConstructorDecl *Ctor = VBaseDecl->getDefaultConstructor(Context);
- if (!Ctor) {
- Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
- << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
- << 0 << VBase->getType();
- Diag(VBaseDecl->getLocation(), diag::note_previous_decl)
- << Context.getTagDeclType(VBaseDecl);
+ } else if (!AnyErrors) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeBase(Context, VBase);
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
+ MultiExprArg(*this, 0, 0));
+ BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.isInvalid()) {
HadError = true;
continue;
}
- ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this);
- if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0),
- Constructor->getLocation(), CtorArgs))
+ // Don't attach synthesized base initializers in a dependent
+ // context; they'll be checked again at template instantiation
+ // time.
+ if (CurContext->isDependentContext())
continue;
- MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
-
- // FIXME: CXXBaseOrMemberInitializer should only contain a single
- // subexpression so we can wrap it in a CXXExprWithTemporaries if
- // necessary.
- // FIXME: Is there any better source-location information we can give?
- ExprTemporaries.clear();
- CXXBaseOrMemberInitializer *Member =
+ CXXBaseOrMemberInitializer *CXXBaseInit =
new (Context) CXXBaseOrMemberInitializer(Context,
Context.getTrivialTypeSourceInfo(VBase->getType(),
SourceLocation()),
- Ctor,
SourceLocation(),
- CtorArgs.takeAs<Expr>(),
- CtorArgs.size(),
+ BaseInit.takeAs<Expr>(),
SourceLocation());
- AllToInit.push_back(Member);
+ AllToInit.push_back(CXXBaseInit);
}
}
@@ -1466,43 +1518,34 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
= AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
AllToInit.push_back(Value);
}
- else {
- CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- assert(BaseDecl && "SetBaseOrMemberInitializers - BaseDecl null");
- CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context);
- if (!Ctor) {
- Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
- << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
- << 0 << Base->getType();
- Diag(BaseDecl->getLocation(), diag::note_previous_decl)
- << Context.getTagDeclType(BaseDecl);
+ else if (!AnyErrors) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeBase(Context, Base);
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
+ MultiExprArg(*this, 0, 0));
+ BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.isInvalid()) {
HadError = true;
continue;
}
-
- ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this);
- if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0),
- Constructor->getLocation(), CtorArgs))
+
+ // Don't attach synthesized base initializers in a dependent
+ // context; they'll be regenerated at template instantiation
+ // time.
+ if (CurContext->isDependentContext())
continue;
- MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
-
- // FIXME: CXXBaseOrMemberInitializer should only contain a single
- // subexpression so we can wrap it in a CXXExprWithTemporaries if
- // necessary.
- // FIXME: Is there any better source-location information we can give?
- ExprTemporaries.clear();
- CXXBaseOrMemberInitializer *Member =
+ CXXBaseOrMemberInitializer *CXXBaseInit =
new (Context) CXXBaseOrMemberInitializer(Context,
Context.getTrivialTypeSourceInfo(Base->getType(),
SourceLocation()),
- Ctor,
SourceLocation(),
- CtorArgs.takeAs<Expr>(),
- CtorArgs.size(),
+ BaseInit.takeAs<Expr>(),
SourceLocation());
- AllToInit.push_back(Member);
+ AllToInit.push_back(CXXBaseInit);
}
}
}
@@ -1535,66 +1578,49 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
continue;
}
- if ((*Field)->getType()->isDependentType())
+ if ((*Field)->getType()->isDependentType() || AnyErrors)
continue;
QualType FT = Context.getBaseElementType((*Field)->getType());
- if (const RecordType* RT = FT->getAs<RecordType>()) {
- CXXConstructorDecl *Ctor =
- cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(Context);
- if (!Ctor) {
- 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_decl)
- << Context.getTagDeclType(RT->getDecl());
+ if (FT->getAs<RecordType>()) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeMember(*Field);
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ OwningExprResult MemberInit = InitSeq.Perform(*this, InitEntity, InitKind,
+ MultiExprArg(*this, 0, 0));
+ MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit));
+ if (MemberInit.isInvalid()) {
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))
+
+ // Don't attach synthesized member initializers in a dependent
+ // context; they'll be regenerated a template instantiation
+ // time.
+ if (CurContext->isDependentContext())
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(Context,
*Field, SourceLocation(),
- Ctor,
SourceLocation(),
- CtorArgs.takeAs<Expr>(),
- CtorArgs.size(),
+ MemberInit.takeAs<Expr>(),
SourceLocation());
AllToInit.push_back(Member);
- MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
}
else if (FT->isReferenceType()) {
- Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
+ Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
<< (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)
+ Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
<< (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
<< 1 << (*Field)->getDeclName();
Diag((*Field)->getLocation(), diag::note_declared_at);
@@ -1659,7 +1685,8 @@ static void *GetKeyForMember(CXXBaseOrMemberInitializer *Member,
/// ActOnMemInitializers - Handle the member initializers for a constructor.
void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
- MemInitTy **MemInits, unsigned NumMemInits) {
+ MemInitTy **MemInits, unsigned NumMemInits,
+ bool AnyErrors) {
if (!ConstructorDecl)
return;
@@ -1709,7 +1736,7 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SetBaseOrMemberInitializers(Constructor,
reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits),
- NumMemInits, false);
+ NumMemInits, false, AnyErrors);
if (Constructor->isDependentContext())
return;
@@ -1860,7 +1887,7 @@ void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) {
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(CDtorDecl.getAs<Decl>()))
- SetBaseOrMemberInitializers(Constructor, 0, 0, false);
+ SetBaseOrMemberInitializers(Constructor, 0, 0, false, false);
}
namespace {
@@ -1978,13 +2005,15 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
if (!RT)
return false;
- const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
- if (!RD)
- return false;
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
if (CurrentRD && CurrentRD != RD)
return false;
+ // FIXME: is this reasonable? It matches current behavior, but....
+ if (!RD->getDefinition())
+ return false;
+
if (!RD->isAbstract())
return false;
@@ -2086,6 +2115,11 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
if (Record->isInvalidDecl())
return;
+ // Set access bits correctly on the directly-declared conversions.
+ UnresolvedSetImpl *Convs = Record->getConversionFunctions();
+ for (UnresolvedSetIterator I = Convs->begin(), E = Convs->end(); I != E; ++I)
+ Convs->setAccess(I, (*I)->getAccess());
+
if (!Record->isAbstract()) {
// Collect all the pure virtual methods and see if this is an abstract
// class after all.
@@ -2227,7 +2261,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
/*IdentifierInfo=*/0,
ArgType, /*TInfo=*/0,
VarDecl::None, 0);
- CopyConstructor->setParams(Context, &FromParam, 1);
+ CopyConstructor->setParams(&FromParam, 1);
ClassDecl->addDecl(CopyConstructor);
}
@@ -2311,7 +2345,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
/*IdentifierInfo=*/0,
ArgType, /*TInfo=*/0,
VarDecl::None, 0);
- CopyAssignment->setParams(Context, &FromParam, 1);
+ CopyAssignment->setParams(&FromParam, 1);
// Don't call addedAssignmentOperator. There is no way to distinguish an
// implicit from an explicit assignment operator.
@@ -2793,13 +2827,16 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
SourceLocation IdentLoc,
IdentifierInfo *II,
- SourceLocation LBrace) {
+ SourceLocation LBrace,
+ AttributeList *AttrList) {
NamespaceDecl *Namespc =
NamespaceDecl::Create(Context, CurContext, IdentLoc, II);
Namespc->setLBracLoc(LBrace);
Scope *DeclRegionScope = NamespcScope->getParent();
+ ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
+
if (II) {
// C++ [namespace.def]p2:
// The identifier in an original-namespace-definition shall not have been
@@ -3654,7 +3691,7 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
(NestedNameSpecifier *)SS.getScopeRep(),
IdentLoc, R.getFoundDecl());
- CurContext->addDecl(AliasDecl);
+ PushOnScopeChains(AliasDecl, S);
return DeclPtrTy::make(AliasDecl);
}
@@ -3668,13 +3705,16 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
= cast<CXXRecordDecl>(Constructor->getDeclContext());
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
- if (SetBaseOrMemberInitializers(Constructor, 0, 0, true)) {
+ DeclContext *PreviousContext = CurContext;
+ CurContext = Constructor;
+ if (SetBaseOrMemberInitializers(Constructor, 0, 0, true, false)) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXDefaultConstructor << Context.getTagDeclType(ClassDecl);
Constructor->setInvalidDecl();
} else {
Constructor->setUsed();
}
+ CurContext = PreviousContext;
}
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
@@ -3683,6 +3723,10 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
"DefineImplicitDestructor - call it for implicit default dtor");
CXXRecordDecl *ClassDecl = Destructor->getParent();
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
+
+ DeclContext *PreviousContext = CurContext;
+ CurContext = Destructor;
+
// C++ [class.dtor] p5
// Before the implicitly-declared default destructor for a class is
// implicitly defined, all the implicitly-declared default destructors
@@ -3729,8 +3773,11 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
<< CXXDestructor << Context.getTagDeclType(ClassDecl);
Destructor->setInvalidDecl();
+ CurContext = PreviousContext;
+
return;
}
+ CurContext = PreviousContext;
Destructor->setUsed();
}
@@ -3745,6 +3792,9 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl
= cast<CXXRecordDecl>(MethodDecl->getDeclContext());
+ DeclContext *PreviousContext = CurContext;
+ CurContext = MethodDecl;
+
// C++[class.copy] p12
// Before the implicitly-declared copy assignment operator for a class is
// implicitly defined, all implicitly-declared copy assignment operators
@@ -3788,6 +3838,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
}
if (!err)
MethodDecl->setUsed();
+
+ CurContext = PreviousContext;
}
CXXMethodDecl *
@@ -3808,7 +3860,7 @@ Sema::getAssignOperatorMethod(SourceLocation CurrentLocation,
RHSType,
CurrentLocation));
Expr *Args[2] = { &*LHS, &*RHS };
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(CurrentLocation);
AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2,
CandidateSet);
OverloadCandidateSet::iterator Best;
@@ -3830,6 +3882,10 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl
= cast<CXXRecordDecl>(CopyConstructor->getDeclContext());
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
+
+ DeclContext *PreviousContext = CurContext;
+ CurContext = CopyConstructor;
+
// C++ [class.copy] p209
// Before the implicitly-declared copy constructor for a class is
// implicitly defined, all the implicitly-declared copy constructors
@@ -3858,13 +3914,16 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
}
}
CopyConstructor->setUsed();
+
+ CurContext = PreviousContext;
}
Sema::OwningExprResult
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor,
MultiExprArg ExprArgs,
- bool RequiresZeroInit) {
+ bool RequiresZeroInit,
+ bool BaseInitialization) {
bool Elidable = false;
// C++ [class.copy]p15:
@@ -3897,7 +3956,8 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
}
return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
- Elidable, move(ExprArgs), RequiresZeroInit);
+ Elidable, move(ExprArgs), RequiresZeroInit,
+ BaseInitialization);
}
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
@@ -3906,32 +3966,17 @@ Sema::OwningExprResult
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor, bool Elidable,
MultiExprArg ExprArgs,
- bool RequiresZeroInit) {
+ bool RequiresZeroInit,
+ bool BaseInitialization) {
unsigned NumExprs = ExprArgs.size();
Expr **Exprs = (Expr **)ExprArgs.release();
MarkDeclarationReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
Constructor, Elidable, Exprs, NumExprs,
- RequiresZeroInit));
-}
-
-Sema::OwningExprResult
-Sema::BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Constructor,
- QualType Ty,
- SourceLocation TyBeginLoc,
- MultiExprArg Args,
- SourceLocation RParenLoc) {
- unsigned NumExprs = Args.size();
- Expr **Exprs = (Expr **)Args.release();
-
- MarkDeclarationReferenced(TyBeginLoc, Constructor);
- return Owned(new (Context) CXXTemporaryObjectExpr(Context, Constructor, Ty,
- TyBeginLoc, Exprs,
- NumExprs, RParenLoc));
+ RequiresZeroInit, BaseInitialization));
}
-
bool Sema::InitializeVarWithConstructor(VarDecl *VD,
CXXConstructorDecl *Constructor,
MultiExprArg Exprs) {
@@ -3944,18 +3989,18 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD,
Expr *Temp = TempResult.takeAs<Expr>();
MarkDeclarationReferenced(VD->getLocation(), Constructor);
Temp = MaybeCreateCXXExprWithTemporaries(Temp);
- VD->setInit(Context, Temp);
+ VD->setInit(Temp);
return false;
}
-void Sema::FinalizeVarWithDestructor(VarDecl *VD, QualType DeclInitType) {
- CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(
- DeclInitType->getAs<RecordType>()->getDecl());
- if (!ClassDecl->hasTrivialDestructor())
- if (CXXDestructorDecl *Destructor =
- const_cast<CXXDestructorDecl*>(ClassDecl->getDestructor(Context)))
- MarkDeclarationReferenced(VD->getLocation(), Destructor);
+void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Record->getDecl());
+ if (!ClassDecl->hasTrivialDestructor()) {
+ CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context);
+ MarkDeclarationReferenced(VD->getLocation(), Destructor);
+ CheckDestructorAccess(VD->getLocation(), Record);
+ }
}
/// AddCXXDirectInitializerToDecl - This action is called immediately after
@@ -3991,24 +4036,6 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
// exactly form was it (like the CodeGen) can handle both cases without
// special case code.
- // If either the declaration has a dependent type or if any of the expressions
- // is type-dependent, we represent the initialization via a ParenListExpr for
- // later use during template instantiation.
- if (VDecl->getType()->isDependentType() ||
- Expr::hasAnyTypeDependentArguments((Expr **)Exprs.get(), Exprs.size())) {
- // Let clients know that initialization was done with a direct initializer.
- VDecl->setCXXDirectInitializer(true);
-
- // Store the initialization expressions as a ParenListExpr.
- unsigned NumExprs = Exprs.size();
- VDecl->setInit(Context,
- new (Context) ParenListExpr(Context, LParenLoc,
- (Expr **)Exprs.release(),
- NumExprs, RParenLoc));
- return;
- }
-
-
// C++ 8.5p11:
// The form of initialization (using parentheses or '=') is generally
// insignificant, but does matter when the entity being initialized has a
@@ -4017,7 +4044,8 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
if (const ArrayType *Array = Context.getAsArrayType(DeclInitType))
DeclInitType = Context.getBaseElementType(Array);
- if (RequireCompleteType(VDecl->getLocation(), VDecl->getType(),
+ if (!VDecl->getType()->isDependentType() &&
+ RequireCompleteType(VDecl->getLocation(), VDecl->getType(),
diag::err_typecheck_decl_incomplete_type)) {
VDecl->setInvalidDecl();
return;
@@ -4029,14 +4057,30 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
AbstractVariableType))
VDecl->setInvalidDecl();
- const VarDecl *Def = 0;
- if (VDecl->getDefinition(Def)) {
+ const VarDecl *Def;
+ if ((Def = VDecl->getDefinition()) && Def != VDecl) {
Diag(VDecl->getLocation(), diag::err_redefinition)
<< VDecl->getDeclName();
Diag(Def->getLocation(), diag::note_previous_definition);
VDecl->setInvalidDecl();
return;
}
+
+ // If either the declaration has a dependent type or if any of the
+ // expressions is type-dependent, we represent the initialization
+ // via a ParenListExpr for later use during template instantiation.
+ if (VDecl->getType()->isDependentType() ||
+ Expr::hasAnyTypeDependentArguments((Expr **)Exprs.get(), Exprs.size())) {
+ // Let clients know that initialization was done with a direct initializer.
+ VDecl->setCXXDirectInitializer(true);
+
+ // Store the initialization expressions as a ParenListExpr.
+ unsigned NumExprs = Exprs.size();
+ VDecl->setInit(new (Context) ParenListExpr(Context, LParenLoc,
+ (Expr **)Exprs.release(),
+ NumExprs, RParenLoc));
+ return;
+ }
// Capture the variable that is being initialized and the style of
// initialization.
@@ -4056,11 +4100,11 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
}
Result = MaybeCreateCXXExprWithTemporaries(move(Result));
- VDecl->setInit(Context, Result.takeAs<Expr>());
+ VDecl->setInit(Result.takeAs<Expr>());
VDecl->setCXXDirectInitializer(true);
- if (VDecl->getType()->getAs<RecordType>())
- FinalizeVarWithDestructor(VDecl, DeclInitType);
+ if (const RecordType *Record = VDecl->getType()->getAs<RecordType>())
+ FinalizeVarWithDestructor(VDecl, Record);
}
/// \brief Add the applicable constructor candidates for an initialization
@@ -4112,10 +4156,12 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef,
Constructor->isDefaultConstructor())) {
if (ConstructorTmpl)
SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl,
+ ConstructorTmpl->getAccess(),
/*ExplicitArgs*/ 0,
Args, NumArgs, CandidateSet);
else
- SemaRef.AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
+ SemaRef.AddOverloadCandidate(Constructor, Constructor->getAccess(),
+ Args, NumArgs, CandidateSet);
}
}
}
@@ -4145,7 +4191,7 @@ Sema::TryInitializationByConstructor(QualType ClassType,
SourceLocation Loc,
InitializationKind Kind) {
// Build the overload candidate set
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(Loc);
AddConstructorInitializationCandidates(*this, ClassType, Args, NumArgs, Kind,
CandidateSet);
@@ -4167,92 +4213,6 @@ Sema::TryInitializationByConstructor(QualType ClassType,
return 0;
}
-/// \brief Perform initialization by constructor (C++ [dcl.init]p14), which
-/// may occur as part of direct-initialization or copy-initialization.
-///
-/// \param ClassType the type of the object being initialized, which must have
-/// class type.
-///
-/// \param ArgsPtr the arguments provided to initialize the object
-///
-/// \param Loc the source location where the initialization occurs
-///
-/// \param Range the source range that covers the entire initialization
-///
-/// \param InitEntity the name of the entity being initialized, if known
-///
-/// \param Kind the type of initialization being performed
-///
-/// \param ConvertedArgs a vector that will be filled in with the
-/// appropriately-converted arguments to the constructor (if initialization
-/// succeeded).
-///
-/// \returns the constructor used to initialize the object, if successful.
-/// Otherwise, emits a diagnostic and returns NULL.
-CXXConstructorDecl *
-Sema::PerformInitializationByConstructor(QualType ClassType,
- MultiExprArg ArgsPtr,
- SourceLocation Loc, SourceRange Range,
- DeclarationName InitEntity,
- InitializationKind Kind,
- ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs) {
-
- // Build the overload candidate set
- Expr **Args = (Expr **)ArgsPtr.get();
- unsigned NumArgs = ArgsPtr.size();
- OverloadCandidateSet CandidateSet;
- AddConstructorInitializationCandidates(*this, ClassType, Args, NumArgs, Kind,
- CandidateSet);
-
- OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Loc, Best)) {
- case OR_Success:
- // We found a constructor. Break out so that we can convert the arguments
- // appropriately.
- break;
-
- case OR_No_Viable_Function:
- if (InitEntity)
- Diag(Loc, diag::err_ovl_no_viable_function_in_init)
- << InitEntity << Range;
- else
- Diag(Loc, diag::err_ovl_no_viable_function_in_init)
- << ClassType << Range;
- PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
- return 0;
-
- case OR_Ambiguous:
- if (InitEntity)
- Diag(Loc, diag::err_ovl_ambiguous_init) << InitEntity << Range;
- else
- Diag(Loc, diag::err_ovl_ambiguous_init) << ClassType << Range;
- PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs);
- return 0;
-
- case OR_Deleted:
- if (InitEntity)
- Diag(Loc, diag::err_ovl_deleted_init)
- << Best->Function->isDeleted()
- << InitEntity << Range;
- else {
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(ClassType->getAs<RecordType>()->getDecl());
- Diag(Loc, diag::err_ovl_deleted_init)
- << Best->Function->isDeleted()
- << RD->getDeclName() << Range;
- }
- PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
- return 0;
- }
-
- // Convert the arguments, fill in default arguments, etc.
- CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
- if (CompleteConstructorCall(Constructor, move(ArgsPtr), Loc, ConvertedArgs))
- return 0;
-
- return Constructor;
-}
-
/// \brief Given a constructor and the set of arguments provided for the
/// constructor, convert the arguments and add any required default arguments
/// to form a proper call to this constructor.
@@ -4453,7 +4413,9 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
ICS->Standard.Third = ICK_Identity;
ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
- ICS->Standard.ToTypePtr = T1.getAsOpaquePtr();
+ ICS->Standard.setToType(0, T2);
+ ICS->Standard.setToType(1, T1);
+ ICS->Standard.setToType(2, T1);
ICS->Standard.ReferenceBinding = true;
ICS->Standard.DirectBinding = true;
ICS->Standard.RRefBinding = false;
@@ -4486,7 +4448,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
CXXRecordDecl *T2RecordDecl
= dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(DeclLoc);
const UnresolvedSetImpl *Conversions
= T2RecordDecl->getVisibleConversionFunctions();
for (UnresolvedSetImpl::iterator I = Conversions->begin(),
@@ -4509,10 +4471,11 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
if (Conv->getConversionType()->isLValueReferenceType() &&
(AllowExplicit || !Conv->isExplicit())) {
if (ConvTemplate)
- AddTemplateConversionCandidate(ConvTemplate, ActingDC,
+ AddTemplateConversionCandidate(ConvTemplate, I.getAccess(), ActingDC,
Init, DeclType, CandidateSet);
else
- AddConversionCandidate(Conv, ActingDC, Init, DeclType, CandidateSet);
+ AddConversionCandidate(Conv, I.getAccess(), ActingDC, Init,
+ DeclType, CandidateSet);
}
}
@@ -4606,6 +4569,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
if (!isRValRef && T1.getCVRQualifiers() != Qualifiers::Const) {
if (!ICS)
Diag(DeclLoc, diag::err_not_reference_to_const_init)
+ << T1.isVolatileQualified()
<< T1 << int(InitLvalue != Expr::LV_Valid)
<< T2 << Init->getSourceRange();
return true;
@@ -4642,7 +4606,9 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
ICS->Standard.Third = ICK_Identity;
ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
- ICS->Standard.ToTypePtr = T1.getAsOpaquePtr();
+ ICS->Standard.setToType(0, T2);
+ ICS->Standard.setToType(1, T1);
+ ICS->Standard.setToType(2, T1);
ICS->Standard.ReferenceBinding = true;
ICS->Standard.DirectBinding = false;
ICS->Standard.RRefBinding = isRValRef;
@@ -5611,7 +5577,8 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
QualType NewTy = New->getType()->getAs<FunctionType>()->getResultType();
QualType OldTy = Old->getType()->getAs<FunctionType>()->getResultType();
- if (Context.hasSameType(NewTy, OldTy))
+ if (Context.hasSameType(NewTy, OldTy) ||
+ NewTy->isDependentType() || OldTy->isDependentType())
return false;
// Check if the return types are covariant
@@ -5665,8 +5632,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
}
// Check if we the conversion from derived to base is valid.
- if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy,
- diag::err_covariant_return_inaccessible_base,
+ if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, ADK_covariance,
diag::err_covariant_return_ambiguous_derived_to_base_conv,
// FIXME: Should this point to the return type?
New->getLocation(), SourceRange(), New->getDeclName())) {
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 1b07d19882e0..1e9b56a90ed6 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -446,18 +446,19 @@ Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl,
// Category
ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
assert (CatDecl && "MatchOneProtocolPropertiesInClass");
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Pr = (*P);
- ObjCCategoryDecl::prop_iterator CP, CE;
- // Is this property already in category's list of properties?
- for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP != CE; ++CP)
- if ((*CP)->getIdentifier() == Pr->getIdentifier())
- break;
- if (CP != CE)
- // Property protocol already exist in class. Diagnose any mismatch.
- DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier());
- }
+ if (!CatDecl->IsClassExtension())
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Pr = (*P);
+ ObjCCategoryDecl::prop_iterator CP, CE;
+ // Is this property already in category's list of properties?
+ for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP != CE; ++CP)
+ if ((*CP)->getIdentifier() == Pr->getIdentifier())
+ break;
+ if (CP != CE)
+ // Property protocol already exist in class. Diagnose any mismatch.
+ DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier());
+ }
return;
}
for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
@@ -596,44 +597,59 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
unsigned NumProtoRefs,
const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc) {
- ObjCCategoryDecl *CDecl =
- ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc,
- CategoryLoc, CategoryName);
- // FIXME: PushOnScopeChains?
- CurContext->addDecl(CDecl);
-
+ ObjCCategoryDecl *CDecl = 0;
ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc);
- /// Check that class of this category is already completely declared.
- if (!IDecl || IDecl->isForwardDecl()) {
- CDecl->setInvalidDecl();
- Diag(ClassLoc, diag::err_undef_interface) << ClassName;
- return DeclPtrTy::make(CDecl);
- }
+ if (!CategoryName) {
+ // Class extensions require a special treatment. Use an existing one.
+ for (CDecl = IDecl->getCategoryList(); CDecl;
+ CDecl = CDecl->getNextClassCategory())
+ if (CDecl->IsClassExtension())
+ break;
+ }
+ if (!CDecl) {
+ CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc,
+ CategoryLoc, CategoryName);
+ // FIXME: PushOnScopeChains?
+ CurContext->addDecl(CDecl);
+
+ /// Check that class of this category is already completely declared.
+ if (!IDecl || IDecl->isForwardDecl()) {
+ CDecl->setInvalidDecl();
+ Diag(ClassLoc, diag::err_undef_interface) << ClassName;
+ return DeclPtrTy::make(CDecl);
+ }
- CDecl->setClassInterface(IDecl);
+ CDecl->setClassInterface(IDecl);
+ // Insert first use of class extension to the list of class's categories.
+ if (!CategoryName)
+ CDecl->insertNextClassCategory();
+ }
// If the interface is deprecated, warn about it.
(void)DiagnoseUseOfDecl(IDecl, ClassLoc);
- /// Check for duplicate interface declaration for this category
- ObjCCategoryDecl *CDeclChain;
- for (CDeclChain = IDecl->getCategoryList(); CDeclChain;
- CDeclChain = CDeclChain->getNextClassCategory()) {
- if (CategoryName && CDeclChain->getIdentifier() == CategoryName) {
- Diag(CategoryLoc, diag::warn_dup_category_def)
- << ClassName << CategoryName;
- Diag(CDeclChain->getLocation(), diag::note_previous_definition);
- break;
+ if (CategoryName) {
+ /// Check for duplicate interface declaration for this category
+ ObjCCategoryDecl *CDeclChain;
+ for (CDeclChain = IDecl->getCategoryList(); CDeclChain;
+ CDeclChain = CDeclChain->getNextClassCategory()) {
+ if (CDeclChain->getIdentifier() == CategoryName) {
+ // Class extensions can be declared multiple times.
+ Diag(CategoryLoc, diag::warn_dup_category_def)
+ << ClassName << CategoryName;
+ Diag(CDeclChain->getLocation(), diag::note_previous_definition);
+ break;
+ }
}
+ if (!CDeclChain)
+ CDecl->insertNextClassCategory();
}
- if (!CDeclChain)
- CDecl->insertNextClassCategory();
if (NumProtoRefs) {
CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
// Protocols in the class extension belong to the class.
- if (!CDecl->getIdentifier())
+ if (CDecl->IsClassExtension())
IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs,
NumProtoRefs, ProtoLocs,
Context);
@@ -1102,11 +1118,12 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
CollectImmediateProperties((*PI), PropMap);
}
if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
- for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(),
- E = CATDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = (*P);
- PropMap[Prop->getIdentifier()] = Prop;
- }
+ if (!CATDecl->IsClassExtension())
+ for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(),
+ E = CATDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ PropMap[Prop->getIdentifier()] = Prop;
+ }
// scan through class's protocols.
for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(),
E = CATDecl->protocol_end(); PI != E; ++PI)
@@ -1127,6 +1144,46 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
}
}
+/// LookupPropertyDecl - Looks up a property in the current class and all
+/// its protocols.
+ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl,
+ IdentifierInfo *II) {
+ if (const ObjCInterfaceDecl *IDecl =
+ dyn_cast<ObjCInterfaceDecl>(CDecl)) {
+ for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
+ E = IDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ if (Prop->getIdentifier() == II)
+ return Prop;
+ }
+ // scan through class's protocols.
+ for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
+ E = IDecl->protocol_end(); PI != E; ++PI) {
+ ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II);
+ if (Prop)
+ return Prop;
+ }
+ }
+ else if (const ObjCProtocolDecl *PDecl =
+ dyn_cast<ObjCProtocolDecl>(CDecl)) {
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ if (Prop->getIdentifier() == II)
+ return Prop;
+ }
+ // scan through protocol's protocols.
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI) {
+ ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II);
+ if (Prop)
+ return Prop;
+ }
+ }
+ return 0;
+}
+
+
void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
ObjCContainerDecl *CDecl,
const llvm::DenseSet<Selector>& InsMap) {
@@ -1149,7 +1206,14 @@ void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
PropImplMap.count(Prop))
continue;
-
+ if (LangOpts.ObjCNonFragileABI2) {
+ ActOnPropertyImplDecl(IMPDecl->getLocation(),
+ SourceLocation(),
+ true, DeclPtrTy::make(IMPDecl),
+ Prop->getIdentifier(),
+ Prop->getIdentifier());
+ continue;
+ }
if (!InsMap.count(Prop->getGetterName())) {
Diag(Prop->getLocation(),
isa<ObjCCategoryDecl>(CDecl) ?
@@ -1214,7 +1278,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
// Check class extensions (unnamed categories)
for (ObjCCategoryDecl *Categories = I->getCategoryList();
Categories; Categories = Categories->getNextClassCategory()) {
- if (!Categories->getIdentifier()) {
+ if (Categories->IsClassExtension()) {
ImplMethodsVsClassMethods(IMPDecl, Categories, IncompleteImpl);
break;
}
@@ -1222,7 +1286,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
} else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
// For extended class, unimplemented methods in its protocols will
// be reported in the primary class.
- if (C->getIdentifier()) {
+ if (!C->IsClassExtension()) {
for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(),
E = C->protocol_end(); PI != E; ++PI)
CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
@@ -1443,7 +1507,8 @@ void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) {
// We have a new signature for an existing method - add it.
// This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
- Entry.Next = new ObjCMethodList(Method, Entry.Next);
+ ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>();
+ Entry.Next = new (Mem) ObjCMethodList(Method, Entry.Next);
}
// FIXME: Finish implementing -Wno-strict-selector-match.
@@ -1506,7 +1571,8 @@ void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) {
if (!match) {
// We have a new signature for an existing method - add it.
// This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
- struct ObjCMethodList *OMI = new ObjCMethodList(Method, FirstMethod.Next);
+ ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>();
+ ObjCMethodList *OMI = new (Mem) ObjCMethodList(Method, FirstMethod.Next);
FirstMethod.Next = OMI;
}
}
@@ -1777,17 +1843,18 @@ void Sema::ActOnAtEnd(SourceRange AtEnd,
// Compare protocol properties with those in category
CompareProperties(C, DeclPtrTy::make(C));
- if (C->getIdentifier() == 0)
+ if (C->IsClassExtension())
DiagnoseClassExtensionDupMethods(C, C->getClassInterface());
}
if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(ClassDecl)) {
- // ProcessPropertyDecl is responsible for diagnosing conflicts with any
- // user-defined setter/getter. It also synthesizes setter/getter methods
- // and adds them to the DeclContext and global method pools.
- for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(),
- E = CDecl->prop_end();
- I != E; ++I)
- ProcessPropertyDecl(*I, CDecl);
+ if (CDecl->getIdentifier())
+ // ProcessPropertyDecl is responsible for diagnosing conflicts with any
+ // user-defined setter/getter. It also synthesizes setter/getter methods
+ // and adds them to the DeclContext and global method pools.
+ for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(),
+ E = CDecl->prop_end();
+ I != E; ++I)
+ ProcessPropertyDecl(*I, CDecl);
CDecl->setAtEndRange(AtEnd);
}
if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
@@ -2088,7 +2155,22 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
// May modify Attributes.
CheckObjCPropertyAttributes(T, AtLoc, Attributes);
if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl))
- if (!CDecl->getIdentifier()) {
+ if (CDecl->IsClassExtension()) {
+ // Diagnose if this property is already in continuation class.
+ DeclContext *DC = dyn_cast<DeclContext>(ClassDecl);
+ assert(DC && "ClassDecl is not a DeclContext");
+ DeclContext::lookup_result Found = DC->lookup(FD.D.getIdentifier());
+ if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) {
+ Diag(AtLoc, diag::err_duplicate_property);
+ Diag((*Found.first)->getLocation(), diag::note_property_declare);
+ return DeclPtrTy();
+ }
+ ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
+ FD.D.getIdentifierLoc(),
+ FD.D.getIdentifier(),
+ AtLoc, T);
+ DC->addDecl(PDecl);
+
// This is a continuation class. property requires special
// handling.
if ((CCPrimary = CDecl->getClassInterface())) {
@@ -2152,6 +2234,7 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
ProcessPropertyDecl(PIDecl, CCPrimary);
return DeclPtrTy();
}
+
// No matching property found in the primary class. Just fall thru
// and add property to continuation class's primary class.
ClassDecl = CCPrimary;
@@ -2246,6 +2329,28 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
return DeclPtrTy::make(PDecl);
}
+ObjCIvarDecl*
+Sema::SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl,
+ IdentifierInfo *NameII) {
+ ObjCIvarDecl *Ivar = 0;
+ ObjCPropertyDecl *Prop = LookupPropertyDecl(IDecl, NameII);
+ if (Prop && !Prop->isInvalidDecl()) {
+ DeclContext *EnclosingContext = cast_or_null<DeclContext>(IDecl);
+ QualType PropType = Context.getCanonicalType(Prop->getType());
+ assert(EnclosingContext &&
+ "null DeclContext for synthesized ivar - SynthesizeNewPropertyIvar");
+ Ivar = ObjCIvarDecl::Create(Context, EnclosingContext,
+ Prop->getLocation(),
+ NameII, PropType, /*Dinfo=*/0,
+ ObjCIvarDecl::Public,
+ (Expr *)0);
+ Ivar->setLexicalDeclContext(IDecl);
+ IDecl->addDecl(Ivar);
+ Prop->setPropertyIvarDecl(Ivar);
+ }
+ return Ivar;
+}
+
/// ActOnPropertyImplDecl - This routine performs semantic checks and
/// builds the AST node for a property implementation declaration; declared
/// as @synthesize or @dynamic.
@@ -2283,7 +2388,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
}
if (const ObjCCategoryDecl *CD =
dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) {
- if (CD->getIdentifier()) {
+ if (!CD->IsClassExtension()) {
Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName();
Diag(property->getLocation(), diag::note_property_declare);
return DeclPtrTy();
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 7e2a98d0bf1f..9be411b552ad 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -12,10 +12,11 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
-#include "clang/Basic/Diagnostic.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallPtrSet.h"
namespace clang {
@@ -92,6 +93,52 @@ bool Sema::CheckDistantExceptionSpec(QualType T) {
return FnT->hasExceptionSpec();
}
+bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
+ bool MissingEmptyExceptionSpecification = false;
+ if (!CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec,
+ diag::note_previous_declaration,
+ Old->getType()->getAs<FunctionProtoType>(),
+ Old->getLocation(),
+ New->getType()->getAs<FunctionProtoType>(),
+ New->getLocation(),
+ &MissingEmptyExceptionSpecification))
+ return false;
+
+ // The failure was something other than an empty exception
+ // specification; return an error.
+ if (!MissingEmptyExceptionSpecification)
+ return true;
+
+ // The new function declaration is only missing an empty exception
+ // specification "throw()". If the throw() specification came from a
+ // function in a system header that has C linkage, just add an empty
+ // exception specification to the "new" declaration. This is an
+ // egregious workaround for glibc, which adds throw() specifications
+ // to many libc functions as an optimization. Unfortunately, that
+ // optimization isn't permitted by the C++ standard, so we're forced
+ // to work around it here.
+ if (isa<FunctionProtoType>(New->getType()) &&
+ Context.getSourceManager().isInSystemHeader(Old->getLocation()) &&
+ Old->isExternC()) {
+ const FunctionProtoType *NewProto
+ = cast<FunctionProtoType>(New->getType());
+ QualType NewType = Context.getFunctionType(NewProto->getResultType(),
+ NewProto->arg_type_begin(),
+ NewProto->getNumArgs(),
+ NewProto->isVariadic(),
+ NewProto->getTypeQuals(),
+ true, false, 0, 0,
+ NewProto->getNoReturnAttr(),
+ NewProto->getCallConv());
+ New->setType(NewType);
+ return false;
+ }
+
+ Diag(New->getLocation(), diag::err_mismatched_exception_spec);
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ return true;
+}
+
/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
/// exception specifications. Exception specifications are equivalent if
/// they allow exactly the same set of exception types. It does not matter how
@@ -111,12 +158,26 @@ bool Sema::CheckEquivalentExceptionSpec(
bool Sema::CheckEquivalentExceptionSpec(
const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
const FunctionProtoType *Old, SourceLocation OldLoc,
- const FunctionProtoType *New, SourceLocation NewLoc) {
+ const FunctionProtoType *New, SourceLocation NewLoc,
+ bool *MissingEmptyExceptionSpecification) {
+ if (MissingEmptyExceptionSpecification)
+ *MissingEmptyExceptionSpecification = false;
+
bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec();
bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec();
if (OldAny && NewAny)
return false;
if (OldAny || NewAny) {
+ if (MissingEmptyExceptionSpecification && Old->hasExceptionSpec() &&
+ !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0 &&
+ !New->hasExceptionSpec()) {
+ // The old type has a throw() exception specification and the
+ // new type has no exception specification, and the caller asked
+ // to handle this itself.
+ *MissingEmptyExceptionSpecification = true;
+ return true;
+ }
+
Diag(NewLoc, DiagID);
if (NoteID.getDiagID() != 0)
Diag(OldLoc, NoteID);
@@ -232,8 +293,22 @@ bool Sema::CheckExceptionSpecSubset(
if (Paths.isAmbiguous(CanonicalSuperT))
continue;
- if (FindInaccessibleBase(CanonicalSubT, CanonicalSuperT, Paths, true))
- continue;
+ // Do this check from a context without privileges.
+ switch (CheckBaseClassAccess(SourceLocation(), false,
+ CanonicalSuperT, CanonicalSubT,
+ Paths.front(),
+ /*ForceCheck*/ true,
+ /*ForceUnprivileged*/ true,
+ ADK_quiet)) {
+ case AR_accessible: break;
+ case AR_inaccessible: continue;
+ case AR_dependent:
+ llvm_unreachable("access check dependent for unprivileged context");
+ break;
+ case AR_delayed:
+ llvm_unreachable("access check delayed in non-declaration");
+ break;
+ }
Contained = true;
break;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 50976f7b704b..633884f673ba 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -14,7 +14,7 @@
#include "Sema.h"
#include "SemaInit.h"
#include "Lookup.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -200,6 +200,28 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) {
}
}
+void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) {
+ DefaultFunctionArrayConversion(E);
+
+ QualType Ty = E->getType();
+ assert(!Ty.isNull() && "DefaultFunctionArrayLvalueConversion - missing type");
+ if (!Ty->isDependentType() && Ty.hasQualifiers() &&
+ (!getLangOptions().CPlusPlus || !Ty->isRecordType()) &&
+ E->isLvalue(Context) == Expr::LV_Valid) {
+ // C++ [conv.lval]p1:
+ // [...] If T is a non-class type, the type of the rvalue is the
+ // cv-unqualified version of T. Otherwise, the type of the
+ // rvalue is T
+ //
+ // C99 6.3.2.1p2:
+ // If the lvalue has qualified type, the value has the unqualified
+ // version of the type of the lvalue; otherwise, the value has the
+ // type of the lvalue.
+ ImpCastExprToType(E, Ty.getUnqualifiedType(), CastExpr::CK_NoOp);
+ }
+}
+
+
/// UsualUnaryConversions - Performs various conversions that are common to most
/// operators (C99 6.3). The conversions of array and function types are
/// sometimes surpressed. For example, the array->pointer conversion doesn't
@@ -233,7 +255,7 @@ Expr *Sema::UsualUnaryConversions(Expr *&Expr) {
return Expr;
}
- DefaultFunctionArrayConversion(Expr);
+ DefaultFunctionArrayLvalueConversion(Expr);
return Expr;
}
@@ -678,7 +700,13 @@ static void DecomposeTemplateName(LookupResult &R, const UnqualifiedId &Id) {
R.resolveKind();
}
+/// Determines whether the given record is "fully-formed" at the given
+/// location, i.e. whether a qualified lookup into it is assured of
+/// getting consistent results already.
static bool IsFullyFormedScope(Sema &SemaRef, CXXRecordDecl *Record) {
+ if (!Record->hasDefinition())
+ return false;
+
for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(),
E = Record->bases_end(); I != E; ++I) {
CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType());
@@ -686,7 +714,7 @@ static bool IsFullyFormedScope(Sema &SemaRef, CXXRecordDecl *Record) {
if (!BaseRT) return false;
CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
- if (!BaseRecord->isDefinition() ||
+ if (!BaseRecord->hasDefinition() ||
!IsFullyFormedScope(SemaRef, BaseRecord))
return false;
}
@@ -719,7 +747,7 @@ static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
if (Bases.count(Record->getCanonicalDecl()))
return false;
- RecordDecl *RD = Record->getDefinition(SemaRef.Context);
+ RecordDecl *RD = Record->getDefinition();
if (!RD) return false;
Record = cast<CXXRecordDecl>(RD);
@@ -1243,9 +1271,9 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
else
LookForIvars = (Lookup.isSingleResult() &&
Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod());
-
+ ObjCInterfaceDecl *IFace = 0;
if (LookForIvars) {
- ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
+ IFace = getCurMethodDecl()->getClassInterface();
ObjCInterfaceDecl *ClassDeclared;
if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) {
// Diagnose using an ivar in a class method.
@@ -1314,6 +1342,11 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
}
}
}
+ if (LangOpts.ObjCNonFragileABI2 && LookForIvars && Lookup.empty()) {
+ ObjCIvarDecl *Ivar = SynthesizeNewPropertyIvar(IFace, II);
+ if (Ivar)
+ return LookupInObjCMethod(Lookup, S, II, AllowBuiltinCreation);
+ }
// Sentinel value saying that we didn't do anything special.
return Owned((Expr*) 0);
}
@@ -1487,7 +1520,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
bool NeedsADL) {
// If this is a single, fully-resolved result and we don't need ADL,
// just build an ordinary singleton decl ref.
- if (!NeedsADL && R.isSingleResult())
+ if (!NeedsADL && R.isSingleResult() && !R.getAsSingle<FunctionTemplateDecl>())
return BuildDeclarationNameExpr(SS, R.getNameLoc(), R.getFoundDecl());
// We only need to check the declaration if there's exactly one
@@ -1497,16 +1530,20 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
CheckDeclInExpr(*this, R.getNameLoc(), R.getFoundDecl()))
return ExprError();
+ // Otherwise, just build an unresolved lookup expression. Suppress
+ // any lookup-related diagnostics; we'll hash these out later, when
+ // we've picked a target.
+ R.suppressDiagnostics();
+
bool Dependent
= UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), 0);
UnresolvedLookupExpr *ULE
- = UnresolvedLookupExpr::Create(Context, Dependent,
+ = UnresolvedLookupExpr::Create(Context, Dependent, R.getNamingClass(),
(NestedNameSpecifier*) SS.getScopeRep(),
SS.getRange(),
R.getLookupName(), R.getNameLoc(),
NeedsADL, R.isOverloadedResult());
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
- ULE->addDecl(*I);
+ ULE->addDecls(R.begin(), R.end());
return Owned(ULE);
}
@@ -1616,8 +1653,7 @@ Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
if (cast<DeclContext>(currentDecl)->isDependentContext()) {
ResTy = Context.DependentTy;
} else {
- unsigned Length =
- PredefinedExpr::ComputeName(Context, IT, currentDecl).length();
+ unsigned Length = PredefinedExpr::ComputeName(IT, currentDecl).length();
llvm::APInt LengthI(32, Length + 1);
ResTy = Context.CharTy.withConst();
@@ -1642,6 +1678,8 @@ Sema::OwningExprResult Sema::ActOnCharacterConstant(const Token &Tok) {
Ty = Context.IntTy; // 'x' and L'x' -> int in C.
else if (Literal.isWide())
Ty = Context.WCharTy; // L'x' -> wchar_t in C++.
+ else if (Literal.isMultiChar())
+ Ty = Context.IntTy; // 'wxyz' -> int in C++.
else
Ty = Context.CharTy; // 'x' -> char in C++
@@ -2029,8 +2067,9 @@ Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc,
Expr *RHSExp = static_cast<Expr*>(Idx.get());
// Perform default conversions.
- DefaultFunctionArrayConversion(LHSExp);
- DefaultFunctionArrayConversion(RHSExp);
+ if (!LHSExp->getType()->getAs<VectorType>())
+ DefaultFunctionArrayLvalueConversion(LHSExp);
+ DefaultFunctionArrayLvalueConversion(RHSExp);
QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType();
@@ -2072,7 +2111,7 @@ Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc,
ResultType = VTy->getElementType();
} else if (LHSTy->isArrayType()) {
// If we see an array that wasn't promoted by
- // DefaultFunctionArrayConversion, it must be an array that
+ // DefaultFunctionArrayLvalueConversion, it must be an array that
// wasn't promoted because of the C90 rule that doesn't
// allow promoting non-lvalue arrays. Warn, then
// force the promotion here.
@@ -2542,7 +2581,11 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
bool Dependent =
BaseExprType->isDependentType() ||
R.isUnresolvableResult() ||
- UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), TemplateArgs);
+ OverloadExpr::ComputeDependence(R.begin(), R.end(), TemplateArgs);
+
+ // Suppress any lookup-related diagnostics; we'll do these when we
+ // pick a member.
+ R.suppressDiagnostics();
UnresolvedMemberExpr *MemExpr
= UnresolvedMemberExpr::Create(Context, Dependent,
@@ -2552,8 +2595,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
Qualifier, SS.getRange(),
MemberName, MemberLoc,
TemplateArgs);
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
- MemExpr->addDecl(*I);
+ MemExpr->addDecls(R.begin(), R.end());
return Owned(MemExpr);
}
@@ -3001,7 +3043,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
if (DiagnoseUseOfDecl(OMD, MemberLoc))
return ExprError();
- return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel,
+ return Owned(new (Context) ObjCMessageExpr(Context, BaseExpr, Sel,
OMD->getResultType(),
OMD, OpLoc, MemberLoc,
NULL, 0));
@@ -3248,7 +3290,8 @@ Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
Expr *UninstExpr = Param->getUninstantiatedDefaultArg();
// Instantiate the expression.
- MultiLevelTemplateArgumentList ArgList = getTemplateInstantiationArgs(FD);
+ MultiLevelTemplateArgumentList ArgList
+ = getTemplateInstantiationArgs(FD, 0, /*RelativeToPrimary=*/true);
InstantiatingTemplate Inst(*this, CallLoc, Param,
ArgList.getInnermost().getFlatArgumentList(),
@@ -3770,7 +3813,7 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, FunctionalStyle,
ConversionDecl);
- DefaultFunctionArrayConversion(castExpr);
+ DefaultFunctionArrayLvalueConversion(castExpr);
// C99 6.5.4p2: the cast type needs to be void or scalar and the expression
// type needs to be scalar.
@@ -4807,7 +4850,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
//
// Suppress this for references: C++ 8.5.3p5.
if (!lhsType->isReferenceType())
- DefaultFunctionArrayConversion(rExpr);
+ DefaultFunctionArrayLvalueConversion(rExpr);
Sema::AssignConvertType result =
CheckAssignmentConstraints(lhsType, rExpr->getType());
@@ -5690,6 +5733,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_SubObjCPropertySetting:
Diag = diag::error_no_subobject_property_setting;
break;
+ case Expr::MLV_SubObjCPropertyGetterSetting:
+ Diag = diag::error_no_subobject_property_getter_setting;
+ break;
}
SourceRange Assign;
@@ -5770,7 +5816,9 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS,
// C99 6.5.17
QualType Sema::CheckCommaOperands(Expr *LHS, Expr *&RHS, SourceLocation Loc) {
// Comma performs lvalue conversion (C99 6.3.2.1), but not unary conversions.
- DefaultFunctionArrayConversion(RHS);
+ // C++ does not perform this conversion (C++ [expr.comma]p1).
+ if (!getLangOptions().CPlusPlus)
+ DefaultFunctionArrayLvalueConversion(RHS);
// FIXME: Check that RHS type is complete in C mode (it's legal for it to be
// incomplete in C++).
@@ -5961,8 +6009,7 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
Diag(OpLoc, diag::err_typecheck_address_of)
<< "bit-field" << op->getSourceRange();
return QualType();
- } else if (isa<ExtVectorElementExpr>(op) || (isa<ArraySubscriptExpr>(op) &&
- cast<ArraySubscriptExpr>(op)->getBase()->getType()->isVectorType())){
+ } else if (op->refersToVectorElement()) {
// The operand cannot be an element of a vector
Diag(OpLoc, diag::err_typecheck_address_of)
<< "vector element" << op->getSourceRange();
@@ -6337,17 +6384,11 @@ Action::OwningExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
// point. We perform both an operator-name lookup from the local
// scope and an argument-dependent lookup based on the types of
// the arguments.
- FunctionSet Functions;
+ UnresolvedSet<16> Functions;
OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc);
- if (OverOp != OO_None) {
- if (S)
- LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
- Functions);
- Expr *Args[2] = { lhs, rhs };
- DeclarationName OpName
- = Context.DeclarationNames.getCXXOperatorName(OverOp);
- ArgumentDependentLookup(OpName, /*Operator*/true, Args, 2, Functions);
- }
+ if (S && OverOp != OO_None)
+ LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
+ Functions);
// Build the (potentially-overloaded, potentially-dependent)
// binary operation.
@@ -6383,7 +6424,7 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
resultType = CheckAddressOfOperand(Input, OpLoc);
break;
case UnaryOperator::Deref:
- DefaultFunctionArrayConversion(Input);
+ DefaultFunctionArrayLvalueConversion(Input);
resultType = CheckIndirectionOperand(Input, OpLoc);
break;
case UnaryOperator::Plus:
@@ -6420,7 +6461,7 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
break;
case UnaryOperator::LNot: // logical negation
// Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5).
- DefaultFunctionArrayConversion(Input);
+ DefaultFunctionArrayLvalueConversion(Input);
resultType = Input->getType();
if (resultType->isDependentType())
break;
@@ -6456,16 +6497,11 @@ Action::OwningExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
// point. We perform both an operator-name lookup from the local
// scope and an argument-dependent lookup based on the types of
// the arguments.
- FunctionSet Functions;
+ UnresolvedSet<16> Functions;
OverloadedOperatorKind OverOp = UnaryOperator::getOverloadedOperator(Opc);
- if (OverOp != OO_None) {
- if (S)
- LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(),
- Functions);
- DeclarationName OpName
- = Context.DeclarationNames.getCXXOperatorName(OverOp);
- ArgumentDependentLookup(OpName, /*Operator*/true, &Input, 1, Functions);
- }
+ if (S && OverOp != OO_None)
+ LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(),
+ Functions);
return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input));
}
@@ -6595,7 +6631,7 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
// Promote the array so it looks more like a normal array subscript
// expression.
- DefaultFunctionArrayConversion(Res);
+ DefaultFunctionArrayLvalueConversion(Res);
// C99 6.5.2.1p1
Expr *Idx = static_cast<Expr*>(OC.U.E);
@@ -6772,6 +6808,8 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
return;
}
+
+ CurBlock->ReturnType = RetTy;
return;
}
@@ -6792,11 +6830,18 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
// empty arg list, don't push any params.
CurBlock->isVariadic = false;
} else if (FTI.hasPrototype) {
- for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
- CurBlock->Params.push_back(FTI.ArgInfo[i].Param.getAs<ParmVarDecl>());
+ for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
+ ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>();
+ if (Param->getIdentifier() == 0 &&
+ !Param->isImplicit() &&
+ !Param->isInvalidDecl() &&
+ !getLangOptions().CPlusPlus)
+ Diag(Param->getLocation(), diag::err_parameter_name_omitted);
+ CurBlock->Params.push_back(Param);
+ }
CurBlock->isVariadic = FTI.isVariadic;
}
- CurBlock->TheDecl->setParams(Context, CurBlock->Params.data(),
+ CurBlock->TheDecl->setParams(CurBlock->Params.data(),
CurBlock->Params.size());
CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic);
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
@@ -7255,6 +7300,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
// FIXME: keep track of references to static functions
Function->setUsed(true);
+
return;
}
@@ -7390,7 +7436,7 @@ bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) {
DiagnoseAssignmentAsCondition(E);
if (!E->isTypeDependent()) {
- DefaultFunctionArrayConversion(E);
+ DefaultFunctionArrayLvalueConversion(E);
QualType T = E->getType();
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index b004fc3dba72..9eeda54299ae 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -72,18 +72,17 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
if (const RecordType *RecordT = T->getAs<RecordType>()) {
CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl());
// C++ [expr.typeid]p3:
+ // [...] If the type of the expression is a class type, the class
+ // shall be completely-defined.
+ if (RequireCompleteType(OpLoc, T, diag::err_incomplete_typeid))
+ return ExprError();
+
+ // C++ [expr.typeid]p3:
// When typeid is applied to an expression other than an lvalue of a
// polymorphic class type [...] [the] expression is an unevaluated
// operand. [...]
if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid)
isUnevaluatedOperand = false;
- else {
- // C++ [expr.typeid]p3:
- // [...] If the type of the expression is a class type, the class
- // shall be completely-defined.
- if (RequireCompleteType(OpLoc, T, diag::err_incomplete_typeid))
- return ExprError();
- }
}
// C++ [expr.typeid]p4:
@@ -195,7 +194,9 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
MultiExprArg exprs,
SourceLocation *CommaLocs,
SourceLocation RParenLoc) {
- assert(TypeRep && "Missing type!");
+ if (!TypeRep)
+ return ExprError();
+
TypeSourceInfo *TInfo;
QualType Ty = GetTypeFromParser(TypeRep, &TInfo);
if (!TInfo)
@@ -263,29 +264,18 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
if (NumExprs > 1 || !Record->hasTrivialConstructor() ||
!Record->hasTrivialDestructor()) {
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
-
- CXXConstructorDecl *Constructor
- = PerformInitializationByConstructor(Ty, move(exprs),
- TypeRange.getBegin(),
- SourceRange(TypeRange.getBegin(),
- RParenLoc),
- DeclarationName(),
- InitializationKind::CreateDirect(TypeRange.getBegin(),
- LParenLoc,
- RParenLoc),
- ConstructorArgs);
-
- if (!Constructor)
- return ExprError();
-
- OwningExprResult Result =
- BuildCXXTemporaryObjectExpr(Constructor, Ty, TyBeginLoc,
- move_arg(ConstructorArgs), RParenLoc);
- if (Result.isInvalid())
- return ExprError();
-
- return MaybeBindToTemporary(Result.takeAs<Expr>());
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(Ty);
+ InitializationKind Kind
+ = NumExprs ? InitializationKind::CreateDirect(TypeRange.getBegin(),
+ LParenLoc, RParenLoc)
+ : InitializationKind::CreateValue(TypeRange.getBegin(),
+ LParenLoc, RParenLoc);
+ InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs);
+ OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind,
+ move(exprs));
+
+ // FIXME: Improve AST representation?
+ return move(Result);
}
// Fall through to value-initialize an object of class type that
@@ -530,10 +520,13 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
PlacementArgs.release();
ConstructorArgs.release();
ArraySizeE.release();
- return Owned(new (Context) CXXNewExpr(UseGlobal, OperatorNew, PlaceArgs,
- NumPlaceArgs, ParenTypeId, ArraySize, Constructor, Init,
- ConsArgs, NumConsArgs, OperatorDelete, ResultType,
- StartLoc, Init ? ConstructorRParen : SourceLocation()));
+ return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew,
+ PlaceArgs, NumPlaceArgs, ParenTypeId,
+ ArraySize, Constructor, Init,
+ ConsArgs, NumConsArgs, OperatorDelete,
+ ResultType, StartLoc,
+ Init ? ConstructorRParen :
+ SourceLocation()));
}
/// CheckAllocatedType - Checks that a type is suitable as the allocated type
@@ -636,19 +629,24 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
// FIXME: handle ambiguity
- OverloadCandidateSet Candidates;
+ OverloadCandidateSet Candidates(StartLoc);
for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end();
Alloc != AllocEnd; ++Alloc) {
// Even member operator new/delete are implicitly treated as
// static, so don't use AddMemberCandidate.
- if (FunctionDecl *Fn =
- dyn_cast<FunctionDecl>((*Alloc)->getUnderlyingDecl())) {
- AddOverloadCandidate(Fn, Args, NumArgs, Candidates,
- /*SuppressUserConversions=*/false);
+
+ if (FunctionTemplateDecl *FnTemplate =
+ dyn_cast<FunctionTemplateDecl>((*Alloc)->getUnderlyingDecl())) {
+ AddTemplateOverloadCandidate(FnTemplate, Alloc.getAccess(),
+ /*ExplicitTemplateArgs=*/0, Args, NumArgs,
+ Candidates,
+ /*SuppressUserConversions=*/false);
continue;
- }
-
- // FIXME: Handle function templates
+ }
+
+ FunctionDecl *Fn = cast<FunctionDecl>((*Alloc)->getUnderlyingDecl());
+ AddOverloadCandidate(Fn, Alloc.getAccess(), Args, NumArgs, Candidates,
+ /*SuppressUserConversions=*/false);
}
// Do the resolution.
@@ -779,12 +777,16 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
DeclContext::lookup_iterator Alloc, AllocEnd;
for (llvm::tie(Alloc, AllocEnd) = GlobalCtx->lookup(Name);
Alloc != AllocEnd; ++Alloc) {
- // FIXME: Do we need to check for default arguments here?
- FunctionDecl *Func = cast<FunctionDecl>(*Alloc);
- if (Func->getNumParams() == 1 &&
+ // Only look at non-template functions, as it is the predefined,
+ // non-templated allocation function we are trying to declare here.
+ if (FunctionDecl *Func = dyn_cast<FunctionDecl>(*Alloc)) {
+ QualType InitialParamType =
Context.getCanonicalType(
- Func->getParamDecl(0)->getType().getUnqualifiedType()) == Argument)
- return;
+ Func->getParamDecl(0)->getType().getUnqualifiedType());
+ // FIXME: Do we need to check for default arguments here?
+ if (Func->getNumParams() == 1 && InitialParamType == Argument)
+ return;
+ }
}
}
@@ -812,7 +814,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
0, Argument, /*TInfo=*/0,
VarDecl::None, 0);
- Alloc->setParams(Context, &Param, 1);
+ Alloc->setParams(&Param, 1);
// FIXME: Also add this declaration to the IdentifierResolver, but
// make sure it is at the end of the chain to coincide with the
@@ -1487,9 +1489,9 @@ QualType Sema::CheckPointerToMemberOperands(
static QualType TargetType(const ImplicitConversionSequence &ICS) {
switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion:
- return ICS.Standard.getToType();
+ return ICS.Standard.getToType(2);
case ImplicitConversionSequence::UserDefinedConversion:
- return ICS.UserDefined.After.getToType();
+ return ICS.UserDefined.After.getToType(2);
case ImplicitConversionSequence::AmbiguousConversion:
return ICS.Ambiguous.getToType();
case ImplicitConversionSequence::EllipsisConversion:
@@ -1587,7 +1589,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
SourceLocation Loc) {
Expr *Args[2] = { LHS, RHS };
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(Loc);
Self.AddBuiltinOperatorCandidates(OO_Conditional, Loc, Args, 2, CandidateSet);
OverloadCandidateSet::iterator Best;
@@ -1689,8 +1691,8 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
if (LVoid || RVoid) {
// ... then the [l2r] conversions are performed on the second and third
// operands ...
- DefaultFunctionArrayConversion(LHS);
- DefaultFunctionArrayConversion(RHS);
+ DefaultFunctionArrayLvalueConversion(LHS);
+ DefaultFunctionArrayLvalueConversion(RHS);
LTy = LHS->getType();
RTy = RHS->getType();
@@ -1776,8 +1778,8 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// C++0x 5.16p6
// LValue-to-rvalue, array-to-pointer, and function-to-pointer standard
// conversions are performed on the second and third operands.
- DefaultFunctionArrayConversion(LHS);
- DefaultFunctionArrayConversion(RHS);
+ DefaultFunctionArrayLvalueConversion(LHS);
+ DefaultFunctionArrayLvalueConversion(RHS);
LTy = LHS->getType();
RTy = RHS->getType();
@@ -1987,10 +1989,8 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
if (!RT)
return Owned(E);
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialDestructor())
- return Owned(E);
-
+ // If this is the result of a call expression, our source might
+ // actually be a reference, in which case we shouldn't bind.
if (CallExpr *CE = dyn_cast<CallExpr>(E)) {
QualType Ty = CE->getCallee()->getType();
if (const PointerType *PT = Ty->getAs<PointerType>())
@@ -2000,6 +2000,13 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
if (FTy->getResultType()->isReferenceType())
return Owned(E);
}
+
+ // That should be enough to guarantee that this type is complete.
+ // If it has a trivial destructor, we can avoid the extra copy.
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (RD->hasTrivialDestructor())
+ return Owned(E);
+
CXXTemporary *Temp = CXXTemporary::Create(Context,
RD->getDestructor(Context));
ExprTemporaries.push_back(Temp);
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index ea8f4e3e890f..0c5d8efa288b 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -470,11 +470,13 @@ Sema::ExprResult Sema::ActOnClassMessage(
// now, we simply pass the "super" identifier through (which isn't consistent
// with instance methods.
if (isSuper)
- return new (Context) ObjCMessageExpr(receiverName, Sel, returnType, Method,
- lbrac, rbrac, ArgExprs, NumArgs);
+ return new (Context) ObjCMessageExpr(Context, receiverName, Sel, returnType,
+ Method, lbrac, rbrac, ArgExprs,
+ NumArgs);
else
- return new (Context) ObjCMessageExpr(ClassDecl, Sel, returnType, Method,
- lbrac, rbrac, ArgExprs, NumArgs);
+ return new (Context) ObjCMessageExpr(Context, ClassDecl, Sel, returnType,
+ Method, lbrac, rbrac, ArgExprs,
+ NumArgs);
}
// ActOnInstanceMessage - used for both unary and keyword messages.
@@ -492,7 +494,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
// If necessary, apply function/array conversion to the receiver.
// C99 6.7.5.3p[7,8].
- DefaultFunctionArrayConversion(RExpr);
+ DefaultFunctionArrayLvalueConversion(RExpr);
QualType returnType;
QualType ReceiverCType =
@@ -521,8 +523,9 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
return true;
returnType = returnType.getNonReferenceType();
- return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac,
- rbrac, ArgExprs, NumArgs);
+ return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType,
+ Method, lbrac, rbrac,
+ ArgExprs, NumArgs);
}
// Handle messages to id.
@@ -536,8 +539,9 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
lbrac, rbrac, returnType))
return true;
returnType = returnType.getNonReferenceType();
- return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac,
- rbrac, ArgExprs, NumArgs);
+ return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType,
+ Method, lbrac, rbrac,
+ ArgExprs, NumArgs);
}
// Handle messages to Class.
@@ -582,8 +586,9 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
lbrac, rbrac, returnType))
return true;
returnType = returnType.getNonReferenceType();
- return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac,
- rbrac, ArgExprs, NumArgs);
+ return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType,
+ Method, lbrac, rbrac,
+ ArgExprs, NumArgs);
}
ObjCMethodDecl *Method = 0;
@@ -665,7 +670,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
lbrac, rbrac, returnType))
return true;
returnType = returnType.getNonReferenceType();
- return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac,
- rbrac, ArgExprs, NumArgs);
+ return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType, Method,
+ lbrac, rbrac, ArgExprs, NumArgs);
}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index fd62e1afce4f..7b4a41777b6a 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -66,40 +66,6 @@ static Expr *IsStringInit(Expr *Init, QualType DeclType, ASTContext &Context) {
return 0;
}
-static bool CheckSingleInitializer(Expr *&Init, QualType DeclType,
- bool DirectInit, Sema &S) {
- // Get the type before calling CheckSingleAssignmentConstraints(), since
- // it can promote the expression.
- QualType InitType = Init->getType();
-
- if (S.getLangOptions().CPlusPlus) {
- // FIXME: I dislike this error message. A lot.
- if (S.PerformImplicitConversion(Init, DeclType,
- Sema::AA_Initializing, DirectInit)) {
- ImplicitConversionSequence ICS;
- OverloadCandidateSet CandidateSet;
- if (S.IsUserDefinedConversion(Init, DeclType, ICS.UserDefined,
- CandidateSet,
- true, false, false) != OR_Ambiguous)
- return S.Diag(Init->getSourceRange().getBegin(),
- diag::err_typecheck_convert_incompatible)
- << DeclType << Init->getType() << Sema::AA_Initializing
- << Init->getSourceRange();
- S.Diag(Init->getSourceRange().getBegin(),
- diag::err_typecheck_convert_ambiguous)
- << DeclType << Init->getType() << Init->getSourceRange();
- S.PrintOverloadCandidates(CandidateSet, Sema::OCD_AllCandidates, &Init, 1);
- return true;
- }
- return false;
- }
-
- Sema::AssignConvertType ConvTy =
- S.CheckSingleAssignmentConstraints(DeclType, Init);
- return S.DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType,
- InitType, Init, Sema::AA_Initializing);
-}
-
static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) {
// Get the length of the string as parsed.
uint64_t StrLength =
@@ -174,47 +140,57 @@ class InitListChecker {
std::map<InitListExpr *, InitListExpr *> SyntacticToSemantic;
InitListExpr *FullyStructuredList;
- void CheckImplicitInitList(InitListExpr *ParentIList, QualType T,
+ void CheckImplicitInitList(const InitializedEntity &Entity,
+ InitListExpr *ParentIList, QualType T,
unsigned &Index, InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject = false);
- void CheckExplicitInitList(InitListExpr *IList, QualType &T,
+ void CheckExplicitInitList(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType &T,
unsigned &Index, InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject = false);
- void CheckListElementTypes(InitListExpr *IList, QualType &DeclType,
+ void CheckListElementTypes(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType &DeclType,
bool SubobjectIsDesignatorContext,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject = false);
- void CheckSubElementType(InitListExpr *IList, QualType ElemType,
+ void CheckSubElementType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType ElemType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
- void CheckScalarType(InitListExpr *IList, QualType DeclType,
+ void CheckScalarType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
- void CheckReferenceType(InitListExpr *IList, QualType DeclType,
+ void CheckReferenceType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
- void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index,
+ void CheckVectorType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType DeclType, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
- void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType,
+ void CheckStructUnionTypes(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType DeclType,
RecordDecl::field_iterator Field,
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject = false);
- void CheckArrayType(InitListExpr *IList, QualType &DeclType,
+ void CheckArrayType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType &DeclType,
llvm::APSInt elementIndex,
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
- bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE,
+ bool CheckDesignatedInitializer(const InitializedEntity &Entity,
+ InitListExpr *IList, DesignatedInitExpr *DIE,
unsigned DesigIdx,
QualType &CurrentObjectType,
RecordDecl::field_iterator *NextField,
@@ -433,7 +409,8 @@ InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
unsigned newStructuredIndex = 0;
FullyStructuredList
= getStructuredSubobjectInit(IL, newIndex, T, 0, 0, IL->getSourceRange());
- CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex,
+ CheckExplicitInitList(Entity, IL, T, newIndex,
+ FullyStructuredList, newStructuredIndex,
/*TopLevelObject=*/true);
if (!hadError) {
@@ -470,7 +447,8 @@ int InitListChecker::numStructUnionElements(QualType DeclType) {
return InitializableMembers - structDecl->hasFlexibleArrayMember();
}
-void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
+void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
+ InitListExpr *ParentIList,
QualType T, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
@@ -504,7 +482,8 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
// Check the element types and build the structural subobject.
unsigned StartIndex = Index;
- CheckListElementTypes(ParentIList, T, false, Index,
+ CheckListElementTypes(Entity, ParentIList, T,
+ /*SubobjectIsDesignatorContext=*/false, Index,
StructuredSubobjectInitList,
StructuredSubobjectInitIndex,
TopLevelObject);
@@ -520,7 +499,8 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
}
}
-void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
+void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType &T,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
@@ -528,10 +508,10 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
assert(IList->isExplicit() && "Illegal Implicit InitListExpr");
SyntacticToSemantic[IList] = StructuredList;
StructuredList->setSyntacticForm(IList);
- CheckListElementTypes(IList, T, true, Index, StructuredList,
- StructuredIndex, TopLevelObject);
- IList->setType(T);
- StructuredList->setType(T);
+ CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true,
+ Index, StructuredList, StructuredIndex, TopLevelObject);
+ IList->setType(T.getNonReferenceType());
+ StructuredList->setType(T.getNonReferenceType());
if (hadError)
return;
@@ -580,7 +560,8 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
<< CodeModificationHint::CreateRemoval(IList->getLocEnd());
}
-void InitListChecker::CheckListElementTypes(InitListExpr *IList,
+void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
+ InitListExpr *IList,
QualType &DeclType,
bool SubobjectIsDesignatorContext,
unsigned &Index,
@@ -588,13 +569,15 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
unsigned &StructuredIndex,
bool TopLevelObject) {
if (DeclType->isScalarType()) {
- CheckScalarType(IList, DeclType, Index, StructuredList, StructuredIndex);
+ CheckScalarType(Entity, IList, DeclType, Index,
+ StructuredList, StructuredIndex);
} else if (DeclType->isVectorType()) {
- CheckVectorType(IList, DeclType, Index, StructuredList, StructuredIndex);
+ CheckVectorType(Entity, IList, DeclType, Index,
+ StructuredList, StructuredIndex);
} else if (DeclType->isAggregateType()) {
if (DeclType->isRecordType()) {
RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
- CheckStructUnionTypes(IList, DeclType, RD->field_begin(),
+ CheckStructUnionTypes(Entity, IList, DeclType, RD->field_begin(),
SubobjectIsDesignatorContext, Index,
StructuredList, StructuredIndex,
TopLevelObject);
@@ -602,7 +585,8 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
llvm::APSInt Zero(
SemaRef.Context.getTypeSize(SemaRef.Context.getSizeType()),
false);
- CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index,
+ CheckArrayType(Entity, IList, DeclType, Zero,
+ SubobjectIsDesignatorContext, Index,
StructuredList, StructuredIndex);
} else
assert(0 && "Aggregate that isn't a structure or array?!");
@@ -625,7 +609,8 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
<< DeclType << IList->getSourceRange();
hadError = true;
} else if (DeclType->isReferenceType()) {
- CheckReferenceType(IList, DeclType, Index, StructuredList, StructuredIndex);
+ CheckReferenceType(Entity, IList, DeclType, Index,
+ StructuredList, StructuredIndex);
} else {
// In C, all types are either scalars or aggregates, but
// additional handling is needed here for C++ (and possibly others?).
@@ -633,7 +618,8 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
}
}
-void InitListChecker::CheckSubElementType(InitListExpr *IList,
+void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
+ InitListExpr *IList,
QualType ElemType,
unsigned &Index,
InitListExpr *StructuredList,
@@ -646,7 +632,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
= getStructuredSubobjectInit(IList, Index, ElemType,
StructuredList, StructuredIndex,
SubInitList->getSourceRange());
- CheckExplicitInitList(SubInitList, ElemType, newIndex,
+ CheckExplicitInitList(Entity, SubInitList, ElemType, newIndex,
newStructuredList, newStructuredIndex);
++StructuredIndex;
++Index;
@@ -655,9 +641,11 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
UpdateStructuredListElement(StructuredList, StructuredIndex, Str);
++Index;
} else if (ElemType->isScalarType()) {
- CheckScalarType(IList, ElemType, Index, StructuredList, StructuredIndex);
+ CheckScalarType(Entity, IList, ElemType, Index,
+ StructuredList, StructuredIndex);
} else if (ElemType->isReferenceType()) {
- CheckReferenceType(IList, ElemType, Index, StructuredList, StructuredIndex);
+ CheckReferenceType(Entity, IList, ElemType, Index,
+ StructuredList, StructuredIndex);
} else {
if (SemaRef.getLangOptions().CPlusPlus) {
// C++ [dcl.init.aggr]p12:
@@ -665,17 +653,21 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
// initializing the aggregate member with an ini- tializer from
// an initializer-list. If the initializer can initialize a
// member, the member is initialized. [...]
- ImplicitConversionSequence ICS
- = SemaRef.TryCopyInitialization(expr, ElemType,
- /*SuppressUserConversions=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
-
- if (!ICS.isBad()) {
- if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS,
- Sema::AA_Initializing))
+
+ // FIXME: Better EqualLoc?
+ InitializationKind Kind =
+ InitializationKind::CreateCopy(expr->getLocStart(), SourceLocation());
+ InitializationSequence Seq(SemaRef, Entity, Kind, &expr, 1);
+
+ if (Seq) {
+ Sema::OwningExprResult Result =
+ Seq.Perform(SemaRef, Entity, Kind,
+ Sema::MultiExprArg(SemaRef, (void **)&expr, 1));
+ if (Result.isInvalid())
hadError = true;
- UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+
+ UpdateStructuredListElement(StructuredList, StructuredIndex,
+ Result.takeAs<Expr>());
++Index;
return;
}
@@ -707,13 +699,15 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
// considered for the initialization of the first member of
// the subaggregate.
if (ElemType->isAggregateType() || ElemType->isVectorType()) {
- CheckImplicitInitList(IList, ElemType, Index, StructuredList,
+ CheckImplicitInitList(Entity, IList, ElemType, Index, StructuredList,
StructuredIndex);
++StructuredIndex;
} else {
// We cannot initialize this element, so let
// PerformCopyInitialization produce the appropriate diagnostic.
- SemaRef.PerformCopyInitialization(expr, ElemType, Sema::AA_Initializing);
+ SemaRef.PerformCopyInitialization(Entity, SourceLocation(),
+ SemaRef.Owned(expr));
+ IList->setInit(Index, 0);
hadError = true;
++Index;
++StructuredIndex;
@@ -721,7 +715,8 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
}
}
-void InitListChecker::CheckScalarType(InitListExpr *IList, QualType DeclType,
+void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
@@ -745,17 +740,26 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType DeclType,
return;
}
- Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
- if (CheckSingleInitializer(expr, DeclType, false, SemaRef))
+ Sema::OwningExprResult Result =
+ SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(),
+ SemaRef.Owned(expr));
+
+ Expr *ResultExpr = 0;
+
+ if (Result.isInvalid())
hadError = true; // types weren't compatible.
- else if (savExpr != expr) {
- // The type was promoted, update initializer list.
- IList->setInit(Index, expr);
+ else {
+ ResultExpr = Result.takeAs<Expr>();
+
+ if (ResultExpr != expr) {
+ // The type was promoted, update initializer list.
+ IList->setInit(Index, ResultExpr);
+ }
}
if (hadError)
++StructuredIndex;
else
- UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+ UpdateStructuredListElement(StructuredList, StructuredIndex, ResultExpr);
++Index;
} else {
SemaRef.Diag(IList->getLocStart(), diag::err_empty_scalar_initializer)
@@ -767,7 +771,8 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType DeclType,
}
}
-void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType,
+void InitListChecker::CheckReferenceType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
@@ -782,17 +787,16 @@ void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType,
return;
}
- Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
- if (SemaRef.CheckReferenceInit(expr, DeclType,
- /*FIXME:*/expr->getLocStart(),
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false))
+ Sema::OwningExprResult Result =
+ SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(),
+ SemaRef.Owned(expr));
+
+ if (Result.isInvalid())
hadError = true;
- else if (savExpr != expr) {
- // The type was promoted, update initializer list.
- IList->setInit(Index, expr);
- }
+
+ expr = Result.takeAs<Expr>();
+ IList->setInit(Index, expr);
+
if (hadError)
++StructuredIndex;
else
@@ -814,7 +818,8 @@ void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType,
}
}
-void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
+void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
@@ -825,22 +830,33 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
QualType elementType = VT->getElementType();
if (!SemaRef.getLangOptions().OpenCL) {
+ InitializedEntity ElementEntity =
+ InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity);
+
for (unsigned i = 0; i < maxElements; ++i, ++numEltsInit) {
// Don't attempt to go past the end of the init list
if (Index >= IList->getNumInits())
break;
- CheckSubElementType(IList, elementType, Index,
+
+ ElementEntity.setElementIndex(Index);
+ CheckSubElementType(ElementEntity, IList, elementType, Index,
StructuredList, StructuredIndex);
}
} else {
+ InitializedEntity ElementEntity =
+ InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity);
+
// OpenCL initializers allows vectors to be constructed from vectors.
for (unsigned i = 0; i < maxElements; ++i) {
// Don't attempt to go past the end of the init list
if (Index >= IList->getNumInits())
break;
+
+ ElementEntity.setElementIndex(Index);
+
QualType IType = IList->getInit(Index)->getType();
if (!IType->isVectorType()) {
- CheckSubElementType(IList, elementType, Index,
+ CheckSubElementType(ElementEntity, IList, elementType, Index,
StructuredList, StructuredIndex);
++numEltsInit;
} else {
@@ -848,7 +864,7 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
unsigned numIElts = IVT->getNumElements();
QualType VecType = SemaRef.Context.getExtVectorType(elementType,
numIElts);
- CheckSubElementType(IList, VecType, Index,
+ CheckSubElementType(ElementEntity, IList, VecType, Index,
StructuredList, StructuredIndex);
numEltsInit += numIElts;
}
@@ -864,7 +880,8 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
}
}
-void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
+void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType &DeclType,
llvm::APSInt elementIndex,
bool SubobjectIsDesignatorContext,
unsigned &Index,
@@ -925,7 +942,7 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
// Handle this designated initializer. elementIndex will be
// updated to be the next array element we'll initialize.
- if (CheckDesignatedInitializer(IList, DIE, 0,
+ if (CheckDesignatedInitializer(Entity, IList, DIE, 0,
DeclType, 0, &elementIndex, Index,
StructuredList, StructuredIndex, true,
false)) {
@@ -952,8 +969,11 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
if (maxElementsKnown && elementIndex == maxElements)
break;
+ InitializedEntity ElementEntity =
+ InitializedEntity::InitializeElement(SemaRef.Context, StructuredIndex,
+ Entity);
// Check this element.
- CheckSubElementType(IList, elementType, Index,
+ CheckSubElementType(ElementEntity, IList, elementType, Index,
StructuredList, StructuredIndex);
++elementIndex;
@@ -978,7 +998,8 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
}
}
-void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
+void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
+ InitListExpr *IList,
QualType DeclType,
RecordDecl::field_iterator Field,
bool SubobjectIsDesignatorContext,
@@ -1027,7 +1048,7 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
// Handle this designated initializer. Field will be updated to
// the next field that we'll be initializing.
- if (CheckDesignatedInitializer(IList, DIE, 0,
+ if (CheckDesignatedInitializer(Entity, IList, DIE, 0,
DeclType, &Field, 0, Index,
StructuredList, StructuredIndex,
true, TopLevelObject))
@@ -1056,7 +1077,9 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
continue;
}
- CheckSubElementType(IList, Field->getType(), Index,
+ InitializedEntity MemberEntity =
+ InitializedEntity::InitializeMember(*Field, &Entity);
+ CheckSubElementType(MemberEntity, IList, Field->getType(), Index,
StructuredList, StructuredIndex);
InitializedSomething = true;
@@ -1092,12 +1115,15 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
<< *Field;
}
+ InitializedEntity MemberEntity =
+ InitializedEntity::InitializeMember(*Field, &Entity);
+
if (isa<InitListExpr>(IList->getInit(Index)))
- CheckSubElementType(IList, Field->getType(), Index, StructuredList,
- StructuredIndex);
+ CheckSubElementType(MemberEntity, IList, Field->getType(), Index,
+ StructuredList, StructuredIndex);
else
- CheckImplicitInitList(IList, Field->getType(), Index, StructuredList,
- StructuredIndex);
+ CheckImplicitInitList(MemberEntity, IList, Field->getType(), Index,
+ StructuredList, StructuredIndex);
}
/// \brief Expand a field designator that refers to a member of an
@@ -1194,7 +1220,8 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
///
/// @returns true if there was an error, false otherwise.
bool
-InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
+InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
+ InitListExpr *IList,
DesignatedInitExpr *DIE,
unsigned DesigIdx,
QualType &CurrentObjectType,
@@ -1215,7 +1242,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
unsigned OldIndex = Index;
IList->setInit(OldIndex, DIE->getInit());
- CheckSubElementType(IList, CurrentObjectType, Index,
+ CheckSubElementType(Entity, IList, CurrentObjectType, Index,
StructuredList, StructuredIndex);
// Restore the designated initializer expression in the syntactic
@@ -1423,8 +1450,12 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
unsigned newStructuredIndex = FieldIndex;
unsigned OldIndex = Index;
IList->setInit(Index, DIE->getInit());
- CheckSubElementType(IList, Field->getType(), Index,
+
+ InitializedEntity MemberEntity =
+ InitializedEntity::InitializeMember(*Field, &Entity);
+ CheckSubElementType(MemberEntity, IList, Field->getType(), Index,
StructuredList, newStructuredIndex);
+
IList->setInit(OldIndex, DIE);
if (hadError && !prevHadError) {
++Field;
@@ -1438,8 +1469,12 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
// Recurse to check later designated subobjects.
QualType FieldType = (*Field)->getType();
unsigned newStructuredIndex = FieldIndex;
- if (CheckDesignatedInitializer(IList, DIE, DesigIdx + 1, FieldType, 0, 0,
- Index, StructuredList, newStructuredIndex,
+
+ InitializedEntity MemberEntity =
+ InitializedEntity::InitializeMember(*Field, &Entity);
+ if (CheckDesignatedInitializer(MemberEntity, IList, DIE, DesigIdx + 1,
+ FieldType, 0, 0, Index,
+ StructuredList, newStructuredIndex,
true, false))
return true;
}
@@ -1467,7 +1502,8 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
// Check the remaining fields within this class/struct/union subobject.
bool prevHadError = hadError;
- CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index,
+
+ CheckStructUnionTypes(Entity, IList, CurrentObjectType, Field, false, Index,
StructuredList, FieldIndex);
return hadError && !prevHadError;
}
@@ -1552,12 +1588,19 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
// Move to the next designator
unsigned ElementIndex = DesignatedStartIndex.getZExtValue();
unsigned OldIndex = Index;
+
+ InitializedEntity ElementEntity =
+ InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity);
+
while (DesignatedStartIndex <= DesignatedEndIndex) {
// Recurse to check later designated subobjects.
QualType ElementType = AT->getElementType();
Index = OldIndex;
- if (CheckDesignatedInitializer(IList, DIE, DesigIdx + 1, ElementType, 0, 0,
- Index, StructuredList, ElementIndex,
+
+ ElementEntity.setElementIndex(ElementIndex);
+ if (CheckDesignatedInitializer(ElementEntity, IList, DIE, DesigIdx + 1,
+ ElementType, 0, 0, Index,
+ StructuredList, ElementIndex,
(DesignatedStartIndex == DesignatedEndIndex),
false))
return true;
@@ -1581,7 +1624,8 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
// Check the remaining elements within this array subobject.
bool prevHadError = hadError;
- CheckArrayType(IList, CurrentObjectType, DesignatedStartIndex, false, Index,
+ CheckArrayType(Entity, IList, CurrentObjectType, DesignatedStartIndex,
+ /*SubobjectIsDesignatorContext=*/false, Index,
StructuredList, ElementIndex);
return hadError && !prevHadError;
}
@@ -1628,7 +1672,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
= new (SemaRef.Context) InitListExpr(InitRange.getBegin(), 0, 0,
InitRange.getEnd());
- Result->setType(CurrentObjectType);
+ Result->setType(CurrentObjectType.getNonReferenceType());
// Pre-allocate storage for the structured initializer list.
unsigned NumElements = 0;
@@ -1927,7 +1971,8 @@ void InitializationSequence::AddAddressOverloadResolutionStep(
Step S;
S.Kind = SK_ResolveAddressOfOverloadedFunction;
S.Type = Function->getType();
- S.Function = Function;
+ // Access is currently ignored for these.
+ S.Function = DeclAccessPair::make(Function, AccessSpecifier(0));
Steps.push_back(S);
}
@@ -1948,11 +1993,12 @@ void InitializationSequence::AddReferenceBindingStep(QualType T,
}
void InitializationSequence::AddUserConversionStep(FunctionDecl *Function,
+ AccessSpecifier Access,
QualType T) {
Step S;
S.Kind = SK_UserConversion;
S.Type = T;
- S.Function = Function;
+ S.Function = DeclAccessPair::make(Function, Access);
Steps.push_back(S);
}
@@ -1985,11 +2031,12 @@ void InitializationSequence::AddListInitializationStep(QualType T) {
void
InitializationSequence::AddConstructorInitializationStep(
CXXConstructorDecl *Constructor,
+ AccessSpecifier Access,
QualType T) {
Step S;
S.Kind = SK_ConstructorInitialization;
S.Type = T;
- S.Function = Constructor;
+ S.Function = DeclAccessPair::make(Constructor, Access);
Steps.push_back(S);
}
@@ -2129,10 +2176,13 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
if (!Constructor->isInvalidDecl() &&
Constructor->isConvertingConstructor(AllowExplicit)) {
if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0,
+ S.AddTemplateOverloadCandidate(ConstructorTmpl,
+ ConstructorTmpl->getAccess(),
+ /*ExplicitArgs*/ 0,
&Initializer, 1, CandidateSet);
else
- S.AddOverloadCandidate(Constructor, &Initializer, 1, CandidateSet);
+ S.AddOverloadCandidate(Constructor, Constructor->getAccess(),
+ &Initializer, 1, CandidateSet);
}
}
}
@@ -2172,11 +2222,12 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
if ((AllowExplicit || !Conv->isExplicit()) &&
(AllowRValues || Conv->getConversionType()->isLValueReferenceType())){
if (ConvTemplate)
- S.AddTemplateConversionCandidate(ConvTemplate, ActingDC, Initializer,
+ S.AddTemplateConversionCandidate(ConvTemplate, I.getAccess(),
+ ActingDC, Initializer,
ToType, CandidateSet);
else
- S.AddConversionCandidate(Conv, ActingDC, Initializer, cv1T1,
- CandidateSet);
+ S.AddConversionCandidate(Conv, I.getAccess(), ActingDC,
+ Initializer, cv1T1, CandidateSet);
}
}
}
@@ -2198,7 +2249,8 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
T2 = cv1T1;
// Add the user-defined conversion step.
- Sequence.AddUserConversionStep(Function, T2.getNonReferenceType());
+ Sequence.AddUserConversionStep(Function, Best->getAccess(),
+ T2.getNonReferenceType());
// Determine whether we need to perform derived-to-base or
// cv-qualification adjustments.
@@ -2281,16 +2333,20 @@ static void TryReferenceInitialization(Sema &S,
// - is an lvalue (but is not a bit-field), and "cv1 T1" is
// reference-compatible with "cv2 T2," or
//
- // Per C++ [over.best.ics]p2, we ignore whether the lvalue is a
+ // Per C++ [over.best.ics]p2, we don't diagnose whether the lvalue is a
// bit-field when we're determining whether the reference initialization
- // can occur. This property will be checked by PerformInitialization.
+ // can occur. However, we do pay attention to whether it is a bit-field
+ // to decide whether we're actually binding to a temporary created from
+ // the bit-field.
if (DerivedToBase)
Sequence.AddDerivedToBaseCastStep(
S.Context.getQualifiedType(T1, T2Quals),
/*isLValue=*/true);
if (T1Quals != T2Quals)
Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/true);
- Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/false);
+ bool BindingTemporary = T1Quals.hasConst() && !T1Quals.hasVolatile() &&
+ (Initializer->getBitField() || Initializer->refersToVectorElement());
+ Sequence.AddReferenceBindingStep(cv1T1, BindingTemporary);
return;
}
@@ -2319,7 +2375,7 @@ static void TryReferenceInitialization(Sema &S,
// non-volatile const type (i.e., cv1 shall be const), or the reference
// shall be an rvalue reference and the initializer expression shall
// be an rvalue.
- if (!((isLValueRef && T1Quals.hasConst()) ||
+ if (!((isLValueRef && T1Quals.hasConst() && !T1Quals.hasVolatile()) ||
(isRValueRef && InitLvalue != Expr::LV_Valid))) {
if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty())
Sequence.SetOverloadFailure(
@@ -2489,10 +2545,13 @@ static void TryConstructorInitialization(Sema &S,
if (!Constructor->isInvalidDecl() &&
(AllowExplicit || !Constructor->isExplicit())) {
if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0,
+ S.AddTemplateOverloadCandidate(ConstructorTmpl,
+ ConstructorTmpl->getAccess(),
+ /*ExplicitArgs*/ 0,
Args, NumArgs, CandidateSet);
else
- S.AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
+ S.AddOverloadCandidate(Constructor, Constructor->getAccess(),
+ Args, NumArgs, CandidateSet);
}
}
@@ -2507,14 +2566,26 @@ static void TryConstructorInitialization(Sema &S,
Result);
return;
}
-
+
+ // C++0x [dcl.init]p6:
+ // If a program calls for the default initialization of an object
+ // of a const-qualified type T, T shall be a class type with a
+ // user-provided default constructor.
+ if (Kind.getKind() == InitializationKind::IK_Default &&
+ Entity.getType().isConstQualified() &&
+ cast<CXXConstructorDecl>(Best->Function)->isImplicit()) {
+ Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
+ return;
+ }
+
// Add the constructor initialization step. Any cv-qualification conversion is
// subsumed by the initialization.
if (Kind.getKind() == InitializationKind::IK_Copy) {
- Sequence.AddUserConversionStep(Best->Function, DestType);
+ Sequence.AddUserConversionStep(Best->Function, Best->getAccess(), DestType);
} else {
Sequence.AddConstructorInitializationStep(
cast<CXXConstructorDecl>(Best->Function),
+ Best->getAccess(),
DestType);
}
}
@@ -2579,10 +2650,7 @@ static void TryDefaultInitialization(Sema &S,
// - if T is a (possibly cv-qualified) class type (Clause 9), the default
// constructor for T is called (and the initialization is ill-formed if
// T has no accessible default constructor);
- if (DestType->isRecordType()) {
- // FIXME: If a program calls for the default initialization of an object of
- // a const-qualified type T, T shall be a class type with a user-provided
- // default constructor.
+ if (DestType->isRecordType() && S.getLangOptions().CPlusPlus) {
return TryConstructorInitialization(S, Entity, Kind, 0, 0, DestType,
Sequence);
}
@@ -2593,7 +2661,7 @@ static void TryDefaultInitialization(Sema &S,
// If a program calls for the default initialization of an object of
// a const-qualified type T, T shall be a class type with a user-provided
// default constructor.
- if (DestType.isConstQualified())
+ if (DestType.isConstQualified() && S.getLangOptions().CPlusPlus)
Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
}
@@ -2647,10 +2715,13 @@ static void TryUserDefinedConversion(Sema &S,
if (!Constructor->isInvalidDecl() &&
Constructor->isConvertingConstructor(AllowExplicit)) {
if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0,
+ S.AddTemplateOverloadCandidate(ConstructorTmpl,
+ ConstructorTmpl->getAccess(),
+ /*ExplicitArgs*/ 0,
&Initializer, 1, CandidateSet);
else
- S.AddOverloadCandidate(Constructor, &Initializer, 1, CandidateSet);
+ S.AddOverloadCandidate(Constructor, Constructor->getAccess(),
+ &Initializer, 1, CandidateSet);
}
}
}
@@ -2686,12 +2757,12 @@ static void TryUserDefinedConversion(Sema &S,
if (AllowExplicit || !Conv->isExplicit()) {
if (ConvTemplate)
- S.AddTemplateConversionCandidate(ConvTemplate, ActingDC,
- Initializer, DestType,
+ S.AddTemplateConversionCandidate(ConvTemplate, I.getAccess(),
+ ActingDC, Initializer, DestType,
CandidateSet);
else
- S.AddConversionCandidate(Conv, ActingDC, Initializer, DestType,
- CandidateSet);
+ S.AddConversionCandidate(Conv, I.getAccess(), ActingDC,
+ Initializer, DestType, CandidateSet);
}
}
}
@@ -2712,13 +2783,13 @@ static void TryUserDefinedConversion(Sema &S,
if (isa<CXXConstructorDecl>(Function)) {
// Add the user-defined conversion step. Any cv-qualification conversion is
// subsumed by the initialization.
- Sequence.AddUserConversionStep(Function, DestType);
+ Sequence.AddUserConversionStep(Function, Best->getAccess(), DestType);
return;
}
// Add the user-defined conversion step that calls the conversion function.
QualType ConvType = Function->getResultType().getNonReferenceType();
- Sequence.AddUserConversionStep(Function, ConvType);
+ Sequence.AddUserConversionStep(Function, Best->getAccess(), ConvType);
// If the conversion following the call to the conversion function is
// interesting, add it as a separate step.
@@ -2758,7 +2829,8 @@ InitializationSequence::InitializationSequence(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
Expr **Args,
- unsigned NumArgs) {
+ unsigned NumArgs)
+ : FailedCandidateSet(Kind.getLocation()) {
ASTContext &Context = S.Context;
// C++0x [dcl.init]p16:
@@ -2934,15 +3006,15 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity,
bool IsCopy) {
switch (Entity.getKind()) {
case InitializedEntity::EK_Result:
- case InitializedEntity::EK_Exception:
+ case InitializedEntity::EK_ArrayElement:
+ case InitializedEntity::EK_Member:
return !IsCopy;
case InitializedEntity::EK_New:
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_Base:
- case InitializedEntity::EK_Member:
- case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_VectorElement:
+ case InitializedEntity::EK_Exception:
return false;
case InitializedEntity::EK_Parameter:
@@ -2960,6 +3032,8 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
Sema::OwningExprResult CurInit) {
+ Expr *CurInitExpr = (Expr *)CurInit.get();
+
SourceLocation Loc;
switch (Entity.getKind()) {
@@ -2980,6 +3054,14 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
Loc = Entity.getDecl()->getLocation();
break;
+ case InitializedEntity::EK_ArrayElement:
+ case InitializedEntity::EK_Member:
+ if (Entity.getType()->isReferenceType() ||
+ Kind.getKind() != InitializationKind::IK_Copy)
+ return move(CurInit);
+ Loc = CurInitExpr->getLocStart();
+ break;
+
case InitializedEntity::EK_Parameter:
// FIXME: Do we need this initialization for a parameter?
return move(CurInit);
@@ -2987,14 +3069,11 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
case InitializedEntity::EK_New:
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_Base:
- case InitializedEntity::EK_Member:
- case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_VectorElement:
// We don't need to copy for any of these initialized entities.
return move(CurInit);
}
- Expr *CurInitExpr = (Expr *)CurInit.get();
CXXRecordDecl *Class = 0;
if (const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>())
Class = cast<CXXRecordDecl>(Record->getDecl());
@@ -3006,7 +3085,7 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
= S.Context.DeclarationNames.getCXXConstructorName(
S.Context.getCanonicalType(S.Context.getTypeDeclType(Class)));
DeclContext::lookup_iterator Con, ConEnd;
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(Loc);
for (llvm::tie(Con, ConEnd) = Class->lookup(ConstructorName);
Con != ConEnd; ++Con) {
// Find the constructor (which may be a template).
@@ -3015,7 +3094,8 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
!Constructor->isCopyConstructor())
continue;
- S.AddOverloadCandidate(Constructor, &CurInitExpr, 1, CandidateSet);
+ S.AddOverloadCandidate(Constructor, Constructor->getAccess(),
+ &CurInitExpr, 1, CandidateSet);
}
OverloadCandidateSet::iterator Best;
@@ -3111,6 +3191,9 @@ InitializationSequence::Perform(Sema &S,
if (Kind.getKind() == InitializationKind::IK_Copy || Kind.isExplicitCast())
return Sema::OwningExprResult(S, Args.release()[0]);
+ if (Args.size() == 0)
+ return S.Owned((Expr *)0);
+
unsigned NumArgs = Args.size();
return S.Owned(new (S.Context) ParenListExpr(S.Context,
SourceLocation(),
@@ -3176,7 +3259,9 @@ InitializationSequence::Perform(Sema &S,
case SK_ResolveAddressOfOverloadedFunction:
// Overload resolution determined which function invoke; update the
// initializer to reflect that choice.
- CurInit = S.FixOverloadedFunctionReference(move(CurInit), Step->Function);
+ // Access control was done in overload resolution.
+ CurInit = S.FixOverloadedFunctionReference(move(CurInit),
+ cast<FunctionDecl>(Step->Function.getDecl()));
break;
case SK_CastDerivedToBaseRValue:
@@ -3209,21 +3294,30 @@ InitializationSequence::Perform(Sema &S,
S.Diag(BitField->getLocation(), diag::note_bitfield_decl);
return S.ExprError();
}
+
+ if (CurInitExpr->refersToVectorElement()) {
+ // References cannot bind to vector elements.
+ S.Diag(Kind.getLocation(), diag::err_reference_bind_to_vector_element)
+ << Entity.getType().isVolatileQualified()
+ << CurInitExpr->getSourceRange();
+ return S.ExprError();
+ }
// Reference binding does not have any corresponding ASTs.
// Check exception specifications
if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType))
return S.ExprError();
+
break;
-
+
case SK_BindReferenceToTemporary:
+ // Reference binding does not have any corresponding ASTs.
+
// Check exception specifications
if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType))
return S.ExprError();
- // FIXME: At present, we have no AST to describe when we need to make a
- // temporary to bind a reference to. We should.
break;
case SK_UserConversion: {
@@ -3231,13 +3325,14 @@ InitializationSequence::Perform(Sema &S,
// or a conversion function.
CastExpr::CastKind CastKind = CastExpr::CK_Unknown;
bool IsCopy = false;
- if (CXXConstructorDecl *Constructor
- = dyn_cast<CXXConstructorDecl>(Step->Function)) {
+ FunctionDecl *Fn = cast<FunctionDecl>(Step->Function.getDecl());
+ AccessSpecifier FnAccess = Step->Function.getAccess();
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) {
// Build a call to the selected constructor.
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
SourceLocation Loc = CurInitExpr->getLocStart();
CurInit.release(); // Ownership transferred into MultiExprArg, below.
-
+
// Determine the arguments required to actually perform the constructor
// call.
if (S.CompleteConstructorCall(Constructor,
@@ -3252,6 +3347,8 @@ InitializationSequence::Perform(Sema &S,
move_arg(ConstructorArgs));
if (CurInit.isInvalid())
return S.ExprError();
+
+ S.CheckConstructorAccess(Kind.getLocation(), Constructor, FnAccess);
CastKind = CastExpr::CK_ConstructorConversion;
QualType Class = S.Context.getTypeDeclType(Constructor->getParent());
@@ -3260,8 +3357,11 @@ InitializationSequence::Perform(Sema &S,
IsCopy = true;
} else {
// Build a call to the conversion function.
- CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Step->Function);
+ CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn);
+ S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr,
+ Conversion, FnAccess);
+
// FIXME: Should we move this initialization into a separate
// derived-to-base conversion? I believe the answer is "no", because
// we don't want to turn off access control here for c-style casts.
@@ -3326,8 +3426,8 @@ InitializationSequence::Perform(Sema &S,
case SK_ConstructorInitialization: {
CXXConstructorDecl *Constructor
- = cast<CXXConstructorDecl>(Step->Function);
-
+ = cast<CXXConstructorDecl>(Step->Function.getDecl());
+
// Build a call to the selected constructor.
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
SourceLocation Loc = Kind.getLocation();
@@ -3342,9 +3442,13 @@ InitializationSequence::Perform(Sema &S,
CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
Constructor,
move_arg(ConstructorArgs),
- ConstructorInitRequiresZeroInit);
+ ConstructorInitRequiresZeroInit,
+ Entity.getKind() == InitializedEntity::EK_Base);
if (CurInit.isInvalid())
return S.ExprError();
+
+ // Only check access if all of that succeeded.
+ S.CheckConstructorAccess(Loc, Constructor, Step->Function.getAccess());
bool Elidable
= cast<CXXConstructExpr>((Expr *)CurInit.get())->isElidable();
@@ -3422,8 +3526,13 @@ bool InitializationSequence::Diagnose(Sema &S,
QualType DestType = Entity.getType();
switch (Failure) {
case FK_TooManyInitsForReference:
- S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits)
- << SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd());
+ // FIXME: Customize for the initialized entity?
+ if (NumArgs == 0)
+ S.Diag(Kind.getLocation(), diag::err_reference_without_init)
+ << DestType.getNonReferenceType();
+ else // FIXME: diagnostic below could be better!
+ S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits)
+ << SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd());
break;
case FK_ArrayNeedsInitList:
@@ -3492,6 +3601,7 @@ bool InitializationSequence::Diagnose(Sema &S,
Failure == FK_NonConstLValueReferenceBindingToTemporary
? diag::err_lvalue_reference_bind_to_temporary
: diag::err_lvalue_reference_bind_to_unrelated)
+ << DestType.getNonReferenceType().isVolatileQualified()
<< DestType.getNonReferenceType()
<< Args[0]->getType()
<< Args[0]->getSourceRange();
@@ -3567,6 +3677,45 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
case OR_No_Viable_Function:
+ if (Kind.getKind() == InitializationKind::IK_Default &&
+ (Entity.getKind() == InitializedEntity::EK_Base ||
+ Entity.getKind() == InitializedEntity::EK_Member) &&
+ isa<CXXConstructorDecl>(S.CurContext)) {
+ // This is implicit default initialization of a member or
+ // base within a constructor. If no viable function was
+ // found, notify the user that she needs to explicitly
+ // initialize this base/member.
+ CXXConstructorDecl *Constructor
+ = cast<CXXConstructorDecl>(S.CurContext);
+ if (Entity.getKind() == InitializedEntity::EK_Base) {
+ S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
+ << Constructor->isImplicit()
+ << S.Context.getTypeDeclType(Constructor->getParent())
+ << /*base=*/0
+ << Entity.getType();
+
+ RecordDecl *BaseDecl
+ = Entity.getBaseSpecifier()->getType()->getAs<RecordType>()
+ ->getDecl();
+ S.Diag(BaseDecl->getLocation(), diag::note_previous_decl)
+ << S.Context.getTagDeclType(BaseDecl);
+ } else {
+ S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
+ << Constructor->isImplicit()
+ << S.Context.getTypeDeclType(Constructor->getParent())
+ << /*member=*/1
+ << Entity.getName();
+ S.Diag(Entity.getDecl()->getLocation(), diag::note_field_decl);
+
+ if (const RecordType *Record
+ = Entity.getType()->getAs<RecordType>())
+ S.Diag(Record->getDecl()->getLocation(),
+ diag::note_previous_decl)
+ << S.Context.getTagDeclType(Record->getDecl());
+ }
+ break;
+ }
+
S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init)
<< DestType << ArgsRange;
S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_AllCandidates,
@@ -3597,14 +3746,217 @@ bool InitializationSequence::Diagnose(Sema &S,
}
case FK_DefaultInitOfConst:
- S.Diag(Kind.getLocation(), diag::err_default_init_const)
- << DestType;
+ if (Entity.getKind() == InitializedEntity::EK_Member &&
+ isa<CXXConstructorDecl>(S.CurContext)) {
+ // This is implicit default-initialization of a const member in
+ // a constructor. Complain that it needs to be explicitly
+ // initialized.
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(S.CurContext);
+ S.Diag(Kind.getLocation(), diag::err_uninitialized_member_in_ctor)
+ << Constructor->isImplicit()
+ << S.Context.getTypeDeclType(Constructor->getParent())
+ << /*const=*/1
+ << Entity.getName();
+ S.Diag(Entity.getDecl()->getLocation(), diag::note_previous_decl)
+ << Entity.getName();
+ } else {
+ S.Diag(Kind.getLocation(), diag::err_default_init_const)
+ << DestType << (bool)DestType->getAs<RecordType>();
+ }
break;
}
return true;
}
+void InitializationSequence::dump(llvm::raw_ostream &OS) const {
+ switch (SequenceKind) {
+ case FailedSequence: {
+ OS << "Failed sequence: ";
+ switch (Failure) {
+ case FK_TooManyInitsForReference:
+ OS << "too many initializers for reference";
+ break;
+
+ case FK_ArrayNeedsInitList:
+ OS << "array requires initializer list";
+ break;
+
+ case FK_ArrayNeedsInitListOrStringLiteral:
+ OS << "array requires initializer list or string literal";
+ break;
+
+ case FK_AddressOfOverloadFailed:
+ OS << "address of overloaded function failed";
+ break;
+
+ case FK_ReferenceInitOverloadFailed:
+ OS << "overload resolution for reference initialization failed";
+ break;
+
+ case FK_NonConstLValueReferenceBindingToTemporary:
+ OS << "non-const lvalue reference bound to temporary";
+ break;
+
+ case FK_NonConstLValueReferenceBindingToUnrelated:
+ OS << "non-const lvalue reference bound to unrelated type";
+ break;
+
+ case FK_RValueReferenceBindingToLValue:
+ OS << "rvalue reference bound to an lvalue";
+ break;
+
+ case FK_ReferenceInitDropsQualifiers:
+ OS << "reference initialization drops qualifiers";
+ break;
+
+ case FK_ReferenceInitFailed:
+ OS << "reference initialization failed";
+ break;
+
+ case FK_ConversionFailed:
+ OS << "conversion failed";
+ break;
+
+ case FK_TooManyInitsForScalar:
+ OS << "too many initializers for scalar";
+ break;
+
+ case FK_ReferenceBindingToInitList:
+ OS << "referencing binding to initializer list";
+ break;
+
+ case FK_InitListBadDestinationType:
+ OS << "initializer list for non-aggregate, non-scalar type";
+ break;
+
+ case FK_UserConversionOverloadFailed:
+ OS << "overloading failed for user-defined conversion";
+ break;
+
+ case FK_ConstructorOverloadFailed:
+ OS << "constructor overloading failed";
+ break;
+
+ case FK_DefaultInitOfConst:
+ OS << "default initialization of a const variable";
+ break;
+ }
+ OS << '\n';
+ return;
+ }
+
+ case DependentSequence:
+ OS << "Dependent sequence: ";
+ return;
+
+ case UserDefinedConversion:
+ OS << "User-defined conversion sequence: ";
+ break;
+
+ case ConstructorInitialization:
+ OS << "Constructor initialization sequence: ";
+ break;
+
+ case ReferenceBinding:
+ OS << "Reference binding: ";
+ break;
+
+ case ListInitialization:
+ OS << "List initialization: ";
+ break;
+
+ case ZeroInitialization:
+ OS << "Zero initialization\n";
+ return;
+
+ case NoInitialization:
+ OS << "No initialization\n";
+ return;
+
+ case StandardConversion:
+ OS << "Standard conversion: ";
+ break;
+
+ case CAssignment:
+ OS << "C assignment: ";
+ break;
+
+ case StringInit:
+ OS << "String initialization: ";
+ break;
+ }
+
+ for (step_iterator S = step_begin(), SEnd = step_end(); S != SEnd; ++S) {
+ if (S != step_begin()) {
+ OS << " -> ";
+ }
+
+ switch (S->Kind) {
+ case SK_ResolveAddressOfOverloadedFunction:
+ OS << "resolve address of overloaded function";
+ break;
+
+ case SK_CastDerivedToBaseRValue:
+ OS << "derived-to-base case (rvalue" << S->Type.getAsString() << ")";
+ break;
+
+ case SK_CastDerivedToBaseLValue:
+ OS << "derived-to-base case (lvalue" << S->Type.getAsString() << ")";
+ break;
+
+ case SK_BindReference:
+ OS << "bind reference to lvalue";
+ break;
+
+ case SK_BindReferenceToTemporary:
+ OS << "bind reference to a temporary";
+ break;
+
+ case SK_UserConversion:
+ OS << "user-defined conversion via " << S->Function->getNameAsString();
+ break;
+
+ case SK_QualificationConversionRValue:
+ OS << "qualification conversion (rvalue)";
+
+ case SK_QualificationConversionLValue:
+ OS << "qualification conversion (lvalue)";
+ break;
+
+ case SK_ConversionSequence:
+ OS << "implicit conversion sequence (";
+ S->ICS->DebugPrint(); // FIXME: use OS
+ OS << ")";
+ break;
+
+ case SK_ListInitialization:
+ OS << "list initialization";
+ break;
+
+ case SK_ConstructorInitialization:
+ OS << "constructor initialization";
+ break;
+
+ case SK_ZeroInitialization:
+ OS << "zero initialization";
+ break;
+
+ case SK_CAssignment:
+ OS << "C assignment";
+ break;
+
+ case SK_StringInit:
+ OS << "string initialization";
+ break;
+ }
+ }
+}
+
+void InitializationSequence::dump() const {
+ dump(llvm::errs());
+}
+
//===----------------------------------------------------------------------===//
// Initialization helper functions
//===----------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h
index d7d3756020f8..2b49df28fe86 100644
--- a/lib/Sema/SemaInit.h
+++ b/lib/Sema/SemaInit.h
@@ -15,12 +15,17 @@
#include "SemaOverload.h"
#include "clang/AST/Type.h"
+#include "clang/AST/UnresolvedSet.h"
#include "clang/Parse/Action.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallVector.h"
#include <cassert>
+namespace llvm {
+ class raw_ostream;
+}
+
namespace clang {
class CXXBaseSpecifier;
@@ -62,7 +67,6 @@ public:
/// \brief The entity being initialized is an element of a vector.
/// or vector.
EK_VectorElement
-
};
private:
@@ -91,8 +95,8 @@ private:
/// base class.
CXXBaseSpecifier *Base;
- /// \brief When Kind = EK_ArrayOrVectorElement, the index of the
- /// array or vector element being initialized.
+ /// \brief When Kind = EK_ArrayElement or EK_VectorElement, the
+ /// index of the array or vector element being initialized.
unsigned Index;
};
@@ -197,6 +201,12 @@ public:
/// initialized.
DeclaratorDecl *getDecl() const;
+ /// \brief Retrieve the base specifier.
+ CXXBaseSpecifier *getBaseSpecifier() const {
+ assert(getKind() == EK_Base && "Not a base specifier");
+ return Base;
+ }
+
/// \brief Determine the location of the 'return' keyword when initializing
/// the result of a function call.
SourceLocation getReturnLoc() const {
@@ -440,7 +450,11 @@ public:
/// \brief When Kind == SK_ResolvedOverloadedFunction or Kind ==
/// SK_UserConversion, the function that the expression should be
/// resolved to or the conversion function to call, respectively.
- FunctionDecl *Function;
+ ///
+ /// Always a FunctionDecl.
+ /// For conversion decls, the naming class is the source type.
+ /// For construct decls, the naming class is the target type.
+ DeclAccessPair Function;
/// \brief When Kind = SK_ConversionSequence, the implicit conversion
/// sequence
@@ -607,7 +621,9 @@ public:
/// \brief Add a new step invoking a conversion function, which is either
/// a constructor or a conversion function.
- void AddUserConversionStep(FunctionDecl *Function, QualType T);
+ void AddUserConversionStep(FunctionDecl *Function,
+ AccessSpecifier Access,
+ QualType T);
/// \brief Add a new step that performs a qualification conversion to the
/// given type.
@@ -622,6 +638,7 @@ public:
/// \brief Add a constructor-initialization step.
void AddConstructorInitializationStep(CXXConstructorDecl *Constructor,
+ AccessSpecifier Access,
QualType T);
/// \brief Add a zero-initialization step.
@@ -658,6 +675,14 @@ public:
assert(getKind() == FailedSequence && "Not an initialization failure!");
return Failure;
}
+
+ /// \brief Dump a representation of this initialization sequence to
+ /// the given stream, for debugging purposes.
+ void dump(llvm::raw_ostream &OS) const;
+
+ /// \brief Dump a representation of this initialization sequence to
+ /// standard error, for debugging purposes.
+ void dump() const;
};
} // end namespace clang
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index f5d2a7d89988..c7569d6eda25 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -404,7 +404,7 @@ void LookupResult::resolveKind() {
}
void LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) {
- CXXBasePaths::paths_iterator I, E;
+ CXXBasePaths::const_paths_iterator I, E;
DeclContext::lookup_iterator DI, DE;
for (I = P.begin(), E = P.end(); I != E; ++I)
for (llvm::tie(DI,DE) = I->Decls; DI != DE; ++DI)
@@ -438,9 +438,42 @@ void LookupResult::print(llvm::raw_ostream &Out) {
}
}
+/// \brief Lookup a builtin function, when name lookup would otherwise
+/// fail.
+static bool LookupBuiltin(Sema &S, LookupResult &R) {
+ Sema::LookupNameKind NameKind = R.getLookupKind();
+
+ // If we didn't find a use of this identifier, and if the identifier
+ // corresponds to a compiler builtin, create the decl object for the builtin
+ // now, injecting it into translation unit scope, and return it.
+ if (NameKind == Sema::LookupOrdinaryName ||
+ NameKind == Sema::LookupRedeclarationWithLinkage) {
+ IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo();
+ if (II) {
+ // If this is a builtin on this (or all) targets, create the decl.
+ if (unsigned BuiltinID = II->getBuiltinID()) {
+ // In C++, we don't have any predefined library functions like
+ // 'malloc'. Instead, we'll just error.
+ if (S.getLangOptions().CPlusPlus &&
+ S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
+ return false;
+
+ NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
+ S.TUScope, R.isForRedeclaration(),
+ R.getNameLoc());
+ if (D)
+ R.addDecl(D);
+ return (D != NULL);
+ }
+ }
+ }
+
+ return false;
+}
+
// 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(LookupResult &R, const DeclContext *DC) {
+static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
bool Found = false;
DeclContext::lookup_const_iterator I, E;
@@ -452,87 +485,89 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) {
}
}
+ if (!Found && DC->isTranslationUnit() && LookupBuiltin(S, R))
+ return true;
+
if (R.getLookupName().getNameKind()
- == DeclarationName::CXXConversionFunctionName &&
- !R.getLookupName().getCXXNameType()->isDependentType() &&
- isa<CXXRecordDecl>(DC)) {
+ != DeclarationName::CXXConversionFunctionName ||
+ R.getLookupName().getCXXNameType()->isDependentType() ||
+ !isa<CXXRecordDecl>(DC))
+ return Found;
+
+ // C++ [temp.mem]p6:
+ // A specialization of a conversion function template is not found by
+ // name lookup. Instead, any conversion function templates visible in the
+ // context of the use are considered. [...]
+ const CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
+ if (!Record->isDefinition())
+ return Found;
+
+ const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions();
+ for (UnresolvedSetImpl::iterator U = Unresolved->begin(),
+ UEnd = Unresolved->end(); U != UEnd; ++U) {
+ FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U);
+ if (!ConvTemplate)
+ continue;
+
+ // When we're performing lookup for the purposes of redeclaration, just
+ // add the conversion function template. When we deduce template
+ // arguments for specializations, we'll end up unifying the return
+ // type of the new declaration with the type of the function template.
+ if (R.isForRedeclaration()) {
+ R.addDecl(ConvTemplate);
+ Found = true;
+ continue;
+ }
+
// C++ [temp.mem]p6:
- // A specialization of a conversion function template is not found by
- // name lookup. Instead, any conversion function templates visible in the
- // context of the use are considered. [...]
- const CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
- if (!Record->isDefinition())
- return Found;
-
- const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions();
- for (UnresolvedSetImpl::iterator U = Unresolved->begin(),
- UEnd = Unresolved->end(); U != UEnd; ++U) {
- FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U);
- if (!ConvTemplate)
- continue;
-
- // When we're performing lookup for the purposes of redeclaration, just
- // add the conversion function template. When we deduce template
- // arguments for specializations, we'll end up unifying the return
- // type of the new declaration with the type of the function template.
- if (R.isForRedeclaration()) {
- R.addDecl(ConvTemplate);
- Found = true;
- continue;
- }
-
- // C++ [temp.mem]p6:
- // [...] For each such operator, if argument deduction succeeds
- // (14.9.2.3), the resulting specialization is used as if found by
- // name lookup.
- //
- // When referencing a conversion function for any purpose other than
- // a redeclaration (such that we'll be building an expression with the
- // result), perform template argument deduction and place the
- // specialization into the result set. We do this to avoid forcing all
- // callers to perform special deduction for conversion functions.
- Sema::TemplateDeductionInfo Info(R.getSema().Context);
- FunctionDecl *Specialization = 0;
-
- const FunctionProtoType *ConvProto
- = ConvTemplate->getTemplatedDecl()->getType()
- ->getAs<FunctionProtoType>();
- assert(ConvProto && "Nonsensical conversion function template type");
-
- // Compute the type of the function that we would expect the conversion
- // function to have, if it were to match the name given.
- // FIXME: Calling convention!
- QualType ExpectedType
- = R.getSema().Context.getFunctionType(
- R.getLookupName().getCXXNameType(),
- 0, 0, ConvProto->isVariadic(),
- ConvProto->getTypeQuals(),
- false, false, 0, 0,
- ConvProto->getNoReturnAttr());
-
- // Perform template argument deduction against the type that we would
- // expect the function to have.
- if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType,
- Specialization, Info)
- == Sema::TDK_Success) {
- R.addDecl(Specialization);
- Found = true;
- }
+ // [...] For each such operator, if argument deduction succeeds
+ // (14.9.2.3), the resulting specialization is used as if found by
+ // name lookup.
+ //
+ // When referencing a conversion function for any purpose other than
+ // a redeclaration (such that we'll be building an expression with the
+ // result), perform template argument deduction and place the
+ // specialization into the result set. We do this to avoid forcing all
+ // callers to perform special deduction for conversion functions.
+ Sema::TemplateDeductionInfo Info(R.getSema().Context, R.getNameLoc());
+ FunctionDecl *Specialization = 0;
+
+ const FunctionProtoType *ConvProto
+ = ConvTemplate->getTemplatedDecl()->getType()->getAs<FunctionProtoType>();
+ assert(ConvProto && "Nonsensical conversion function template type");
+
+ // Compute the type of the function that we would expect the conversion
+ // function to have, if it were to match the name given.
+ // FIXME: Calling convention!
+ QualType ExpectedType
+ = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(),
+ 0, 0, ConvProto->isVariadic(),
+ ConvProto->getTypeQuals(),
+ false, false, 0, 0,
+ ConvProto->getNoReturnAttr());
+
+ // Perform template argument deduction against the type that we would
+ // expect the function to have.
+ if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType,
+ Specialization, Info)
+ == Sema::TDK_Success) {
+ R.addDecl(Specialization);
+ Found = true;
}
}
-
+
return Found;
}
// Performs C++ unqualified lookup into the given file context.
static bool
-CppNamespaceLookup(LookupResult &R, ASTContext &Context, DeclContext *NS,
- UnqualUsingDirectiveSet &UDirs) {
+CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context,
+ DeclContext *NS, UnqualUsingDirectiveSet &UDirs) {
assert(NS && NS->isFileContext() && "CppNamespaceLookup() requires namespace!");
// Perform direct name lookup into the LookupCtx.
- bool Found = LookupDirect(R, NS);
+ bool Found = LookupDirect(S, R, NS);
// Perform direct name lookup into the namespaces nominated by the
// using directives whose common ancestor is this namespace.
@@ -540,7 +575,7 @@ CppNamespaceLookup(LookupResult &R, ASTContext &Context, DeclContext *NS,
llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(NS);
for (; UI != UEnd; ++UI)
- if (LookupDirect(R, UI->getNominatedNamespace()))
+ if (LookupDirect(S, R, UI->getNominatedNamespace()))
Found = true;
R.resolveKind();
@@ -650,12 +685,9 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
for (; S; S = S->getParent()) {
DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
- if (!Ctx || Ctx->isTransparentContext())
+ if (Ctx && Ctx->isTransparentContext())
continue;
- assert(Ctx && Ctx->isFileContext() &&
- "We should have been looking only at file context here already.");
-
// Check whether the IdResolver has anything in this scope.
bool Found = false;
for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) {
@@ -669,16 +701,21 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
}
}
- // Look into context considering using-directives.
- if (CppNamespaceLookup(R, Context, Ctx, UDirs))
- Found = true;
+ if (Ctx) {
+ assert(Ctx->isFileContext() &&
+ "We should have been looking only at file context here already.");
+
+ // Look into context considering using-directives.
+ if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs))
+ Found = true;
+ }
if (Found) {
R.resolveKind();
return true;
}
- if (R.isForRedeclaration() && !Ctx->isTransparentContext())
+ if (R.isForRedeclaration() && Ctx && !Ctx->isTransparentContext())
return false;
}
@@ -793,26 +830,9 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
// If we didn't find a use of this identifier, and if the identifier
// corresponds to a compiler builtin, create the decl object for the builtin
// now, injecting it into translation unit scope, and return it.
- if (NameKind == LookupOrdinaryName ||
- NameKind == LookupRedeclarationWithLinkage) {
- IdentifierInfo *II = Name.getAsIdentifierInfo();
- if (II && AllowBuiltinCreation) {
- // If this is a builtin on this (or all) targets, create the decl.
- if (unsigned BuiltinID = II->getBuiltinID()) {
- // In C++, we don't have any predefined library functions like
- // 'malloc'. Instead, we'll just error.
- if (getLangOptions().CPlusPlus &&
- Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
- return false;
+ if (AllowBuiltinCreation)
+ return LookupBuiltin(*this, R);
- NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
- S, R.isForRedeclaration(),
- R.getNameLoc());
- if (D) R.addDecl(D);
- return (D != NULL);
- }
- }
- }
return false;
}
@@ -842,7 +862,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
/// 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(LookupResult &R,
+static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
DeclContext *StartDC) {
assert(StartDC->isFileContext() && "start context is not a file context");
@@ -885,7 +905,7 @@ static bool LookupQualifiedNameInUsingDirectives(LookupResult &R,
// between LookupResults.
bool UseLocal = !R.empty();
LookupResult &DirectR = UseLocal ? LocalR : R;
- bool FoundDirect = LookupDirect(DirectR, ND);
+ bool FoundDirect = LookupDirect(S, DirectR, ND);
if (FoundDirect) {
// First do any local hiding.
@@ -965,7 +985,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)) {
+ if (LookupDirect(*this, R, LookupCtx)) {
R.resolveKind();
if (isa<CXXRecordDecl>(LookupCtx))
R.setNamingClass(cast<CXXRecordDecl>(LookupCtx));
@@ -986,7 +1006,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// If this is a namespace, look it up in the implied namespaces.
if (LookupCtx->isFileContext())
- return LookupQualifiedNameInUsingDirectives(R, LookupCtx);
+ return LookupQualifiedNameInUsingDirectives(*this, R, LookupCtx);
// If this isn't a C++ class, we aren't allowed to look into base
// classes, we're done.
@@ -1407,6 +1427,12 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
AssociatedClasses);
}
+ // Only recurse into base classes for complete types.
+ if (!Class->hasDefinition()) {
+ // FIXME: we might need to instantiate templates here
+ return;
+ }
+
// Add direct and indirect base classes along with their associated
// namespaces.
llvm::SmallVector<CXXRecordDecl *, 32> Bases;
@@ -1693,7 +1719,7 @@ ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) {
void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
QualType T1, QualType T2,
- FunctionSet &Functions) {
+ UnresolvedSetImpl &Functions) {
// C++ [over.match.oper]p3:
// -- The set of non-member candidates is the result of the
// unqualified lookup of operator@ in the context of the
@@ -1719,29 +1745,58 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
Op != OpEnd; ++Op) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Op)) {
if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
- Functions.insert(FD); // FIXME: canonical FD
+ Functions.addDecl(FD, Op.getAccess()); // FIXME: canonical FD
} else if (FunctionTemplateDecl *FunTmpl
= dyn_cast<FunctionTemplateDecl>(*Op)) {
// FIXME: friend operators?
// FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate,
// later?
if (!FunTmpl->getDeclContext()->isRecord())
- Functions.insert(FunTmpl);
+ Functions.addDecl(FunTmpl, Op.getAccess());
}
}
}
-static void CollectFunctionDecl(Sema::FunctionSet &Functions,
- Decl *D) {
- if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
- Functions.insert(Func);
- else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D))
- Functions.insert(FunTmpl);
+void ADLResult::insert(NamedDecl *New) {
+ NamedDecl *&Old = Decls[cast<NamedDecl>(New->getCanonicalDecl())];
+
+ // If we haven't yet seen a decl for this key, or the last decl
+ // was exactly this one, we're done.
+ if (Old == 0 || Old == New) {
+ Old = New;
+ return;
+ }
+
+ // Otherwise, decide which is a more recent redeclaration.
+ FunctionDecl *OldFD, *NewFD;
+ if (isa<FunctionTemplateDecl>(New)) {
+ OldFD = cast<FunctionTemplateDecl>(Old)->getTemplatedDecl();
+ NewFD = cast<FunctionTemplateDecl>(New)->getTemplatedDecl();
+ } else {
+ OldFD = cast<FunctionDecl>(Old);
+ NewFD = cast<FunctionDecl>(New);
+ }
+
+ FunctionDecl *Cursor = NewFD;
+ while (true) {
+ Cursor = Cursor->getPreviousDeclaration();
+
+ // If we got to the end without finding OldFD, OldFD is the newer
+ // declaration; leave things as they are.
+ if (!Cursor) return;
+
+ // If we do find OldFD, then NewFD is newer.
+ if (Cursor == OldFD) break;
+
+ // Otherwise, keep looking.
+ }
+
+ Old = New;
}
void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
Expr **Args, unsigned NumArgs,
- FunctionSet &Functions) {
+ ADLResult &Result) {
// Find all of the associated namespaces and classes based on the
// arguments we have.
AssociatedNamespaceSet AssociatedNamespaces;
@@ -1784,7 +1839,7 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
// lookup (11.4).
DeclContext::lookup_iterator I, E;
for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I) {
- Decl *D = *I;
+ NamedDecl *D = *I;
// If the only declaration here is an ordinary friend, consider
// it only if it was declared in an associated classes.
if (D->getIdentifierNamespace() == Decl::IDNS_OrdinaryFriend) {
@@ -1793,10 +1848,18 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
continue;
}
- FunctionDecl *Fn;
- if (!Operator || !(Fn = dyn_cast<FunctionDecl>(D)) ||
- IsAcceptableNonMemberOperatorCandidate(Fn, T1, T2, Context))
- CollectFunctionDecl(Functions, D);
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
+ if (isa<FunctionDecl>(D)) {
+ if (Operator &&
+ !IsAcceptableNonMemberOperatorCandidate(cast<FunctionDecl>(D),
+ T1, T2, Context))
+ continue;
+ } else if (!isa<FunctionTemplateDecl>(D))
+ continue;
+
+ Result.insert(D);
}
}
}
@@ -1985,6 +2048,9 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
bool InBaseClass,
VisibleDeclConsumer &Consumer,
VisibleDeclsRecord &Visited) {
+ if (!Ctx)
+ return;
+
// Make sure we don't visit the same context twice.
if (Visited.visitedContext(Ctx->getPrimaryContext()))
return;
@@ -2022,6 +2088,9 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
// Traverse the contexts of inherited C++ classes.
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
+ if (!Record->hasDefinition())
+ return;
+
for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(),
BEnd = Record->bases_end();
B != BEnd; ++B) {
@@ -2138,9 +2207,9 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
// For instance methods, look for ivars in the method's interface.
LookupResult IvarResult(Result.getSema(), Result.getLookupName(),
Result.getNameLoc(), Sema::LookupMemberName);
- ObjCInterfaceDecl *IFace = Method->getClassInterface();
- LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false,
- /*InBaseClass=*/false, Consumer, Visited);
+ if (ObjCInterfaceDecl *IFace = Method->getClassInterface())
+ LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false,
+ /*InBaseClass=*/false, Consumer, Visited);
}
// We've already performed all of the name lookup that we need
@@ -2312,9 +2381,16 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS,
DeclContext *MemberContext, bool EnteringContext,
const ObjCObjectPointerType *OPT) {
-
if (Diags.hasFatalErrorOccurred())
return false;
+
+ // Provide a stop gap for files that are just seriously broken. Trying
+ // to correct all typos can turn into a HUGE performance penalty, causing
+ // some files to take minutes to get rejected by the parser.
+ // FIXME: Is this the right solution?
+ if (TyposCorrected == 20)
+ return false;
+ ++TyposCorrected;
// We only attempt to correct typos for identifiers.
IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo();
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 44a8f15e57b6..b79b1cc99375 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -148,7 +148,7 @@ bool StandardConversionSequence::isPointerConversionToBool() const {
// array-to-pointer or function-to-pointer implicit conversions, so
// check for their presence as well as checking whether FromType is
// a pointer.
- if (getToType()->isBooleanType() &&
+ if (getToType(1)->isBooleanType() &&
(getFromType()->isPointerType() || getFromType()->isBlockPointerType() ||
First == ICK_Array_To_Pointer || First == ICK_Function_To_Pointer))
return true;
@@ -164,7 +164,7 @@ bool
StandardConversionSequence::
isPointerConversionToVoidPointer(ASTContext& Context) const {
QualType FromType = getFromType();
- QualType ToType = getToType();
+ QualType ToType = getToType(1);
// Note that FromType has not necessarily been transformed by the
// array-to-pointer implicit conversion, so check for its presence
@@ -447,16 +447,24 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
bool InOverloadResolution,
bool UserCast) {
ImplicitConversionSequence ICS;
- OverloadCandidateSet Conversions;
- OverloadingResult UserDefResult = OR_Success;
- if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard))
+ if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard)) {
ICS.setStandard();
- else if (getLangOptions().CPlusPlus &&
- (UserDefResult = IsUserDefinedConversion(From, ToType,
- ICS.UserDefined,
- Conversions,
- !SuppressUserConversions, AllowExplicit,
- ForceRValue, UserCast)) == OR_Success) {
+ return ICS;
+ }
+
+ if (!getLangOptions().CPlusPlus) {
+ ICS.setBad();
+ ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
+ return ICS;
+ }
+
+ OverloadCandidateSet Conversions(From->getExprLoc());
+ OverloadingResult UserDefResult
+ = IsUserDefinedConversion(From, ToType, ICS.UserDefined, Conversions,
+ !SuppressUserConversions, AllowExplicit,
+ ForceRValue, UserCast);
+
+ if (UserDefResult == OR_Success) {
ICS.setUserDefined();
// C++ [over.ics.user]p4:
// A conversion of an expression of class type to the same class
@@ -477,7 +485,7 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
ICS.setStandard();
ICS.Standard.setAsIdentityConversion();
ICS.Standard.setFromType(From->getType());
- ICS.Standard.setToType(ToType);
+ ICS.Standard.setAllToTypes(ToType);
ICS.Standard.CopyConstructor = Constructor;
if (ToCanon != FromCanon)
ICS.Standard.Second = ICK_Derived_To_Base;
@@ -595,7 +603,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// conversion (4.4). (C++ 4.2p2)
SCS.Second = ICK_Identity;
SCS.Third = ICK_Qualification;
- SCS.setToType(ToType);
+ SCS.setAllToTypes(FromType);
return true;
}
} else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) {
@@ -634,6 +642,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// We don't require any conversions for the first step.
SCS.First = ICK_Identity;
}
+ SCS.setToType(0, FromType);
// The second conversion can be an integral promotion, floating
// point promotion, integral conversion, floating point conversion,
@@ -714,6 +723,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// No second conversion required.
SCS.Second = ICK_Identity;
}
+ SCS.setToType(1, FromType);
QualType CanonFrom;
QualType CanonTo;
@@ -740,13 +750,13 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
CanonFrom = CanonTo;
}
}
+ SCS.setToType(2, FromType);
// If we have not converted the argument type to the parameter type,
// this is a bad conversion sequence.
if (CanonFrom != CanonTo)
return false;
- SCS.setToType(FromType);
return true;
}
@@ -766,7 +776,8 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
// int can represent all the values of the source type; otherwise,
// the source rvalue can be converted to an rvalue of type unsigned
// int (C++ 4.5p1).
- if (FromType->isPromotableIntegerType() && !FromType->isBooleanType()) {
+ if (FromType->isPromotableIntegerType() && !FromType->isBooleanType() &&
+ !FromType->isEnumeralType()) {
if (// We can promote any signed, promotable integer type to an int
(FromType->isSignedIntegerType() ||
// We can promote any unsigned integer type whose size is
@@ -1344,14 +1355,13 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType,
/// CheckMemberPointerConversion - Check the member pointer conversion from the
/// expression From to the type ToType. This routine checks for ambiguous or
-/// virtual (FIXME: or inaccessible) base-to-derived member pointer conversions
+/// virtual or inaccessible base-to-derived member pointer conversions
/// for which IsMemberPointerConversion has already returned true. It returns
/// true and produces a diagnostic if there was an error, or returns false
/// otherwise.
bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
CastExpr::CastKind &Kind,
bool IgnoreBaseAccess) {
- (void)IgnoreBaseAccess;
QualType FromType = From->getType();
const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>();
if (!FromPtrType) {
@@ -1374,7 +1384,7 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
assert(FromClass->isRecordType() && "Pointer into non-class.");
assert(ToClass->isRecordType() && "Pointer into non-class.");
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/ true,
/*DetectVirtual=*/true);
bool DerivationOkay = IsDerivedFrom(ToClass, FromClass, Paths);
assert(DerivationOkay &&
@@ -1383,13 +1393,6 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
if (Paths.isAmbiguous(Context.getCanonicalType(FromClass).
getUnqualifiedType())) {
- // Derivation is ambiguous. Redo the check to find the exact paths.
- Paths.clear();
- Paths.setRecordingPaths(true);
- bool StillOkay = IsDerivedFrom(ToClass, FromClass, Paths);
- assert(StillOkay && "Derivation changed due to quantum fluctuation.");
- (void)StillOkay;
-
std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths);
Diag(From->getExprLoc(), diag::err_ambiguous_memptr_conv)
<< 0 << FromClass << ToClass << PathDisplayStr << From->getSourceRange();
@@ -1403,6 +1406,10 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
return true;
}
+ if (!IgnoreBaseAccess)
+ CheckBaseClassAccess(From->getExprLoc(), /*BaseToDerived*/ true,
+ FromClass, ToClass, Paths.front());
+
// Must be a base to derived member conversion.
Kind = CastExpr::CK_BaseToDerivedMemberPointer;
return false;
@@ -1418,7 +1425,7 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) {
// If FromType and ToType are the same type, this is not a
// qualification conversion.
- if (FromType == ToType)
+ if (FromType.getUnqualifiedType() == ToType.getUnqualifiedType())
return false;
// (C++ 4.4p4):
@@ -1526,13 +1533,16 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
if (!Constructor->isInvalidDecl() &&
Constructor->isConvertingConstructor(AllowExplicit)) {
if (ConstructorTmpl)
- AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0,
+ AddTemplateOverloadCandidate(ConstructorTmpl,
+ ConstructorTmpl->getAccess(),
+ /*ExplicitArgs*/ 0,
&From, 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,
+ AddOverloadCandidate(Constructor, Constructor->getAccess(),
+ &From, 1, CandidateSet,
SuppressUserConversions, ForceRValue);
}
}
@@ -1568,11 +1578,12 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
if (AllowExplicit || !Conv->isExplicit()) {
if (ConvTemplate)
- AddTemplateConversionCandidate(ConvTemplate, ActingContext,
- From, ToType, CandidateSet);
+ AddTemplateConversionCandidate(ConvTemplate, I.getAccess(),
+ ActingContext, From, ToType,
+ CandidateSet);
else
- AddConversionCandidate(Conv, ActingContext, From, ToType,
- CandidateSet);
+ AddConversionCandidate(Conv, I.getAccess(), ActingContext,
+ From, ToType, CandidateSet);
}
}
}
@@ -1601,7 +1612,7 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
User.After.setAsIdentityConversion();
User.After.setFromType(
ThisType->getAs<PointerType>()->getPointeeType());
- User.After.setToType(ToType);
+ User.After.setAllToTypes(ToType);
return OR_Success;
} else if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>(Best->Function)) {
@@ -1647,7 +1658,7 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
bool
Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
ImplicitConversionSequence ICS;
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(From->getExprLoc());
OverloadingResult OvResult =
IsUserDefinedConversion(From, ToType, ICS.UserDefined,
CandidateSet, true, false, false);
@@ -1718,6 +1729,43 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
return ImplicitConversionSequence::Indistinguishable;
}
+// Per 13.3.3.2p3, compare the given standard conversion sequences to
+// determine if one is a proper subset of the other.
+static ImplicitConversionSequence::CompareKind
+compareStandardConversionSubsets(ASTContext &Context,
+ const StandardConversionSequence& SCS1,
+ const StandardConversionSequence& SCS2) {
+ ImplicitConversionSequence::CompareKind Result
+ = ImplicitConversionSequence::Indistinguishable;
+
+ if (SCS1.Second != SCS2.Second) {
+ if (SCS1.Second == ICK_Identity)
+ Result = ImplicitConversionSequence::Better;
+ else if (SCS2.Second == ICK_Identity)
+ Result = ImplicitConversionSequence::Worse;
+ else
+ return ImplicitConversionSequence::Indistinguishable;
+ } else if (!Context.hasSameType(SCS1.getToType(1), SCS2.getToType(1)))
+ return ImplicitConversionSequence::Indistinguishable;
+
+ if (SCS1.Third == SCS2.Third) {
+ return Context.hasSameType(SCS1.getToType(2), SCS2.getToType(2))? Result
+ : ImplicitConversionSequence::Indistinguishable;
+ }
+
+ if (SCS1.Third == ICK_Identity)
+ return Result == ImplicitConversionSequence::Worse
+ ? ImplicitConversionSequence::Indistinguishable
+ : ImplicitConversionSequence::Better;
+
+ if (SCS2.Third == ICK_Identity)
+ return Result == ImplicitConversionSequence::Better
+ ? ImplicitConversionSequence::Indistinguishable
+ : ImplicitConversionSequence::Worse;
+
+ return ImplicitConversionSequence::Indistinguishable;
+}
+
/// CompareStandardConversionSequences - Compare two standard
/// conversion sequences to determine whether one is better than the
/// other or if they are indistinguishable (C++ 13.3.3.2p3).
@@ -1733,21 +1781,9 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// excluding any Lvalue Transformation; the identity conversion
// sequence is considered to be a subsequence of any
// non-identity conversion sequence) or, if not that,
- if (SCS1.Second == SCS2.Second && SCS1.Third == SCS2.Third)
- // Neither is a proper subsequence of the other. Do nothing.
- ;
- else if ((SCS1.Second == ICK_Identity && SCS1.Third == SCS2.Third) ||
- (SCS1.Third == ICK_Identity && SCS1.Second == SCS2.Second) ||
- (SCS1.Second == ICK_Identity &&
- SCS1.Third == ICK_Identity))
- // SCS1 is a proper subsequence of SCS2.
- return ImplicitConversionSequence::Better;
- else if ((SCS2.Second == ICK_Identity && SCS2.Third == SCS1.Third) ||
- (SCS2.Third == ICK_Identity && SCS2.Second == SCS1.Second) ||
- (SCS2.Second == ICK_Identity &&
- SCS2.Third == ICK_Identity))
- // SCS2 is a proper subsequence of SCS1.
- return ImplicitConversionSequence::Worse;
+ if (ImplicitConversionSequence::CompareKind CK
+ = compareStandardConversionSubsets(Context, SCS1, SCS2))
+ return CK;
// -- the rank of S1 is better than the rank of S2 (by the rules
// defined below), or, if not that,
@@ -1852,8 +1888,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// top-level cv-qualifiers, and the type to which the reference
// initialized by S2 refers is more cv-qualified than the type
// to which the reference initialized by S1 refers.
- QualType T1 = SCS1.getToType();
- QualType T2 = SCS2.getToType();
+ QualType T1 = SCS1.getToType(2);
+ QualType T2 = SCS2.getToType(2);
T1 = Context.getCanonicalType(T1);
T2 = Context.getCanonicalType(T2);
Qualifiers T1Quals, T2Quals;
@@ -1894,8 +1930,8 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
// FIXME: the example in the standard doesn't use a qualification
// conversion (!)
- QualType T1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr);
- QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
+ QualType T1 = SCS1.getToType(2);
+ QualType T2 = SCS2.getToType(2);
T1 = Context.getCanonicalType(T1);
T2 = Context.getCanonicalType(T2);
Qualifiers T1Quals, T2Quals;
@@ -1984,9 +2020,9 @@ ImplicitConversionSequence::CompareKind
Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2) {
QualType FromType1 = SCS1.getFromType();
- QualType ToType1 = SCS1.getToType();
+ QualType ToType1 = SCS1.getToType(1);
QualType FromType2 = SCS2.getFromType();
- QualType ToType2 = SCS2.getToType();
+ QualType ToType2 = SCS2.getToType(1);
// Adjust the types we're converting from via the array-to-pointer
// conversion, if we need to.
@@ -2276,7 +2312,7 @@ Sema::TryObjectArgumentInitialization(QualType OrigFromType,
// Success. Mark this as a reference binding.
ICS.setStandard();
ICS.Standard.setFromType(FromType);
- ICS.Standard.setToType(ImplicitParamType);
+ ICS.Standard.setAllToTypes(ImplicitParamType);
ICS.Standard.ReferenceBinding = true;
ICS.Standard.DirectBinding = true;
ICS.Standard.RRefBinding = false;
@@ -2360,6 +2396,7 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
/// code completion.
void
Sema::AddOverloadCandidate(FunctionDecl *Function,
+ AccessSpecifier Access,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
@@ -2380,7 +2417,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// function, e.g., X::f(). We use an empty type for the implied
// object argument (C++ [over.call.func]p3), and the acting context
// is irrelevant.
- AddMethodCandidate(Method, Method->getParent(),
+ AddMethodCandidate(Method, Access, Method->getParent(),
QualType(), Args, NumArgs, CandidateSet,
SuppressUserConversions, ForceRValue);
return;
@@ -2410,6 +2447,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = Function;
+ Candidate.Access = Access;
Candidate.Viable = true;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
@@ -2469,35 +2507,33 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
/// \brief Add all of the function declarations in the given function set to
/// the overload canddiate set.
-void Sema::AddFunctionCandidates(const FunctionSet &Functions,
+void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
- for (FunctionSet::const_iterator F = Functions.begin(),
- FEnd = Functions.end();
- F != FEnd; ++F) {
+ for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) {
// FIXME: using declarations
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*F)) {
if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic())
- AddMethodCandidate(cast<CXXMethodDecl>(FD),
+ AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getAccess(),
cast<CXXMethodDecl>(FD)->getParent(),
Args[0]->getType(), Args + 1, NumArgs - 1,
CandidateSet, SuppressUserConversions);
else
- AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
+ AddOverloadCandidate(FD, AS_none, Args, NumArgs, CandidateSet,
SuppressUserConversions);
} else {
FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*F);
if (isa<CXXMethodDecl>(FunTmpl->getTemplatedDecl()) &&
!cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic())
- AddMethodTemplateCandidate(FunTmpl,
+ AddMethodTemplateCandidate(FunTmpl, F.getAccess(),
cast<CXXRecordDecl>(FunTmpl->getDeclContext()),
/*FIXME: explicit args */ 0,
Args[0]->getType(), Args + 1, NumArgs - 1,
CandidateSet,
SuppressUserConversions);
else
- AddTemplateOverloadCandidate(FunTmpl,
+ AddTemplateOverloadCandidate(FunTmpl, AS_none,
/*FIXME: explicit args */ 0,
Args, NumArgs, CandidateSet,
SuppressUserConversions);
@@ -2508,6 +2544,7 @@ 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,
+ AccessSpecifier Access,
QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
@@ -2520,13 +2557,13 @@ void Sema::AddMethodCandidate(NamedDecl *Decl,
if (FunctionTemplateDecl *TD = dyn_cast<FunctionTemplateDecl>(Decl)) {
assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) &&
"Expected a member function template");
- AddMethodTemplateCandidate(TD, ActingContext, /*ExplicitArgs*/ 0,
+ AddMethodTemplateCandidate(TD, Access, ActingContext, /*ExplicitArgs*/ 0,
ObjectType, Args, NumArgs,
CandidateSet,
SuppressUserConversions,
ForceRValue);
} else {
- AddMethodCandidate(cast<CXXMethodDecl>(Decl), ActingContext,
+ AddMethodCandidate(cast<CXXMethodDecl>(Decl), Access, ActingContext,
ObjectType, Args, NumArgs,
CandidateSet, SuppressUserConversions, ForceRValue);
}
@@ -2542,8 +2579,9 @@ void Sema::AddMethodCandidate(NamedDecl *Decl,
/// a slightly hacky way to implement the overloading rules for elidable copy
/// initialization in C++0x (C++0x 12.8p15).
void
-Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
- QualType ObjectType, Expr **Args, unsigned NumArgs,
+Sema::AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access,
+ CXXRecordDecl *ActingContext, QualType ObjectType,
+ Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions, bool ForceRValue) {
const FunctionProtoType* Proto
@@ -2562,6 +2600,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = Method;
+ Candidate.Access = Access;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
@@ -2639,6 +2678,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
/// function template specialization.
void
Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
+ AccessSpecifier Access,
CXXRecordDecl *ActingContext,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
@@ -2658,7 +2698,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
// functions. In such a case, the candidate functions generated from each
// function template are combined with the set of non-template candidate
// functions.
- TemplateDeductionInfo Info(Context);
+ TemplateDeductionInfo Info(Context, CandidateSet.getLocation());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult Result
= DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs,
@@ -2674,8 +2714,8 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
assert(Specialization && "Missing member function template specialization?");
assert(isa<CXXMethodDecl>(Specialization) &&
"Specialization is not a member function?");
- AddMethodCandidate(cast<CXXMethodDecl>(Specialization), ActingContext,
- ObjectType, Args, NumArgs,
+ AddMethodCandidate(cast<CXXMethodDecl>(Specialization), Access,
+ ActingContext, ObjectType, Args, NumArgs,
CandidateSet, SuppressUserConversions, ForceRValue);
}
@@ -2684,6 +2724,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
/// an appropriate function template specialization.
void
Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
+ AccessSpecifier Access,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
@@ -2701,29 +2742,30 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
// functions. In such a case, the candidate functions generated from each
// function template are combined with the set of non-template candidate
// functions.
- TemplateDeductionInfo Info(Context);
+ TemplateDeductionInfo Info(Context, CandidateSet.getLocation());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
Args, NumArgs, Specialization, Info)) {
- // FIXME: Record what happened with template argument deduction, so
- // that we can give the user a beautiful diagnostic.
- (void) Result;
-
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate &Candidate = CandidateSet.back();
Candidate.Function = FunctionTemplate->getTemplatedDecl();
+ Candidate.Access = Access;
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
+
+ // TODO: record more information about failed template arguments
+ Candidate.DeductionFailure.Result = Result;
+ Candidate.DeductionFailure.TemplateParameter = Info.Param.getOpaqueValue();
return;
}
// Add the function template specialization produced by template argument
// deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
- AddOverloadCandidate(Specialization, Args, NumArgs, CandidateSet,
+ AddOverloadCandidate(Specialization, Access, Args, NumArgs, CandidateSet,
SuppressUserConversions, ForceRValue);
}
@@ -2735,6 +2777,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
/// conversion function produces).
void
Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
+ AccessSpecifier Access,
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet) {
@@ -2751,11 +2794,12 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = Conversion;
+ Candidate.Access = Access;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.FinalConversion.setAsIdentityConversion();
Candidate.FinalConversion.setFromType(Conversion->getConversionType());
- Candidate.FinalConversion.setToType(ToType);
+ Candidate.FinalConversion.setAllToTypes(ToType);
// Determine the implicit conversion sequence for the implicit
// object parameter.
@@ -2837,6 +2881,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
/// [temp.deduct.conv]).
void
Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
+ AccessSpecifier Access,
CXXRecordDecl *ActingDC,
Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet) {
@@ -2846,7 +2891,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
if (!CandidateSet.isNewCandidate(FunctionTemplate))
return;
- TemplateDeductionInfo Info(Context);
+ TemplateDeductionInfo Info(Context, CandidateSet.getLocation());
CXXConversionDecl *Specialization = 0;
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, ToType,
@@ -2860,7 +2905,8 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
// Add the conversion function template specialization produced by
// template argument deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
- AddConversionCandidate(Specialization, ActingDC, From, ToType, CandidateSet);
+ AddConversionCandidate(Specialization, Access, ActingDC, From, ToType,
+ CandidateSet);
}
/// AddSurrogateCandidate - Adds a "surrogate" candidate function that
@@ -2869,6 +2915,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
/// with the given arguments (C++ [over.call.object]p2-4). Proto is
/// the type of function that we'll eventually be calling.
void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
+ AccessSpecifier Access,
CXXRecordDecl *ActingContext,
const FunctionProtoType *Proto,
QualType ObjectType,
@@ -2883,6 +2930,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = 0;
+ Candidate.Access = Access;
Candidate.Surrogate = Conversion;
Candidate.Viable = true;
Candidate.IsSurrogate = true;
@@ -2968,7 +3016,7 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
SourceRange OpRange) {
- FunctionSet Functions;
+ UnresolvedSet<16> Fns;
QualType T1 = Args[0]->getType();
QualType T2;
@@ -2977,9 +3025,10 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
if (S)
- LookupOverloadedOperatorName(Op, S, T1, T2, Functions);
- ArgumentDependentLookup(OpName, /*Operator*/true, Args, NumArgs, Functions);
- AddFunctionCandidates(Functions, Args, NumArgs, CandidateSet);
+ LookupOverloadedOperatorName(Op, S, T1, T2, Fns);
+ AddFunctionCandidates(Fns, Args, NumArgs, CandidateSet, false);
+ AddArgumentDependentLookupCandidates(OpName, false, Args, NumArgs, 0,
+ CandidateSet);
AddMemberOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet, OpRange);
AddBuiltinOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet);
}
@@ -3029,7 +3078,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
OperEnd = Operators.end();
Oper != OperEnd;
++Oper)
- AddMethodCandidate(*Oper, Args[0]->getType(),
+ AddMethodCandidate(*Oper, Oper.getAccess(), Args[0]->getType(),
Args + 1, NumArgs - 1, CandidateSet,
/* SuppressUserConversions = */ false);
}
@@ -3055,6 +3104,7 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = 0;
+ Candidate.Access = AS_none;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.BuiltinTypes.ResultTy = ResultTy;
@@ -3362,6 +3412,9 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) {
}
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
+ if (!ClassDecl->hasDefinition())
+ return VRQuals;
+
const UnresolvedSetImpl *Conversions =
ClassDecl->getVisibleConversionFunctions();
@@ -4108,54 +4161,45 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
/// candidate set (C++ [basic.lookup.argdep]).
void
Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
+ bool Operator,
Expr **Args, unsigned NumArgs,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
bool PartialOverloading) {
- FunctionSet Functions;
+ ADLResult Fns;
- // FIXME: Should we be trafficking in canonical function decls throughout?
-
- // Record all of the function candidates that we've already
- // added to the overload set, so that we don't add those same
- // candidates a second time.
- for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
- CandEnd = CandidateSet.end();
- Cand != CandEnd; ++Cand)
- if (Cand->Function) {
- Functions.insert(Cand->Function);
- if (FunctionTemplateDecl *FunTmpl = Cand->Function->getPrimaryTemplate())
- Functions.insert(FunTmpl);
- }
+ // FIXME: This approach for uniquing ADL results (and removing
+ // redundant candidates from the set) relies on pointer-equality,
+ // which means we need to key off the canonical decl. However,
+ // always going back to the canonical decl might not get us the
+ // right set of default arguments. What default arguments are
+ // we supposed to consider on ADL candidates, anyway?
// FIXME: Pass in the explicit template arguments?
- ArgumentDependentLookup(Name, /*Operator*/false, Args, NumArgs, Functions);
+ ArgumentDependentLookup(Name, Operator, Args, NumArgs, Fns);
// Erase all of the candidates we already knew about.
- // FIXME: This is suboptimal. Is there a better way?
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
CandEnd = CandidateSet.end();
Cand != CandEnd; ++Cand)
if (Cand->Function) {
- Functions.erase(Cand->Function);
+ Fns.erase(Cand->Function);
if (FunctionTemplateDecl *FunTmpl = Cand->Function->getPrimaryTemplate())
- Functions.erase(FunTmpl);
+ Fns.erase(FunTmpl);
}
// For each of the ADL candidates we found, add it to the overload
// set.
- for (FunctionSet::iterator Func = Functions.begin(),
- FuncEnd = Functions.end();
- Func != FuncEnd; ++Func) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func)) {
+ for (ADLResult::iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
if (ExplicitTemplateArgs)
continue;
- AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
+ AddOverloadCandidate(FD, AS_none, Args, NumArgs, CandidateSet,
false, false, PartialOverloading);
} else
- AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*Func),
- ExplicitTemplateArgs,
+ AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I),
+ AS_none, ExplicitTemplateArgs,
Args, NumArgs, CandidateSet);
}
}
@@ -4164,7 +4208,8 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
/// candidate is a better candidate than the second (C++ 13.3.3p1).
bool
Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
- const OverloadCandidate& Cand2) {
+ const OverloadCandidate& Cand2,
+ SourceLocation Loc) {
// Define viable functions to be better candidates than non-viable
// functions.
if (!Cand2.Viable)
@@ -4227,6 +4272,7 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
if (FunctionTemplateDecl *BetterTemplate
= getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(),
Cand2.Function->getPrimaryTemplate(),
+ Loc,
isa<CXXConversionDecl>(Cand1.Function)? TPOC_Conversion
: TPOC_Call))
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
@@ -4279,7 +4325,8 @@ OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
Cand != CandidateSet.end(); ++Cand) {
if (Cand->Viable) {
- if (Best == CandidateSet.end() || isBetterOverloadCandidate(*Cand, *Best))
+ if (Best == CandidateSet.end() ||
+ isBetterOverloadCandidate(*Cand, *Best, Loc))
Best = Cand;
}
}
@@ -4294,7 +4341,7 @@ OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
Cand != CandidateSet.end(); ++Cand) {
if (Cand->Viable &&
Cand != Best &&
- !isBetterOverloadCandidate(*Best, *Cand)) {
+ !isBetterOverloadCandidate(*Best, *Cand, Loc)) {
Best = CandidateSet.end();
return OR_Ambiguous;
}
@@ -4414,6 +4461,20 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
QualType FromTy = Conv.Bad.getFromType();
QualType ToTy = Conv.Bad.getToType();
+ if (FromTy == S.Context.OverloadTy) {
+ assert(FromExpr);
+ Expr *E = FromExpr->IgnoreParens();
+ if (isa<UnaryOperator>(E))
+ E = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();
+ DeclarationName Name = cast<OverloadExpr>(E)->getName();
+
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_overload)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << ToTy << Name << I+1;
+ return;
+ }
+
// Do some hand-waving analysis to see if the non-viability is due
// to a qualifier mismatch.
CanQualType CFromTy = S.Context.getCanonicalType(FromTy);
@@ -4520,6 +4581,58 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
<< (unsigned) FnKind << Description << mode << modeCount << NumFormalArgs;
}
+/// Diagnose a failed template-argument deduction.
+void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
+ Expr **Args, unsigned NumArgs) {
+ FunctionDecl *Fn = Cand->Function; // pattern
+
+ TemplateParameter Param = TemplateParameter::getFromOpaqueValue(
+ Cand->DeductionFailure.TemplateParameter);
+
+ switch (Cand->DeductionFailure.Result) {
+ case Sema::TDK_Success:
+ llvm_unreachable("TDK_success while diagnosing bad deduction");
+
+ case Sema::TDK_Incomplete: {
+ NamedDecl *ParamD;
+ (ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) ||
+ (ParamD = Param.dyn_cast<NonTypeTemplateParmDecl*>()) ||
+ (ParamD = Param.dyn_cast<TemplateTemplateParmDecl*>());
+ assert(ParamD && "no parameter found for incomplete deduction result");
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_incomplete_deduction)
+ << ParamD->getDeclName();
+ return;
+ }
+
+ // TODO: diagnose these individually, then kill off
+ // note_ovl_candidate_bad_deduction, which is uselessly vague.
+ case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_Inconsistent:
+ case Sema::TDK_InconsistentQuals:
+ case Sema::TDK_SubstitutionFailure:
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_TooManyArguments:
+ case Sema::TDK_TooFewArguments:
+ case Sema::TDK_InvalidExplicitArguments:
+ case Sema::TDK_FailedOverloadResolution:
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_deduction);
+ return;
+ }
+}
+
+/// Generates a 'note' diagnostic for an overload candidate. We've
+/// already generated a primary error at the call site.
+///
+/// It really does need to be a single diagnostic with its caret
+/// pointed at the candidate declaration. Yes, this creates some
+/// major challenges of technical writing. Yes, this makes pointing
+/// out problems with specific arguments quite awkward. It's still
+/// better than generating twenty screens of text for every failed
+/// overload.
+///
+/// It would be great to be able to express per-candidate problems
+/// more richly for those diagnostic clients that cared, but we'd
+/// still have to be just as careful with the default diagnostics.
void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
Expr **Args, unsigned NumArgs) {
FunctionDecl *Fn = Cand->Function;
@@ -4546,6 +4659,8 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
return DiagnoseArityMismatch(S, Cand, NumArgs);
case ovl_fail_bad_deduction:
+ return DiagnoseBadDeduction(S, Cand, Args, NumArgs);
+
case ovl_fail_trivial_conversion:
case ovl_fail_bad_final_conversion:
return S.NoteOverloadCandidate(Fn);
@@ -4651,8 +4766,8 @@ struct CompareOverloadCandidatesForDisplay {
// TODO: introduce a tri-valued comparison for overload
// candidates. Would be more worthwhile if we had a sort
// that could exploit it.
- if (S.isBetterOverloadCandidate(*L, *R)) return true;
- if (S.isBetterOverloadCandidate(*R, *L)) return false;
+ if (S.isBetterOverloadCandidate(*L, *R, SourceLocation())) return true;
+ if (S.isBetterOverloadCandidate(*R, *L, SourceLocation())) return false;
} else if (R->Viable)
return false;
@@ -4842,6 +4957,14 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
}
}
+static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, NamedDecl *D,
+ AccessSpecifier AS) {
+ if (isa<UnresolvedLookupExpr>(E))
+ return S.CheckUnresolvedLookupAccess(cast<UnresolvedLookupExpr>(E), D, AS);
+
+ return S.CheckUnresolvedMemberAccess(cast<UnresolvedMemberExpr>(E), D, AS);
+}
+
/// ResolveAddressOfOverloadedFunction - Try to resolve the address of
/// an overloaded function (C++ [over.over]), where @p From is an
/// expression with overloaded function type and @p ToType is the type
@@ -4878,52 +5001,28 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
return 0;
// Find the actual overloaded function declaration.
+ if (From->getType() != Context.OverloadTy)
+ return 0;
// C++ [over.over]p1:
// [...] [Note: any redundant set of parentheses surrounding the
// overloaded function name is ignored (5.1). ]
- Expr *OvlExpr = From->IgnoreParens();
-
// C++ [over.over]p1:
// [...] The overloaded function name can be preceded by the &
// operator.
- if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(OvlExpr)) {
- if (UnOp->getOpcode() == UnaryOperator::AddrOf)
- OvlExpr = UnOp->getSubExpr()->IgnoreParens();
+ OverloadExpr *OvlExpr = OverloadExpr::find(From).getPointer();
+ TemplateArgumentListInfo ETABuffer, *ExplicitTemplateArgs = 0;
+ if (OvlExpr->hasExplicitTemplateArgs()) {
+ OvlExpr->getExplicitTemplateArgs().copyInto(ETABuffer);
+ ExplicitTemplateArgs = &ETABuffer;
}
- bool HasExplicitTemplateArgs = false;
- TemplateArgumentListInfo ExplicitTemplateArgs;
-
- llvm::SmallVector<NamedDecl*,8> Fns;
-
- // Look into the overloaded expression.
- if (UnresolvedLookupExpr *UL
- = dyn_cast<UnresolvedLookupExpr>(OvlExpr)) {
- Fns.append(UL->decls_begin(), UL->decls_end());
- if (UL->hasExplicitTemplateArgs()) {
- HasExplicitTemplateArgs = true;
- UL->copyTemplateArgumentsInto(ExplicitTemplateArgs);
- }
- } else if (UnresolvedMemberExpr *ME
- = dyn_cast<UnresolvedMemberExpr>(OvlExpr)) {
- Fns.append(ME->decls_begin(), ME->decls_end());
- if (ME->hasExplicitTemplateArgs()) {
- HasExplicitTemplateArgs = true;
- ME->copyTemplateArgumentsInto(ExplicitTemplateArgs);
- }
- }
-
- // If we didn't actually find anything, we're done.
- if (Fns.empty())
- return 0;
-
// Look through all of the overloaded functions, searching for one
// whose type matches exactly.
- llvm::SmallPtrSet<FunctionDecl *, 4> Matches;
+ UnresolvedSet<4> Matches; // contains only FunctionDecls
bool FoundNonTemplateFunction = false;
- for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(),
- E = Fns.end(); I != E; ++I) {
+ for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
+ E = OvlExpr->decls_end(); I != E; ++I) {
// Look through any using declarations to find the underlying function.
NamedDecl *Fn = (*I)->getUnderlyingDecl();
@@ -4953,10 +5052,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// overloaded functions considered.
// FIXME: We don't really want to build the specialization here, do we?
FunctionDecl *Specialization = 0;
- TemplateDeductionInfo Info(Context);
+ TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc());
if (TemplateDeductionResult Result
- = DeduceTemplateArguments(FunctionTemplate,
- (HasExplicitTemplateArgs ? &ExplicitTemplateArgs : 0),
+ = DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
FunctionType, Specialization, Info)) {
// FIXME: make a note of the failed deduction for diagnostics.
(void)Result;
@@ -4965,8 +5063,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// a candidate? Find a testcase before changing the code.
assert(FunctionType
== Context.getCanonicalType(Specialization->getType()));
- Matches.insert(
- cast<FunctionDecl>(Specialization->getCanonicalDecl()));
+ Matches.addDecl(cast<FunctionDecl>(Specialization->getCanonicalDecl()),
+ I.getAccess());
}
continue;
@@ -4979,7 +5077,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
continue;
// If we have explicit template arguments, skip non-templates.
- if (HasExplicitTemplateArgs)
+ if (OvlExpr->hasExplicitTemplateArgs())
continue;
} else if (IsMember)
continue;
@@ -4989,7 +5087,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) ||
IsNoReturnConversion(Context, FunDecl->getType(), FunctionType,
ResultTy)) {
- Matches.insert(cast<FunctionDecl>(FunDecl->getCanonicalDecl()));
+ Matches.addDecl(cast<FunctionDecl>(FunDecl->getCanonicalDecl()),
+ I.getAccess());
FoundNonTemplateFunction = true;
}
}
@@ -4999,14 +5098,15 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
if (Matches.empty())
return 0;
else if (Matches.size() == 1) {
- FunctionDecl *Result = *Matches.begin();
+ FunctionDecl *Result = cast<FunctionDecl>(*Matches.begin());
MarkDeclarationReferenced(From->getLocStart(), Result);
+ if (Complain)
+ CheckUnresolvedAccess(*this, OvlExpr, Result, Matches.begin().getAccess());
return Result;
}
// C++ [over.over]p4:
// If more than one function is selected, [...]
- typedef llvm::SmallPtrSet<FunctionDecl *, 4>::iterator MatchIter;
if (!FoundNonTemplateFunction) {
// [...] and any given function template specialization F1 is
// eliminated if the set contains a second function template
@@ -5018,41 +5118,50 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// two-pass algorithm (similar to the one used to identify the
// best viable function in an overload set) that identifies the
// best function template (if it exists).
- llvm::SmallVector<FunctionDecl *, 8> TemplateMatches(Matches.begin(),
- Matches.end());
- FunctionDecl *Result =
- getMostSpecialized(TemplateMatches.data(), TemplateMatches.size(),
+
+ UnresolvedSetIterator Result =
+ getMostSpecialized(Matches.begin(), Matches.end(),
TPOC_Other, From->getLocStart(),
PDiag(),
PDiag(diag::err_addr_ovl_ambiguous)
- << TemplateMatches[0]->getDeclName(),
+ << Matches[0]->getDeclName(),
PDiag(diag::note_ovl_candidate)
<< (unsigned) oc_function_template);
- MarkDeclarationReferenced(From->getLocStart(), Result);
- return Result;
+ assert(Result != Matches.end() && "no most-specialized template");
+ MarkDeclarationReferenced(From->getLocStart(), *Result);
+ if (Complain)
+ CheckUnresolvedAccess(*this, OvlExpr, *Result, Result.getAccess());
+ return cast<FunctionDecl>(*Result);
}
// [...] any function template specializations in the set are
// eliminated if the set also contains a non-template function, [...]
- llvm::SmallVector<FunctionDecl *, 4> RemainingMatches;
- for (MatchIter M = Matches.begin(), MEnd = Matches.end(); M != MEnd; ++M)
- if ((*M)->getPrimaryTemplate() == 0)
- RemainingMatches.push_back(*M);
+ for (unsigned I = 0, N = Matches.size(); I != N; ) {
+ if (cast<FunctionDecl>(Matches[I].getDecl())->getPrimaryTemplate() == 0)
+ ++I;
+ else {
+ Matches.erase(I);
+ --N;
+ }
+ }
// [...] After such eliminations, if any, there shall remain exactly one
// selected function.
- if (RemainingMatches.size() == 1) {
- FunctionDecl *Result = RemainingMatches.front();
- MarkDeclarationReferenced(From->getLocStart(), Result);
- return Result;
+ if (Matches.size() == 1) {
+ UnresolvedSetIterator Match = Matches.begin();
+ MarkDeclarationReferenced(From->getLocStart(), *Match);
+ if (Complain)
+ CheckUnresolvedAccess(*this, OvlExpr, *Match, Match.getAccess());
+ return cast<FunctionDecl>(*Match);
}
// FIXME: We should probably return the same thing that BestViableFunction
// returns (even if we issue the diagnostics here).
Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous)
- << RemainingMatches[0]->getDeclName();
- for (unsigned I = 0, N = RemainingMatches.size(); I != N; ++I)
- NoteOverloadCandidate(RemainingMatches[I]);
+ << Matches[0]->getDeclName();
+ for (UnresolvedSetIterator I = Matches.begin(),
+ E = Matches.end(); I != E; ++I)
+ NoteOverloadCandidate(cast<FunctionDecl>(*I));
return 0;
}
@@ -5067,47 +5176,27 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) {
// C++ [over.over]p1:
// [...] [Note: any redundant set of parentheses surrounding the
// overloaded function name is ignored (5.1). ]
- Expr *OvlExpr = From->IgnoreParens();
-
// C++ [over.over]p1:
// [...] The overloaded function name can be preceded by the &
// operator.
- if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(OvlExpr)) {
- if (UnOp->getOpcode() == UnaryOperator::AddrOf)
- OvlExpr = UnOp->getSubExpr()->IgnoreParens();
- }
-
- bool HasExplicitTemplateArgs = false;
- TemplateArgumentListInfo ExplicitTemplateArgs;
-
- llvm::SmallVector<NamedDecl*,8> Fns;
-
- // Look into the overloaded expression.
- if (UnresolvedLookupExpr *UL
- = dyn_cast<UnresolvedLookupExpr>(OvlExpr)) {
- Fns.append(UL->decls_begin(), UL->decls_end());
- if (UL->hasExplicitTemplateArgs()) {
- HasExplicitTemplateArgs = true;
- UL->copyTemplateArgumentsInto(ExplicitTemplateArgs);
- }
- } else if (UnresolvedMemberExpr *ME
- = dyn_cast<UnresolvedMemberExpr>(OvlExpr)) {
- Fns.append(ME->decls_begin(), ME->decls_end());
- if (ME->hasExplicitTemplateArgs()) {
- HasExplicitTemplateArgs = true;
- ME->copyTemplateArgumentsInto(ExplicitTemplateArgs);
- }
- }
+
+ if (From->getType() != Context.OverloadTy)
+ return 0;
+
+ OverloadExpr *OvlExpr = OverloadExpr::find(From).getPointer();
// If we didn't actually find any template-ids, we're done.
- if (Fns.empty() || !HasExplicitTemplateArgs)
+ if (!OvlExpr->hasExplicitTemplateArgs())
return 0;
+
+ TemplateArgumentListInfo ExplicitTemplateArgs;
+ OvlExpr->getExplicitTemplateArgs().copyInto(ExplicitTemplateArgs);
// Look through all of the overloaded functions, searching for one
// whose type matches exactly.
FunctionDecl *Matched = 0;
- for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(),
- E = Fns.end(); I != E; ++I) {
+ for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
+ E = OvlExpr->decls_end(); I != E; ++I) {
// C++0x [temp.arg.explicit]p3:
// [...] In contexts where deduction is done and fails, or in contexts
// where deduction is not done, if a template argument list is
@@ -5123,7 +5212,7 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) {
// function template specialization, which is added to the set of
// overloaded functions considered.
FunctionDecl *Specialization = 0;
- TemplateDeductionInfo Info(Context);
+ TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc());
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs,
Specialization, Info)) {
@@ -5145,6 +5234,7 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) {
/// \brief Add a single candidate to the overload set.
static void AddOverloadedCallCandidate(Sema &S,
NamedDecl *Callee,
+ AccessSpecifier Access,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet &CandidateSet,
@@ -5154,14 +5244,14 @@ static void AddOverloadedCallCandidate(Sema &S,
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) {
assert(!ExplicitTemplateArgs && "Explicit template arguments?");
- S.AddOverloadCandidate(Func, Args, NumArgs, CandidateSet, false, false,
- PartialOverloading);
+ S.AddOverloadCandidate(Func, Access, Args, NumArgs, CandidateSet,
+ false, false, PartialOverloading);
return;
}
if (FunctionTemplateDecl *FuncTemplate
= dyn_cast<FunctionTemplateDecl>(Callee)) {
- S.AddTemplateOverloadCandidate(FuncTemplate, ExplicitTemplateArgs,
+ S.AddTemplateOverloadCandidate(FuncTemplate, Access, ExplicitTemplateArgs,
Args, NumArgs, CandidateSet);
return;
}
@@ -5217,12 +5307,13 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(),
E = ULE->decls_end(); I != E; ++I)
- AddOverloadedCallCandidate(*this, *I, ExplicitTemplateArgs,
+ AddOverloadedCallCandidate(*this, *I, I.getAccess(), ExplicitTemplateArgs,
Args, NumArgs, CandidateSet,
PartialOverloading);
if (ULE->requiresADL())
- AddArgumentDependentLookupCandidates(ULE->getName(), Args, NumArgs,
+ AddArgumentDependentLookupCandidates(ULE->getName(), /*Operator*/ false,
+ Args, NumArgs,
ExplicitTemplateArgs,
CandidateSet,
PartialOverloading);
@@ -5321,7 +5412,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
}
#endif
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(Fn->getExprLoc());
// Add the functions denoted by the callee to the set of candidate
// functions, including those from argument-dependent lookup.
@@ -5338,6 +5429,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) {
case OR_Success: {
FunctionDecl *FDecl = Best->Function;
+ CheckUnresolvedLookupAccess(ULE, FDecl, Best->getAccess());
Fn = FixOverloadedFunctionReference(Fn, FDecl);
return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc);
}
@@ -5372,7 +5464,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
return ExprError();
}
-static bool IsOverloaded(const Sema::FunctionSet &Functions) {
+static bool IsOverloaded(const UnresolvedSetImpl &Functions) {
return Functions.size() > 1 ||
(Functions.size() == 1 && isa<FunctionTemplateDecl>(*Functions.begin()));
}
@@ -5393,10 +5485,10 @@ static bool IsOverloaded(const Sema::FunctionSet &Functions) {
/// by CreateOverloadedUnaryOp().
///
/// \param input The input argument.
-Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
- unsigned OpcIn,
- FunctionSet &Functions,
- ExprArg input) {
+Sema::OwningExprResult
+Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
+ const UnresolvedSetImpl &Fns,
+ ExprArg input) {
UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn);
Expr *Input = (Expr *)input.get();
@@ -5418,14 +5510,12 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
}
if (Input->isTypeDependent()) {
+ CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators
UnresolvedLookupExpr *Fn
- = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true,
+ = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass,
0, SourceRange(), OpName, OpLoc,
- /*ADL*/ true, IsOverloaded(Functions));
- for (FunctionSet::iterator Func = Functions.begin(),
- FuncEnd = Functions.end();
- Func != FuncEnd; ++Func)
- Fn->addDecl(*Func);
+ /*ADL*/ true, IsOverloaded(Fns));
+ Fn->addDecls(Fns.begin(), Fns.end());
input.release();
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
@@ -5435,14 +5525,20 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
}
// Build an empty overload set.
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(OpLoc);
// Add the candidates from the given function set.
- AddFunctionCandidates(Functions, &Args[0], NumArgs, CandidateSet, false);
+ AddFunctionCandidates(Fns, &Args[0], NumArgs, CandidateSet, false);
// Add operator candidates that are member functions.
AddMemberOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet);
+ // Add candidates from ADL.
+ AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true,
+ Args, NumArgs,
+ /*ExplicitTemplateArgs*/ 0,
+ CandidateSet);
+
// Add builtin operator candidates.
AddBuiltinOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet);
@@ -5459,6 +5555,8 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
+ CheckMemberOperatorAccess(OpLoc, Args[0], Method, Best->getAccess());
+
if (PerformObjectArgumentInitialization(Input, Method))
return ExprError();
} else {
@@ -5555,7 +5653,7 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
Sema::OwningExprResult
Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
unsigned OpcIn,
- FunctionSet &Functions,
+ const UnresolvedSetImpl &Fns,
Expr *LHS, Expr *RHS) {
Expr *Args[2] = { LHS, RHS };
LHS=RHS=0; //Please use only Args instead of LHS/RHS couple
@@ -5567,7 +5665,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// If either side is type-dependent, create an appropriate dependent
// expression.
if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) {
- if (Functions.empty()) {
+ if (Fns.empty()) {
// If there are no functions to store, just build a dependent
// BinaryOperator or CompoundAssignment.
if (Opc <= BinaryOperator::Assign || Opc > BinaryOperator::OrAssign)
@@ -5580,17 +5678,15 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
Context.DependentTy,
OpLoc));
}
-
+
+ // FIXME: save results of ADL from here?
+ CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators
UnresolvedLookupExpr *Fn
- = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true,
+ = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass,
0, SourceRange(), OpName, OpLoc,
- /* ADL */ true, IsOverloaded(Functions));
-
- for (FunctionSet::iterator Func = Functions.begin(),
- FuncEnd = Functions.end();
- Func != FuncEnd; ++Func)
- Fn->addDecl(*Func);
+ /*ADL*/ true, IsOverloaded(Fns));
+ Fn->addDecls(Fns.begin(), Fns.end());
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
Args, 2,
Context.DependentTy,
@@ -5612,14 +5708,20 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// Build an empty overload set.
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(OpLoc);
// Add the candidates from the given function set.
- AddFunctionCandidates(Functions, Args, 2, CandidateSet, false);
+ AddFunctionCandidates(Fns, Args, 2, CandidateSet, false);
// Add operator candidates that are member functions.
AddMemberOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet);
+ // Add candidates from ADL.
+ AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true,
+ Args, 2,
+ /*ExplicitTemplateArgs*/ 0,
+ CandidateSet);
+
// Add builtin operator candidates.
AddBuiltinOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet);
@@ -5636,6 +5738,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
+ // Best->Access is only meaningful for class members.
+ CheckMemberOperatorAccess(OpLoc, Args[0], Method, Best->getAccess());
+
OwningExprResult Arg1
= PerformCopyInitialization(
InitializedEntity::InitializeParameter(
@@ -5770,8 +5875,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// expression.
if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) {
+ CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators
UnresolvedLookupExpr *Fn
- = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true,
+ = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass,
0, SourceRange(), OpName, LLoc,
/*ADL*/ true, /*Overloaded*/ false);
// Can't add any actual overloads yet
@@ -5785,7 +5891,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
}
// Build an empty overload set.
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(LLoc);
// Subscript can only be overloaded as a member function.
@@ -5806,14 +5912,24 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// We matched an overloaded operator. Build a call to that
// operator.
+ CheckMemberOperatorAccess(LLoc, Args[0], FnDecl, Best->getAccess());
+
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
- if (PerformObjectArgumentInitialization(Args[0], Method) ||
- PerformCopyInitialization(Args[1],
- FnDecl->getParamDecl(0)->getType(),
- AA_Passing))
+ if (PerformObjectArgumentInitialization(Args[0], Method))
return ExprError();
+ // Convert the arguments.
+ OwningExprResult InputInit
+ = PerformCopyInitialization(InitializedEntity::InitializeParameter(
+ FnDecl->getParamDecl(0)),
+ SourceLocation(),
+ Owned(Args[1]));
+ if (InputInit.isInvalid())
+ return ExprError();
+
+ Args[1] = InputInit.takeAs<Expr>();
+
// Determine the result type
QualType ResultTy
= FnDecl->getType()->getAs<FunctionType>()->getResultType();
@@ -5914,7 +6030,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
QualType ObjectType = UnresExpr->getBaseType();
// Add overload candidates
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(UnresExpr->getMemberLoc());
// FIXME: avoid copy.
TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0;
@@ -5937,11 +6053,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
if (TemplateArgs)
continue;
- AddMethodCandidate(Method, ActingDC, ObjectType, Args, NumArgs,
+ AddMethodCandidate(Method, I.getAccess(), ActingDC, ObjectType,
+ Args, NumArgs,
CandidateSet, /*SuppressUserConversions=*/false);
} else {
AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func),
- ActingDC, TemplateArgs,
+ I.getAccess(), ActingDC, TemplateArgs,
ObjectType, Args, NumArgs,
CandidateSet,
/*SuppressUsedConversions=*/false);
@@ -5954,6 +6071,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
switch (BestViableFunction(CandidateSet, UnresExpr->getLocStart(), Best)) {
case OR_Success:
Method = cast<CXXMethodDecl>(Best->Function);
+ CheckUnresolvedMemberAccess(UnresExpr, Method, Best->getAccess());
break;
case OR_No_Viable_Function:
@@ -6043,7 +6161,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// operators of T. The function call operators of T are obtained by
// ordinary lookup of the name operator() in the context of
// (E).operator().
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(LParenLoc);
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call);
if (RequireCompleteType(LParenLoc, Object->getType(),
@@ -6057,7 +6175,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
Oper != OperEnd; ++Oper) {
- AddMethodCandidate(*Oper, Object->getType(), Args, NumArgs, CandidateSet,
+ AddMethodCandidate(*Oper, Oper.getAccess(), Object->getType(),
+ Args, NumArgs, CandidateSet,
/*SuppressUserConversions=*/ false);
}
@@ -6101,7 +6220,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
ConvType = ConvPtrType->getPointeeType();
if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>())
- AddSurrogateCandidate(Conv, ActingContext, Proto,
+ AddSurrogateCandidate(Conv, I.getAccess(), ActingContext, Proto,
Object->getType(), Args, NumArgs,
CandidateSet);
}
@@ -6158,6 +6277,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
= cast<CXXConversionDecl>(
Best->Conversions[0].UserDefined.ConversionFunction);
+ CheckMemberOperatorAccess(LParenLoc, Object, Conv, Best->getAccess());
+
// We selected one of the surrogate functions that converts the
// object parameter to a function pointer. Perform the conversion
// on the object argument, then let ActOnCallExpr finish the job.
@@ -6171,6 +6292,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
CommaLocs, RParenLoc).release();
}
+ CheckMemberOperatorAccess(LParenLoc, Object,
+ Best->Function, Best->getAccess());
+
// We found an overloaded operator(). Build a CXXOperatorCallExpr
// that calls this method, using Object for the implicit object
// parameter and passing along the remaining arguments.
@@ -6232,8 +6356,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
Arg = Args[i];
// Pass the argument.
- QualType ProtoArgType = Proto->getArgType(i);
- IsError |= PerformCopyInitialization(Arg, ProtoArgType, AA_Passing);
+
+ OwningExprResult InputInit
+ = PerformCopyInitialization(InitializedEntity::InitializeParameter(
+ Method->getParamDecl(i)),
+ SourceLocation(), Owned(Arg));
+
+ IsError |= InputInit.isInvalid();
+ Arg = InputInit.takeAs<Expr>();
} else {
OwningExprResult DefArg
= BuildCXXDefaultArgExpr(LParenLoc, Method, Method->getParamDecl(i));
@@ -6274,6 +6404,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
Expr *Base = static_cast<Expr *>(BaseIn.get());
assert(Base->getType()->isRecordType() && "left-hand side must have class type");
+ SourceLocation Loc = Base->getExprLoc();
+
// C++ [over.ref]p1:
//
// [...] An expression x->m is interpreted as (x.operator->())->m
@@ -6281,10 +6413,10 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
// the operator is selected as the best match function by the
// overload resolution mechanism (13.3).
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Arrow);
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(Loc);
const RecordType *BaseRecord = Base->getType()->getAs<RecordType>();
- if (RequireCompleteType(Base->getLocStart(), Base->getType(),
+ if (RequireCompleteType(Loc, Base->getType(),
PDiag(diag::err_typecheck_incomplete_tag)
<< Base->getSourceRange()))
return ExprError();
@@ -6300,7 +6432,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
- AddMethodCandidate(cast<CXXMethodDecl>(D), ActingContext,
+ AddMethodCandidate(cast<CXXMethodDecl>(D), Oper.getAccess(), ActingContext,
Base->getType(), 0, 0, CandidateSet,
/*SuppressUserConversions=*/false);
}
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index f8353e3db1bd..e6dfa742355f 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -139,9 +139,10 @@ namespace clang {
/// QualType.
void *FromTypePtr;
- /// ToType - The type that this conversion is converting to. This
- /// is an opaque pointer that can be translated into a QualType.
- void *ToTypePtr;
+ /// ToType - The types that this conversion is converting to in
+ /// each step. This is an opaque pointer that can be translated
+ /// into a QualType.
+ void *ToTypePtrs[3];
/// CopyConstructor - The copy constructor that is used to perform
/// this conversion, when the conversion is actually just the
@@ -151,12 +152,22 @@ namespace clang {
CXXConstructorDecl *CopyConstructor;
void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); }
- void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); }
+ void setToType(unsigned Idx, QualType T) {
+ assert(Idx < 3 && "To type index is out of range");
+ ToTypePtrs[Idx] = T.getAsOpaquePtr();
+ }
+ void setAllToTypes(QualType T) {
+ ToTypePtrs[0] = T.getAsOpaquePtr();
+ ToTypePtrs[1] = ToTypePtrs[0];
+ ToTypePtrs[2] = ToTypePtrs[0];
+ }
+
QualType getFromType() const {
return QualType::getFromOpaquePtr(FromTypePtr);
}
- QualType getToType() const {
- return QualType::getFromOpaquePtr(ToTypePtr);
+ QualType getToType(unsigned Idx) const {
+ assert(Idx < 3 && "To type index is out of range");
+ return QualType::getFromOpaquePtr(ToTypePtrs[Idx]);
}
void setAsIdentityConversion();
@@ -446,11 +457,33 @@ namespace clang {
/// Actually an OverloadFailureKind.
unsigned char FailureKind;
- /// FinalConversion - For a conversion function (where Function is
- /// a CXXConversionDecl), the standard conversion that occurs
- /// after the call to the overload candidate to convert the result
- /// of calling the conversion function to the required type.
- StandardConversionSequence FinalConversion;
+ /// PathAccess - The 'path access' to the given function/conversion.
+ /// Actually an AccessSpecifier.
+ unsigned Access;
+
+ AccessSpecifier getAccess() const {
+ return AccessSpecifier(Access);
+ }
+
+ /// A structure used to record information about a failed
+ /// template argument deduction.
+ struct DeductionFailureInfo {
+ // A Sema::TemplateDeductionResult.
+ unsigned Result;
+
+ // A TemplateParameter.
+ void *TemplateParameter;
+ };
+
+ union {
+ DeductionFailureInfo DeductionFailure;
+
+ /// FinalConversion - For a conversion function (where Function is
+ /// a CXXConversionDecl), the standard conversion that occurs
+ /// after the call to the overload candidate to convert the result
+ /// of calling the conversion function to the required type.
+ StandardConversionSequence FinalConversion;
+ };
/// hasAmbiguousConversion - Returns whether this overload
/// candidate requires an ambiguous conversion or not.
@@ -468,8 +501,13 @@ namespace clang {
class OverloadCandidateSet : public llvm::SmallVector<OverloadCandidate, 16> {
typedef llvm::SmallVector<OverloadCandidate, 16> inherited;
llvm::SmallPtrSet<Decl *, 16> Functions;
-
+
+ SourceLocation Loc;
public:
+ OverloadCandidateSet(SourceLocation Loc) : Loc(Loc) {}
+
+ SourceLocation getLocation() const { return Loc; }
+
/// \brief Determine when this overload candidate will be new to the
/// overload set.
bool isNewCandidate(Decl *F) {
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 0c207fa6e87d..fa42634a3475 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -93,6 +93,15 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
if (isa<ObjCImplicitSetterGetterRefExpr>(E))
DiagID = diag::warn_unused_property_expr;
+ if (const CXXExprWithTemporaries *Temps = dyn_cast<CXXExprWithTemporaries>(E))
+ E = Temps->getSubExpr();
+ if (const CXXZeroInitValueExpr *Zero = dyn_cast<CXXZeroInitValueExpr>(E)) {
+ if (const RecordType *RecordT = Zero->getType()->getAs<RecordType>())
+ if (CXXRecordDecl *RecordD = dyn_cast<CXXRecordDecl>(RecordT->getDecl()))
+ if (!RecordD->hasTrivialDestructor())
+ return;
+ }
+
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
// If the callee has attribute pure, const, or warn_unused_result, warn with
// a more specific message to make it clear what is happening.
@@ -370,6 +379,22 @@ static bool CmpCaseVals(const std::pair<llvm::APSInt, CaseStmt*>& lhs,
return false;
}
+/// CmpEnumVals - Comparison predicate for sorting enumeration values.
+///
+static bool CmpEnumVals(const std::pair<llvm::APSInt, EnumConstantDecl*>& lhs,
+ const std::pair<llvm::APSInt, EnumConstantDecl*>& rhs)
+{
+ return lhs.first < rhs.first;
+}
+
+/// EqEnumVals - Comparison preficate for uniqing enumeration values.
+///
+static bool EqEnumVals(const std::pair<llvm::APSInt, EnumConstantDecl*>& lhs,
+ const std::pair<llvm::APSInt, EnumConstantDecl*>& rhs)
+{
+ return lhs.first == rhs.first;
+}
+
/// GetTypeBeforeIntegralPromotion - Returns the pre-promotion type of
/// potentially integral-promoted expression @p expr.
static QualType GetTypeBeforeIntegralPromotion(const Expr* expr) {
@@ -482,6 +507,16 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc,
return false;
}
+/// ActOnSwitchBodyError - This is called if there is an error parsing the
+/// body of the switch stmt instead of ActOnFinishSwitchStmt.
+void Sema::ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch,
+ StmtArg Body) {
+ // Keep the switch stack balanced.
+ assert(getSwitchStack().back() == (SwitchStmt*)Switch.get() &&
+ "switch stack missing push/pop!");
+ getSwitchStack().pop_back();
+}
+
Action::OwningStmtResult
Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
StmtArg Body) {
@@ -550,7 +585,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
CaseValsTy CaseVals;
// Keep track of any GNU case ranges we see. The APSInt is the low value.
- std::vector<std::pair<llvm::APSInt, CaseStmt*> > CaseRanges;
+ typedef std::vector<std::pair<llvm::APSInt, CaseStmt*> > CaseRangesTy;
+ CaseRangesTy CaseRanges;
DefaultStmt *TheDefaultStmt = 0;
@@ -713,6 +749,75 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
}
}
}
+
+ // Check to see if switch is over an Enum and handles all of its
+ // values
+ const EnumType* ET = dyn_cast<EnumType>(CondTypeBeforePromotion);
+ // If switch has default case, then ignore it.
+ if (!CaseListIsErroneous && !TheDefaultStmt && ET) {
+ const EnumDecl *ED = ET->getDecl();
+ typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy;
+ EnumValsTy EnumVals;
+
+ // Gather all enum values, set their type and sort them, allowing easier comparison
+ // with CaseVals.
+ for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin(); EDI != ED->enumerator_end(); EDI++) {
+ llvm::APSInt Val = (*EDI)->getInitVal();
+ if(Val.getBitWidth() < CondWidth)
+ Val.extend(CondWidth);
+ Val.setIsSigned(CondIsSigned);
+ EnumVals.push_back(std::make_pair(Val, (*EDI)));
+ }
+ std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
+ EnumValsTy::iterator EIend = std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
+ // See which case values aren't in enum
+ EnumValsTy::const_iterator EI = EnumVals.begin();
+ for (CaseValsTy::const_iterator CI = CaseVals.begin(); CI != CaseVals.end(); CI++) {
+ while (EI != EIend && EI->first < CI->first)
+ EI++;
+ if (EI == EIend || EI->first > CI->first)
+ Diag(CI->second->getLHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName();
+ }
+ // See which of case ranges aren't in enum
+ EI = EnumVals.begin();
+ for (CaseRangesTy::const_iterator RI = CaseRanges.begin(); RI != CaseRanges.end() && EI != EIend; RI++) {
+ while (EI != EIend && EI->first < RI->first)
+ EI++;
+
+ if (EI == EIend || EI->first != RI->first) {
+ Diag(RI->second->getLHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName();
+ }
+
+ llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
+ while (EI != EIend && EI->first < Hi)
+ EI++;
+ if (EI == EIend || EI->first != Hi)
+ Diag(RI->second->getRHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName();
+ }
+ //Check which enum vals aren't in switch
+ CaseValsTy::const_iterator CI = CaseVals.begin();
+ CaseRangesTy::const_iterator RI = CaseRanges.begin();
+ EI = EnumVals.begin();
+ for (; EI != EIend; EI++) {
+ //Drop unneeded case values
+ llvm::APSInt CIVal;
+ while (CI != CaseVals.end() && CI->first < EI->first)
+ CI++;
+
+ if (CI != CaseVals.end() && CI->first == EI->first)
+ continue;
+
+ //Drop unneeded case ranges
+ for (; RI != CaseRanges.end(); RI++) {
+ llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
+ if (EI->first <= Hi)
+ break;
+ }
+
+ if (RI == CaseRanges.end() || EI->first < RI->first)
+ Diag(CondExpr->getExprLoc(), diag::warn_missing_cases) << EI->second->getDeclName();
+ }
+ }
}
// FIXME: If the case list was broken is some way, we don't have a good system
@@ -863,7 +968,7 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
<< FirstType << First->getSourceRange();
}
if (Second) {
- DefaultFunctionArrayConversion(Second);
+ DefaultFunctionArrayLvalueConversion(Second);
QualType SecondType = Second->getType();
if (!SecondType->isObjCObjectPointerType())
Diag(ForLoc, diag::err_collection_expr_type)
@@ -896,10 +1001,10 @@ Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc,
Expr* E = DestExp.takeAs<Expr>();
if (!E->isTypeDependent()) {
QualType ETy = E->getType();
+ QualType DestTy = Context.getPointerType(Context.VoidTy.withConst());
AssignConvertType ConvTy =
- CheckSingleAssignmentConstraints(Context.VoidPtrTy, E);
- if (DiagnoseAssignmentResult(ConvTy, StarLoc, Context.VoidPtrTy, ETy,
- E, AA_Passing))
+ CheckSingleAssignmentConstraints(DestTy, E);
+ if (DiagnoseAssignmentResult(ConvTy, StarLoc, DestTy, ETy, E, AA_Passing))
return StmtError();
}
return Owned(new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E));
@@ -937,7 +1042,7 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (RetValExp) {
// Don't call UsualUnaryConversions(), since we don't want to do
// integer promotions here.
- DefaultFunctionArrayConversion(RetValExp);
+ DefaultFunctionArrayLvalueConversion(RetValExp);
CurBlock->ReturnType = RetValExp->getType();
if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) {
// We have to remove a 'const' added to copied-in variable which was
@@ -981,11 +1086,19 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// In C++ the return statement is handled via a copy initialization.
// the C version of which boils down to CheckSingleAssignmentConstraints.
- // FIXME: Leaks RetValExp.
- if (PerformCopyInitialization(RetValExp, FnRetType, AA_Returning))
+ OwningExprResult Res = PerformCopyInitialization(
+ InitializedEntity::InitializeResult(ReturnLoc,
+ FnRetType),
+ SourceLocation(),
+ Owned(RetValExp));
+ if (Res.isInvalid()) {
+ // FIXME: Cleanup temporaries here, anyway?
return StmtError();
-
- if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+ }
+
+ RetValExp = Res.takeAs<Expr>();
+ if (RetValExp)
+ CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
}
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
@@ -1025,7 +1138,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
QualType FnRetType;
if (const FunctionDecl *FD = getCurFunctionDecl()) {
FnRetType = FD->getResultType();
- if (FD->hasAttr<NoReturnAttr>())
+ if (FD->hasAttr<NoReturnAttr>() ||
+ FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
<< getCurFunctionOrMethodDecl()->getDeclName();
} else if (ObjCMethodDecl *MD = getCurMethodDecl())
@@ -1121,6 +1235,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
/// This method checks to see if the argument is an acceptable l-value and
/// returns false if it is a case we can handle.
static bool CheckAsmLValue(const Expr *E, Sema &S) {
+ // Type dependent expressions will be checked during instantiation.
+ if (E->isTypeDependent())
+ return false;
+
if (E->isLvalue(S.Context) == Expr::LV_Valid)
return false; // Cool, this is an lvalue.
@@ -1148,7 +1266,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
bool IsVolatile,
unsigned NumOutputs,
unsigned NumInputs,
- std::string *Names,
+ IdentifierInfo **Names,
MultiExprArg constraints,
MultiExprArg exprs,
ExprArg asmString,
@@ -1175,9 +1293,11 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
<< Literal->getSourceRange());
- TargetInfo::ConstraintInfo Info(Literal->getStrData(),
- Literal->getByteLength(),
- Names[i]);
+ llvm::StringRef OutputName;
+ if (Names[i])
+ OutputName = Names[i]->getName();
+
+ TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName);
if (!Context.Target.validateOutputConstraint(Info))
return StmtError(Diag(Literal->getLocStart(),
diag::err_asm_invalid_output_constraint)
@@ -1202,9 +1322,11 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
<< Literal->getSourceRange());
- TargetInfo::ConstraintInfo Info(Literal->getStrData(),
- Literal->getByteLength(),
- Names[i]);
+ llvm::StringRef InputName;
+ if (Names[i])
+ InputName = Names[i]->getName();
+
+ TargetInfo::ConstraintInfo Info(Literal->getString(), InputName);
if (!Context.Target.validateInputConstraint(OutputConstraintInfos.data(),
NumOutputs, Info)) {
return StmtError(Diag(Literal->getLocStart(),
@@ -1232,7 +1354,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
}
}
- DefaultFunctionArrayConversion(Exprs[i]);
+ DefaultFunctionArrayLvalueConversion(Exprs[i]);
InputConstraintInfos.push_back(Info);
}
@@ -1244,11 +1366,9 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
<< Literal->getSourceRange());
- std::string Clobber(Literal->getStrData(),
- Literal->getStrData() +
- Literal->getByteLength());
+ llvm::StringRef Clobber = Literal->getString();
- if (!Context.Target.isValidGCCRegisterName(Clobber.c_str()))
+ if (!Context.Target.isValidGCCRegisterName(Clobber))
return StmtError(Diag(Literal->getLocStart(),
diag::err_asm_unknown_register_name) << Clobber);
}
@@ -1258,9 +1378,9 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
asmString.release();
clobbers.release();
AsmStmt *NS =
- new (Context) AsmStmt(AsmLoc, IsSimple, IsVolatile, MSAsm, NumOutputs,
- NumInputs, Names, Constraints, Exprs, AsmString,
- NumClobbers, Clobbers, RParenLoc);
+ new (Context) AsmStmt(Context, AsmLoc, IsSimple, IsVolatile, MSAsm,
+ NumOutputs, NumInputs, Names, Constraints, Exprs,
+ AsmString, NumClobbers, Clobbers, RParenLoc);
// Validate the asm string, ensuring it makes sense given the operands we
// have.
llvm::SmallVector<AsmStmt::AsmStringPiece, 8> Pieces;
@@ -1527,7 +1647,7 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, StmtArg TryBlock,
CurFunctionNeedsScopeChecking = true;
RawHandlers.release();
- return Owned(new (Context) CXXTryStmt(TryLoc,
- static_cast<Stmt*>(TryBlock.release()),
- Handlers, NumHandlers));
+ return Owned(CXXTryStmt::Create(Context, TryLoc,
+ static_cast<Stmt*>(TryBlock.release()),
+ Handlers, NumHandlers));
}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 00401560c6a0..10e411f5825a 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -823,7 +823,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Check for redefinition of this class template.
if (TUK == TUK_Definition) {
- if (TagDecl *Def = PrevRecordDecl->getDefinition(Context)) {
+ if (TagDecl *Def = PrevRecordDecl->getDefinition()) {
Diag(NameLoc, diag::err_redefinition) << Name;
Diag(Def->getLocation(), diag::note_previous_definition);
// FIXME: Would it make sense to try to "forget" the previous
@@ -1235,18 +1235,14 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
// such a member, the member declaration shall be preceded by a
// template<> for each enclosing class template that is
// explicitly specialized.
- // We interpret this as forbidding typedefs of template
- // specializations in the scope specifiers of out-of-line decls.
- if (const TypedefType *TT = dyn_cast<TypedefType>(T)) {
- const Type *UnderlyingT = TT->LookThroughTypedefs().getTypePtr();
- if (isa<TemplateSpecializationType>(UnderlyingT))
- // FIXME: better source location information.
- Diag(DeclStartLoc, diag::err_typedef_in_def_scope) << QualType(T,0);
- T = UnderlyingT;
- }
+ //
+ // Following the existing practice of GNU and EDG, we allow a typedef of a
+ // template specialization type.
+ if (const TypedefType *TT = dyn_cast<TypedefType>(T))
+ T = TT->LookThroughTypedefs().getTypePtr();
if (const TemplateSpecializationType *SpecType
- = dyn_cast<TemplateSpecializationType>(T)) {
+ = dyn_cast<TemplateSpecializationType>(T)) {
TemplateDecl *Template = SpecType->getTemplateName().getAsTemplateDecl();
if (!Template)
continue; // FIXME: should this be an error? probably...
@@ -1525,17 +1521,19 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
Qualifier = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
QualifierRange = SS.getRange();
}
+
+ // We don't want lookup warnings at this point.
+ R.suppressDiagnostics();
bool Dependent
= UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(),
&TemplateArgs);
UnresolvedLookupExpr *ULE
- = UnresolvedLookupExpr::Create(Context, Dependent,
+ = UnresolvedLookupExpr::Create(Context, Dependent, R.getNamingClass(),
Qualifier, QualifierRange,
R.getLookupName(), R.getNameLoc(),
RequiresADL, TemplateArgs);
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
- ULE->addDecl(*I);
+ ULE->addDecls(R.begin(), R.end());
return Owned(ULE);
}
@@ -2305,7 +2303,17 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
} else
DRE = dyn_cast<DeclRefExpr>(Arg);
- if (!DRE || !isa<ValueDecl>(DRE->getDecl()))
+ if (!DRE)
+ return Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_not_decl_ref)
+ << Arg->getSourceRange();
+
+ // Stop checking the precise nature of the argument if it is value dependent,
+ // it should be checked when instantiated.
+ if (Arg->isValueDependent())
+ return false;
+
+ if (!isa<ValueDecl>(DRE->getDecl()))
return Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_object_or_func_form)
<< Arg->getSourceRange();
@@ -2324,7 +2332,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
// Functions must have external linkage.
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(DRE->getDecl())) {
- if (Func->getLinkage() != NamedDecl::ExternalLinkage) {
+ if (!isExternalLinkage(Func->getLinkage())) {
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_function_not_extern)
<< Func << Arg->getSourceRange();
@@ -2339,7 +2347,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
}
if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
- if (Var->getLinkage() != NamedDecl::ExternalLinkage) {
+ if (!isExternalLinkage(Var->getLinkage())) {
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_object_not_extern)
<< Var << Arg->getSourceRange();
@@ -2656,9 +2664,13 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- if (Entity)
- Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
- Converted = TemplateArgument(Entity);
+ if (Arg->isValueDependent()) {
+ Converted = TemplateArgument(Arg);
+ } else {
+ if (Entity)
+ Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
+ Converted = TemplateArgument(Entity);
+ }
return false;
}
@@ -2696,9 +2708,13 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- if (Entity)
- Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
- Converted = TemplateArgument(Entity);
+ if (Arg->isValueDependent()) {
+ Converted = TemplateArgument(Arg);
+ } else {
+ if (Entity)
+ Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
+ Converted = TemplateArgument(Entity);
+ }
return false;
}
@@ -2712,7 +2728,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
assert(ParamRefType->getPointeeType()->isObjectType() &&
"Only object references allowed here");
- if (!Context.hasSameUnqualifiedType(ParamRefType->getPointeeType(), ArgType)) {
+ QualType ReferredType = ParamRefType->getPointeeType();
+ if (!Context.hasSameUnqualifiedType(ReferredType, ArgType)) {
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_no_ref_bind)
<< InstantiatedParamType << Arg->getType()
@@ -2722,7 +2739,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
unsigned ParamQuals
- = Context.getCanonicalType(ParamType).getCVRQualifiers();
+ = Context.getCanonicalType(ReferredType).getCVRQualifiers();
unsigned ArgQuals = Context.getCanonicalType(ArgType).getCVRQualifiers();
if ((ParamQuals | ArgQuals) != ParamQuals) {
@@ -2738,8 +2755,12 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
- Converted = TemplateArgument(Entity);
+ if (Arg->isValueDependent()) {
+ Converted = TemplateArgument(Arg);
+ } else {
+ Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
+ Converted = TemplateArgument(Entity);
+ }
return false;
}
@@ -3375,12 +3396,23 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// FIXME: Diagnose friend partial specializations
- // FIXME: Template parameter list matters, too
- ClassTemplatePartialSpecializationDecl::Profile(ID,
- Converted.getFlatArguments(),
- Converted.flatSize(),
- Context);
- } else
+ if (!Name.isDependent() &&
+ !TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs.getArgumentArray(),
+ TemplateArgs.size())) {
+ Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
+ << ClassTemplate->getDeclName();
+ isPartialSpecialization = false;
+ } else {
+ // FIXME: Template parameter list matters, too
+ ClassTemplatePartialSpecializationDecl::Profile(ID,
+ Converted.getFlatArguments(),
+ Converted.flatSize(),
+ Context);
+ }
+ }
+
+ if (!isPartialSpecialization)
ClassTemplateSpecializationDecl::Profile(ID,
Converted.getFlatArguments(),
Converted.flatSize(),
@@ -3410,7 +3442,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
QualType CanonType;
if (PrevDecl &&
(PrevDecl->getSpecializationKind() == TSK_Undeclared ||
- TUK == TUK_Friend)) {
+ TUK == TUK_Friend)) {
// Since the only prior class template specialization with these
// arguments was referenced but not declared, or we're only
// referencing this specialization as a friend, reuse that
@@ -3423,8 +3455,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
} else if (isPartialSpecialization) {
// Build the canonical type that describes the converted template
// arguments of the class template partial specialization.
- CanonType = Context.getTemplateSpecializationType(
- TemplateName(ClassTemplate),
+ TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
+ CanonType = Context.getTemplateSpecializationType(CanonTemplate,
Converted.getFlatArguments(),
Converted.flatSize());
@@ -3532,7 +3564,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// Check that this isn't a redefinition of this specialization.
if (TUK == TUK_Definition) {
- if (RecordDecl *Def = Specialization->getDefinition(Context)) {
+ if (RecordDecl *Def = Specialization->getDefinition()) {
SourceRange Range(TemplateNameLoc, RAngleLoc);
Diag(TemplateNameLoc, diag::err_redefinition)
<< Context.getTypeDeclType(Specialization) << Range;
@@ -3619,6 +3651,16 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
return DeclPtrTy();
}
+/// \brief Strips various properties off an implicit instantiation
+/// that has just been explicitly specialized.
+static void StripImplicitInstantiation(NamedDecl *D) {
+ D->invalidateAttrs();
+
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ FD->setInlineSpecified(false);
+ }
+}
+
/// \brief Diagnose cases where we have an explicit template specialization
/// before/after an explicit template instantiation, producing diagnostics
/// for those cases where they are required and determining whether the
@@ -3669,6 +3711,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
if (PrevPointOfInstantiation.isInvalid()) {
// The declaration itself has not actually been instantiated, so it is
// still okay to specialize it.
+ StripImplicitInstantiation(PrevDecl);
return false;
}
// Fall through
@@ -3817,8 +3860,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
LookupResult &Previous) {
// The set of function template specializations that could match this
// explicit function template specialization.
- typedef llvm::SmallVector<FunctionDecl *, 8> CandidateSet;
- CandidateSet Candidates;
+ UnresolvedSet<8> Candidates;
DeclContext *FDLookupContext = FD->getDeclContext()->getLookupContext();
for (LookupResult::iterator I = Previous.begin(), E = Previous.end();
@@ -3837,7 +3879,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// Perform template argument deduction to determine whether we may be
// specializing this template.
// FIXME: It is somewhat wasteful to build
- TemplateDeductionInfo Info(Context);
+ TemplateDeductionInfo Info(Context, FD->getLocation());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult TDK
= DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs,
@@ -3851,22 +3893,24 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
}
// Record this candidate.
- Candidates.push_back(Specialization);
+ Candidates.addDecl(Specialization, I.getAccess());
}
}
// Find the most specialized function template.
- FunctionDecl *Specialization = getMostSpecialized(Candidates.data(),
- Candidates.size(),
- TPOC_Other,
- FD->getLocation(),
+ UnresolvedSetIterator Result
+ = getMostSpecialized(Candidates.begin(), Candidates.end(),
+ TPOC_Other, FD->getLocation(),
PartialDiagnostic(diag::err_function_template_spec_no_match)
<< FD->getDeclName(),
PartialDiagnostic(diag::err_function_template_spec_ambiguous)
<< FD->getDeclName() << (ExplicitTemplateArgs != 0),
PartialDiagnostic(diag::note_function_template_spec_matched));
- if (!Specialization)
+ if (Result == Candidates.end())
return true;
+
+ // Ignore access information; it doesn't figure into redeclaration checking.
+ FunctionDecl *Specialization = cast<FunctionDecl>(*Result);
// FIXME: Check if the prior specialization has a point of instantiation.
// If so, we have run afoul of .
@@ -3887,15 +3931,15 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
FunctionTemplateSpecializationInfo *SpecInfo
= Specialization->getTemplateSpecializationInfo();
assert(SpecInfo && "Function template specialization info missing?");
- if (SpecInfo->getPointOfInstantiation().isValid()) {
- Diag(FD->getLocation(), diag::err_specialization_after_instantiation)
- << FD;
- Diag(SpecInfo->getPointOfInstantiation(),
- diag::note_instantiation_required_here)
- << (Specialization->getTemplateSpecializationKind()
- != TSK_ImplicitInstantiation);
+
+ bool SuppressNew = false;
+ if (CheckSpecializationInstantiationRedecl(FD->getLocation(),
+ TSK_ExplicitSpecialization,
+ Specialization,
+ SpecInfo->getTemplateSpecializationKind(),
+ SpecInfo->getPointOfInstantiation(),
+ SuppressNew))
return true;
- }
// Mark the prior declaration as an explicit specialization, so that later
// clients know that this is an explicit specialization.
@@ -3904,8 +3948,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// Turn the given function declaration into a function template
// specialization, with the template arguments from the previous
// specialization.
- FD->setFunctionTemplateSpecialization(Context,
- Specialization->getPrimaryTemplate(),
+ FD->setFunctionTemplateSpecialization(Specialization->getPrimaryTemplate(),
new (Context) TemplateArgumentList(
*Specialization->getTemplateSpecializationArgs()),
/*InsertPos=*/0,
@@ -3997,14 +4040,15 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
// instantiation to take place, in every translation unit in which such a
// use occurs; no diagnostic is required.
assert(MSInfo && "Member specialization info missing?");
- if (MSInfo->getPointOfInstantiation().isValid()) {
- Diag(Member->getLocation(), diag::err_specialization_after_instantiation)
- << Member;
- Diag(MSInfo->getPointOfInstantiation(),
- diag::note_instantiation_required_here)
- << (MSInfo->getTemplateSpecializationKind() != TSK_ImplicitInstantiation);
+
+ bool SuppressNew = false;
+ if (CheckSpecializationInstantiationRedecl(Member->getLocation(),
+ TSK_ExplicitSpecialization,
+ Instantiation,
+ MSInfo->getTemplateSpecializationKind(),
+ MSInfo->getPointOfInstantiation(),
+ SuppressNew))
return true;
- }
// Check the scope of this explicit specialization.
if (CheckTemplateSpecializationScope(*this,
@@ -4288,13 +4332,13 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// instantiation.
ClassTemplateSpecializationDecl *Def
= cast_or_null<ClassTemplateSpecializationDecl>(
- Specialization->getDefinition(Context));
+ Specialization->getDefinition());
if (!Def)
InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK);
// Instantiate the members of this class template specialization.
Def = cast_or_null<ClassTemplateSpecializationDecl>(
- Specialization->getDefinition(Context));
+ Specialization->getDefinition());
if (Def)
InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK);
@@ -4371,7 +4415,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// Verify that it is okay to explicitly instantiate here.
CXXRecordDecl *PrevDecl
= cast_or_null<CXXRecordDecl>(Record->getPreviousDeclaration());
- if (!PrevDecl && Record->getDefinition(Context))
+ if (!PrevDecl && Record->getDefinition())
PrevDecl = Record;
if (PrevDecl) {
MemberSpecializationInfo *MSInfo = PrevDecl->getMemberSpecializationInfo();
@@ -4388,13 +4432,13 @@ Sema::ActOnExplicitInstantiation(Scope *S,
}
CXXRecordDecl *RecordDef
- = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context));
+ = cast_or_null<CXXRecordDecl>(Record->getDefinition());
if (!RecordDef) {
// C++ [temp.explicit]p3:
// A definition of a member class of a class template shall be in scope
// at the point of an explicit instantiation of the member class.
CXXRecordDecl *Def
- = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
+ = cast_or_null<CXXRecordDecl>(Pattern->getDefinition());
if (!Def) {
Diag(TemplateLoc, diag::err_explicit_instantiation_undefined_member)
<< 0 << Record->getDeclName() << Record->getDeclContext();
@@ -4407,7 +4451,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
TSK))
return true;
- RecordDef = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context));
+ RecordDef = cast_or_null<CXXRecordDecl>(Record->getDefinition());
if (!RecordDef)
return true;
}
@@ -4568,7 +4612,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// A member function [...] of a class template can be explicitly
// instantiated from the member definition associated with its class
// template.
- llvm::SmallVector<FunctionDecl *, 8> Matches;
+ UnresolvedSet<8> Matches;
for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
P != PEnd; ++P) {
NamedDecl *Prev = *P;
@@ -4577,7 +4621,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (Context.hasSameUnqualifiedType(Method->getType(), R)) {
Matches.clear();
- Matches.push_back(Method);
+ Matches.addDecl(Method, P.getAccess());
if (Method->getTemplateSpecializationKind() == TSK_Undeclared)
break;
}
@@ -4588,7 +4632,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (!FunTmpl)
continue;
- TemplateDeductionInfo Info(Context);
+ TemplateDeductionInfo Info(Context, D.getIdentifierLoc());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult TDK
= DeduceTemplateArguments(FunTmpl,
@@ -4599,19 +4643,22 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
continue;
}
- Matches.push_back(Specialization);
+ Matches.addDecl(Specialization, P.getAccess());
}
// Find the most specialized function template specialization.
- FunctionDecl *Specialization
- = getMostSpecialized(Matches.data(), Matches.size(), TPOC_Other,
+ UnresolvedSetIterator Result
+ = getMostSpecialized(Matches.begin(), Matches.end(), TPOC_Other,
D.getIdentifierLoc(),
PartialDiagnostic(diag::err_explicit_instantiation_not_known) << Name,
PartialDiagnostic(diag::err_explicit_instantiation_ambiguous) << Name,
PartialDiagnostic(diag::note_explicit_instantiation_candidate));
- if (!Specialization)
+ if (Result == Matches.end())
return true;
+
+ // Ignore access control bits, we don't need them for redeclaration checking.
+ FunctionDecl *Specialization = cast<FunctionDecl>(*Result);
if (Specialization->getTemplateSpecializationKind() == TSK_Undeclared) {
Diag(D.getIdentifierLoc(),
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 7b433e901e33..df4d4a828d48 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -49,7 +49,7 @@ namespace clang {
using namespace clang;
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
const TemplateArgument &Param,
const TemplateArgument &Arg,
@@ -72,7 +72,7 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) {
/// \brief Deduce the value of the given non-type template parameter
/// from the given constant.
static Sema::TemplateDeductionResult
-DeduceNonTypeTemplateArgument(ASTContext &Context,
+DeduceNonTypeTemplateArgument(Sema &S,
NonTypeTemplateParmDecl *NTTP,
llvm::APSInt Value,
Sema::TemplateDeductionInfo &Info,
@@ -84,7 +84,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context,
QualType T = NTTP->getType();
// FIXME: Make sure we didn't overflow our data type!
- unsigned AllowedBits = Context.getTypeSize(T);
+ unsigned AllowedBits = S.Context.getTypeSize(T);
if (Value.getBitWidth() != AllowedBits)
Value.extOrTrunc(AllowedBits);
Value.setIsSigned(T->isSignedIntegerType());
@@ -126,7 +126,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context,
///
/// \returns true if deduction succeeded, false otherwise.
static Sema::TemplateDeductionResult
-DeduceNonTypeTemplateArgument(ASTContext &Context,
+DeduceNonTypeTemplateArgument(Sema &S,
NonTypeTemplateParmDecl *NTTP,
Expr *Value,
Sema::TemplateDeductionInfo &Info,
@@ -152,8 +152,8 @@ DeduceNonTypeTemplateArgument(ASTContext &Context,
if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Expression) {
// Compare the expressions for equality
llvm::FoldingSetNodeID ID1, ID2;
- Deduced[NTTP->getIndex()].getAsExpr()->Profile(ID1, Context, true);
- Value->Profile(ID2, Context, true);
+ Deduced[NTTP->getIndex()].getAsExpr()->Profile(ID1, S.Context, true);
+ Value->Profile(ID2, S.Context, true);
if (ID1 == ID2)
return Sema::TDK_Success;
@@ -169,7 +169,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context,
///
/// \returns true if deduction succeeded, false otherwise.
static Sema::TemplateDeductionResult
-DeduceNonTypeTemplateArgument(ASTContext &Context,
+DeduceNonTypeTemplateArgument(Sema &S,
NonTypeTemplateParmDecl *NTTP,
Decl *D,
Sema::TemplateDeductionInfo &Info,
@@ -202,7 +202,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context,
}
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
TemplateName Param,
TemplateName Arg,
@@ -221,13 +221,13 @@ DeduceTemplateArguments(ASTContext &Context,
TemplateArgument &ExistingArg = Deduced[TempParam->getIndex()];
if (ExistingArg.isNull()) {
// This is the first deduction for this template template parameter.
- ExistingArg = TemplateArgument(Context.getCanonicalTemplateName(Arg));
+ ExistingArg = TemplateArgument(S.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))
+ if (S.Context.hasSameTemplateName(ExistingArg.getAsTemplate(), Arg))
return Sema::TDK_Success;
// Inconsistent deduction.
@@ -238,7 +238,7 @@ DeduceTemplateArguments(ASTContext &Context,
}
// Verify that the two template names are equivalent.
- if (Context.hasSameTemplateName(Param, Arg))
+ if (S.Context.hasSameTemplateName(Param, Arg))
return Sema::TDK_Success;
// Mismatch of non-dependent template parameter to argument.
@@ -250,7 +250,7 @@ DeduceTemplateArguments(ASTContext &Context,
/// \brief Deduce the template arguments by comparing the template parameter
/// type (which is a template-id) with the template argument type.
///
-/// \param Context the AST context in which this deduction occurs.
+/// \param S the Sema
///
/// \param TemplateParams the template parameters that we are deducing
///
@@ -266,7 +266,7 @@ DeduceTemplateArguments(ASTContext &Context,
/// "success" result means that template argument deduction has not yet failed,
/// but it may still fail, later, for other reasons.
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
const TemplateSpecializationType *Param,
QualType Arg,
@@ -279,7 +279,7 @@ DeduceTemplateArguments(ASTContext &Context,
= dyn_cast<TemplateSpecializationType>(Arg)) {
// Perform template argument deduction for the template name.
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
+ = DeduceTemplateArguments(S, TemplateParams,
Param->getTemplateName(),
SpecArg->getTemplateName(),
Info, Deduced))
@@ -291,7 +291,7 @@ DeduceTemplateArguments(ASTContext &Context,
unsigned NumArgs = std::min(SpecArg->getNumArgs(), Param->getNumArgs());
for (unsigned I = 0; I != NumArgs; ++I)
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
+ = DeduceTemplateArguments(S, TemplateParams,
Param->getArg(I),
SpecArg->getArg(I),
Info, Deduced))
@@ -314,7 +314,7 @@ DeduceTemplateArguments(ASTContext &Context,
// Perform template argument deduction for the template name.
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context,
+ = DeduceTemplateArguments(S,
TemplateParams,
Param->getTemplateName(),
TemplateName(SpecArg->getSpecializedTemplate()),
@@ -328,7 +328,7 @@ DeduceTemplateArguments(ASTContext &Context,
for (unsigned I = 0; I != NumArgs; ++I)
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
+ = DeduceTemplateArguments(S, TemplateParams,
Param->getArg(I),
ArgArgs.get(I),
Info, Deduced))
@@ -340,7 +340,7 @@ DeduceTemplateArguments(ASTContext &Context,
/// \brief Deduce the template arguments by comparing the parameter type and
/// the argument type (C++ [temp.deduct.type]).
///
-/// \param Context the AST context in which this deduction occurs.
+/// \param S the semantic analysis object within which we are deducing
///
/// \param TemplateParams the template parameters that we are deducing
///
@@ -359,7 +359,7 @@ DeduceTemplateArguments(ASTContext &Context,
/// "success" result means that template argument deduction has not yet failed,
/// but it may still fail, later, for other reasons.
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
QualType ParamIn, QualType ArgIn,
Sema::TemplateDeductionInfo &Info,
@@ -367,8 +367,8 @@ DeduceTemplateArguments(ASTContext &Context,
unsigned TDF) {
// We only want to look at the canonical types, since typedefs and
// sugar are not part of template argument deduction.
- QualType Param = Context.getCanonicalType(ParamIn);
- QualType Arg = Context.getCanonicalType(ArgIn);
+ QualType Param = S.Context.getCanonicalType(ParamIn);
+ QualType Arg = S.Context.getCanonicalType(ArgIn);
// C++0x [temp.deduct.call]p4 bullet 1:
// - If the original P is a reference type, the deduced A (i.e., the type
@@ -376,10 +376,10 @@ DeduceTemplateArguments(ASTContext &Context,
// transformed A.
if (TDF & TDF_ParamWithReferenceType) {
Qualifiers Quals;
- QualType UnqualParam = Context.getUnqualifiedArrayType(Param, Quals);
+ QualType UnqualParam = S.Context.getUnqualifiedArrayType(Param, Quals);
Quals.setCVRQualifiers(Quals.getCVRQualifiers() &
Arg.getCVRQualifiersThroughArrayTypes());
- Param = Context.getQualifiedType(UnqualParam, Quals);
+ Param = S.Context.getQualifiedType(UnqualParam, Quals);
}
// If the parameter type is not dependent, there is nothing to deduce.
@@ -409,9 +409,9 @@ DeduceTemplateArguments(ASTContext &Context,
// FIXME: address spaces, ObjC GC qualifiers
if (isa<ArrayType>(Arg)) {
Qualifiers Quals;
- Arg = Context.getUnqualifiedArrayType(Arg, Quals);
+ Arg = S.Context.getUnqualifiedArrayType(Arg, Quals);
if (Quals) {
- Arg = Context.getQualifiedType(Arg, Quals);
+ Arg = S.Context.getQualifiedType(Arg, Quals);
RecanonicalizeArg = true;
}
}
@@ -426,11 +426,11 @@ DeduceTemplateArguments(ASTContext &Context,
}
assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0");
- assert(Arg != Context.OverloadTy && "Unresolved overloaded function");
+ assert(Arg != S.Context.OverloadTy && "Unresolved overloaded function");
QualType DeducedType = Arg;
DeducedType.removeCVRQualifiers(Param.getCVRQualifiers());
if (RecanonicalizeArg)
- DeducedType = Context.getCanonicalType(DeducedType);
+ DeducedType = S.Context.getCanonicalType(DeducedType);
if (Deduced[Index].isNull())
Deduced[Index] = TemplateArgument(DeducedType);
@@ -479,7 +479,7 @@ DeduceTemplateArguments(ASTContext &Context,
return Sema::TDK_NonDeducedMismatch;
unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass);
- return DeduceTemplateArguments(Context, TemplateParams,
+ return DeduceTemplateArguments(S, TemplateParams,
cast<PointerType>(Param)->getPointeeType(),
PointerArg->getPointeeType(),
Info, Deduced, SubTDF);
@@ -491,7 +491,7 @@ DeduceTemplateArguments(ASTContext &Context,
if (!ReferenceArg)
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context, TemplateParams,
+ return DeduceTemplateArguments(S, TemplateParams,
cast<LValueReferenceType>(Param)->getPointeeType(),
ReferenceArg->getPointeeType(),
Info, Deduced, 0);
@@ -503,7 +503,7 @@ DeduceTemplateArguments(ASTContext &Context,
if (!ReferenceArg)
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context, TemplateParams,
+ return DeduceTemplateArguments(S, TemplateParams,
cast<RValueReferenceType>(Param)->getPointeeType(),
ReferenceArg->getPointeeType(),
Info, Deduced, 0);
@@ -512,12 +512,12 @@ DeduceTemplateArguments(ASTContext &Context,
// T [] (implied, but not stated explicitly)
case Type::IncompleteArray: {
const IncompleteArrayType *IncompleteArrayArg =
- Context.getAsIncompleteArrayType(Arg);
+ S.Context.getAsIncompleteArrayType(Arg);
if (!IncompleteArrayArg)
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context, TemplateParams,
- Context.getAsIncompleteArrayType(Param)->getElementType(),
+ return DeduceTemplateArguments(S, TemplateParams,
+ S.Context.getAsIncompleteArrayType(Param)->getElementType(),
IncompleteArrayArg->getElementType(),
Info, Deduced, 0);
}
@@ -525,16 +525,16 @@ DeduceTemplateArguments(ASTContext &Context,
// T [integer-constant]
case Type::ConstantArray: {
const ConstantArrayType *ConstantArrayArg =
- Context.getAsConstantArrayType(Arg);
+ S.Context.getAsConstantArrayType(Arg);
if (!ConstantArrayArg)
return Sema::TDK_NonDeducedMismatch;
const ConstantArrayType *ConstantArrayParm =
- Context.getAsConstantArrayType(Param);
+ S.Context.getAsConstantArrayType(Param);
if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize())
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context, TemplateParams,
+ return DeduceTemplateArguments(S, TemplateParams,
ConstantArrayParm->getElementType(),
ConstantArrayArg->getElementType(),
Info, Deduced, 0);
@@ -542,15 +542,15 @@ DeduceTemplateArguments(ASTContext &Context,
// type [i]
case Type::DependentSizedArray: {
- const ArrayType *ArrayArg = Context.getAsArrayType(Arg);
+ const ArrayType *ArrayArg = S.Context.getAsArrayType(Arg);
if (!ArrayArg)
return Sema::TDK_NonDeducedMismatch;
// Check the element type of the arrays
const DependentSizedArrayType *DependentArrayParm
- = Context.getAsDependentSizedArrayType(Param);
+ = S.Context.getAsDependentSizedArrayType(Param);
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
+ = DeduceTemplateArguments(S, TemplateParams,
DependentArrayParm->getElementType(),
ArrayArg->getElementType(),
Info, Deduced, 0))
@@ -569,12 +569,12 @@ DeduceTemplateArguments(ASTContext &Context,
if (const ConstantArrayType *ConstantArrayArg
= dyn_cast<ConstantArrayType>(ArrayArg)) {
llvm::APSInt Size(ConstantArrayArg->getSize());
- return DeduceNonTypeTemplateArgument(Context, NTTP, Size,
+ return DeduceNonTypeTemplateArgument(S, NTTP, Size,
Info, Deduced);
}
if (const DependentSizedArrayType *DependentArrayArg
= dyn_cast<DependentSizedArrayType>(ArrayArg))
- return DeduceNonTypeTemplateArgument(Context, NTTP,
+ return DeduceNonTypeTemplateArgument(S, NTTP,
DependentArrayArg->getSizeExpr(),
Info, Deduced);
@@ -606,7 +606,7 @@ DeduceTemplateArguments(ASTContext &Context,
// Check return types.
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
+ = DeduceTemplateArguments(S, TemplateParams,
FunctionProtoParam->getResultType(),
FunctionProtoArg->getResultType(),
Info, Deduced, 0))
@@ -615,7 +615,7 @@ DeduceTemplateArguments(ASTContext &Context,
for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) {
// Check argument types.
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
+ = DeduceTemplateArguments(S, TemplateParams,
FunctionProtoParam->getArgType(I),
FunctionProtoArg->getArgType(I),
Info, Deduced, 0))
@@ -636,7 +636,7 @@ DeduceTemplateArguments(ASTContext &Context,
// Try to deduce template arguments from the template-id.
Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams, SpecParam, Arg,
+ = DeduceTemplateArguments(S, TemplateParams, SpecParam, Arg,
Info, Deduced);
if (Result && (TDF & TDF_DerivedClass)) {
@@ -649,7 +649,13 @@ DeduceTemplateArguments(ASTContext &Context,
// More importantly:
// These alternatives are considered only if type deduction would
// otherwise fail.
- if (const RecordType *RecordT = dyn_cast<RecordType>(Arg)) {
+ if (const RecordType *RecordT = Arg->getAs<RecordType>()) {
+ // We cannot inspect base classes as part of deduction when the type
+ // is incomplete, so either instantiate any templates necessary to
+ // complete the type, or skip over it if it cannot be completed.
+ if (S.RequireCompleteType(Info.getLocation(), Arg, 0))
+ return Result;
+
// Use data recursion to crawl through the list of base classes.
// Visited contains the set of nodes we have already visited, while
// ToVisit is our stack of records that we still need to visit.
@@ -670,7 +676,7 @@ DeduceTemplateArguments(ASTContext &Context,
// deduction from it.
if (NextT != RecordT) {
Sema::TemplateDeductionResult BaseResult
- = DeduceTemplateArguments(Context, TemplateParams, SpecParam,
+ = DeduceTemplateArguments(S, TemplateParams, SpecParam,
QualType(NextT, 0), Info, Deduced);
// If template argument deduction for this base was successful,
@@ -715,14 +721,14 @@ DeduceTemplateArguments(ASTContext &Context,
return Sema::TDK_NonDeducedMismatch;
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
+ = DeduceTemplateArguments(S, TemplateParams,
MemPtrParam->getPointeeType(),
MemPtrArg->getPointeeType(),
Info, Deduced,
TDF & TDF_IgnoreQualifiers))
return Result;
- return DeduceTemplateArguments(Context, TemplateParams,
+ return DeduceTemplateArguments(S, TemplateParams,
QualType(MemPtrParam->getClass(), 0),
QualType(MemPtrArg->getClass(), 0),
Info, Deduced, 0);
@@ -740,7 +746,7 @@ DeduceTemplateArguments(ASTContext &Context,
if (!BlockPtrArg)
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context, TemplateParams,
+ return DeduceTemplateArguments(S, TemplateParams,
BlockPtrParam->getPointeeType(),
BlockPtrArg->getPointeeType(), Info,
Deduced, 0);
@@ -761,7 +767,7 @@ DeduceTemplateArguments(ASTContext &Context,
}
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
const TemplateArgument &Param,
const TemplateArgument &Arg,
@@ -774,7 +780,7 @@ DeduceTemplateArguments(ASTContext &Context,
case TemplateArgument::Type:
if (Arg.getKind() == TemplateArgument::Type)
- return DeduceTemplateArguments(Context, TemplateParams, Param.getAsType(),
+ return DeduceTemplateArguments(S, TemplateParams, Param.getAsType(),
Arg.getAsType(), Info, Deduced, 0);
Info.FirstArg = Param;
Info.SecondArg = Arg;
@@ -782,7 +788,7 @@ DeduceTemplateArguments(ASTContext &Context,
case TemplateArgument::Template:
if (Arg.getKind() == TemplateArgument::Template)
- return DeduceTemplateArguments(Context, TemplateParams,
+ return DeduceTemplateArguments(S, TemplateParams,
Param.getAsTemplate(),
Arg.getAsTemplate(), Info, Deduced);
Info.FirstArg = Param;
@@ -826,14 +832,14 @@ DeduceTemplateArguments(ASTContext &Context,
= getDeducedParameterFromExpr(Param.getAsExpr())) {
if (Arg.getKind() == TemplateArgument::Integral)
// FIXME: Sign problems here
- return DeduceNonTypeTemplateArgument(Context, NTTP,
+ return DeduceNonTypeTemplateArgument(S, NTTP,
*Arg.getAsIntegral(),
Info, Deduced);
if (Arg.getKind() == TemplateArgument::Expression)
- return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsExpr(),
+ return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsExpr(),
Info, Deduced);
if (Arg.getKind() == TemplateArgument::Declaration)
- return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsDecl(),
+ return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsDecl(),
Info, Deduced);
assert(false && "Type/value mismatch");
@@ -854,7 +860,7 @@ DeduceTemplateArguments(ASTContext &Context,
}
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
const TemplateArgumentList &ParamList,
const TemplateArgumentList &ArgList,
@@ -863,7 +869,7 @@ DeduceTemplateArguments(ASTContext &Context,
assert(ParamList.size() == ArgList.size());
for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
+ = DeduceTemplateArguments(S, TemplateParams,
ParamList[I], ArgList[I],
Info, Deduced))
return Result;
@@ -951,7 +957,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
llvm::SmallVector<TemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(Context,
+ = ::DeduceTemplateArguments(*this,
Partial->getTemplateParameters(),
Partial->getTemplateArgs(),
TemplateArgs, Info, Deduced))
@@ -1306,6 +1312,91 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
return TDK_Success;
}
+static QualType GetTypeOfFunction(ASTContext &Context,
+ bool isAddressOfOperand,
+ FunctionDecl *Fn) {
+ if (!isAddressOfOperand) return Fn->getType();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn))
+ if (Method->isInstance())
+ return Context.getMemberPointerType(Fn->getType(),
+ Context.getTypeDeclType(Method->getParent()).getTypePtr());
+ return Context.getPointerType(Fn->getType());
+}
+
+/// Apply the deduction rules for overload sets.
+///
+/// \return the null type if this argument should be treated as an
+/// undeduced context
+static QualType
+ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
+ Expr *Arg, QualType ParamType) {
+ llvm::PointerIntPair<OverloadExpr*,1> R = OverloadExpr::find(Arg);
+
+ bool isAddressOfOperand = bool(R.getInt());
+ OverloadExpr *Ovl = R.getPointer();
+
+ // If there were explicit template arguments, we can only find
+ // something via C++ [temp.arg.explicit]p3, i.e. if the arguments
+ // unambiguously name a full specialization.
+ if (Ovl->hasExplicitTemplateArgs()) {
+ // But we can still look for an explicit specialization.
+ if (FunctionDecl *ExplicitSpec
+ = S.ResolveSingleFunctionTemplateSpecialization(Ovl))
+ return GetTypeOfFunction(S.Context, isAddressOfOperand, ExplicitSpec);
+ return QualType();
+ }
+
+ // C++0x [temp.deduct.call]p6:
+ // When P is a function type, pointer to function type, or pointer
+ // to member function type:
+
+ if (!ParamType->isFunctionType() &&
+ !ParamType->isFunctionPointerType() &&
+ !ParamType->isMemberFunctionPointerType())
+ return QualType();
+
+ QualType Match;
+ for (UnresolvedSetIterator I = Ovl->decls_begin(),
+ E = Ovl->decls_end(); I != E; ++I) {
+ NamedDecl *D = (*I)->getUnderlyingDecl();
+
+ // - If the argument is an overload set containing one or more
+ // function templates, the parameter is treated as a
+ // non-deduced context.
+ if (isa<FunctionTemplateDecl>(D))
+ return QualType();
+
+ FunctionDecl *Fn = cast<FunctionDecl>(D);
+ QualType ArgType = GetTypeOfFunction(S.Context, isAddressOfOperand, Fn);
+
+ // - If the argument is an overload set (not containing function
+ // templates), trial argument deduction is attempted using each
+ // of the members of the set. If deduction succeeds for only one
+ // of the overload set members, that member is used as the
+ // argument value for the deduction. If deduction succeeds for
+ // more than one member of the overload set the parameter is
+ // treated as a non-deduced context.
+
+ // We do all of this in a fresh context per C++0x [temp.deduct.type]p2:
+ // Type deduction is done independently for each P/A pair, and
+ // the deduced template argument values are then combined.
+ // So we do not reject deductions which were made elsewhere.
+ llvm::SmallVector<TemplateArgument, 8> Deduced(TemplateParams->size());
+ Sema::TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc());
+ unsigned TDF = 0;
+
+ Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(S, TemplateParams,
+ ParamType, ArgType,
+ Info, Deduced, TDF);
+ if (Result) continue;
+ if (!Match.isNull()) return QualType();
+ Match = ArgType;
+ }
+
+ return Match;
+}
+
/// \brief Perform template argument deduction from a function call
/// (C++ [temp.deduct.call]).
///
@@ -1384,6 +1475,15 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
QualType ParamType = ParamTypes[I];
QualType ArgType = Args[I]->getType();
+ // Overload sets usually make this parameter an undeduced
+ // context, but there are sometimes special circumstances.
+ if (ArgType == Context.OverloadTy) {
+ ArgType = ResolveOverloadForDeduction(*this, TemplateParams,
+ Args[I], ParamType);
+ if (ArgType.isNull())
+ continue;
+ }
+
// C++ [temp.deduct.call]p2:
// If P is not a reference type:
QualType CanonParamType = Context.getCanonicalType(ParamType);
@@ -1454,38 +1554,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
ParamType->getAs<PointerType>()->getPointeeType())))
TDF |= TDF_DerivedClass;
- // FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function
- // pointer parameters.
-
- if (Context.hasSameUnqualifiedType(ArgType, Context.OverloadTy)) {
- // We know that template argument deduction will fail if the argument is
- // still an overloaded function. Check whether we can resolve this
- // argument as a single function template specialization per
- // C++ [temp.arg.explicit]p3.
- FunctionDecl *ExplicitSpec
- = ResolveSingleFunctionTemplateSpecialization(Args[I]);
- Expr *ResolvedArg = 0;
- if (ExplicitSpec)
- ResolvedArg = FixOverloadedFunctionReference(Args[I], ExplicitSpec);
- if (!ExplicitSpec || !ResolvedArg) {
- // Template argument deduction fails if we can't resolve the overloaded
- // function.
- return TDK_FailedOverloadResolution;
- }
-
- // Get the type of the resolved argument, and adjust it per
- // C++0x [temp.deduct.call]p3.
- ArgType = ResolvedArg->getType();
- if (!ParamWasReference && ArgType->isFunctionType())
- ArgType = Context.getPointerType(ArgType);
- if (ArgType->isPointerType() || ArgType->isMemberPointerType())
- TDF |= TDF_IgnoreQualifiers;
-
- ResolvedArg->Destroy(Context);
- }
-
if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(Context, TemplateParams,
+ = ::DeduceTemplateArguments(*this, TemplateParams,
ParamType, ArgType, Info, Deduced,
TDF))
return Result;
@@ -1548,11 +1618,12 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// Trap any errors that might occur.
SFINAETrap Trap(*this);
+ Deduced.resize(TemplateParams->size());
+
if (!ArgFunctionType.isNull()) {
// Deduce template arguments from the function type.
- Deduced.resize(TemplateParams->size());
if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(Context, TemplateParams,
+ = ::DeduceTemplateArguments(*this, TemplateParams,
FunctionType, ArgFunctionType, Info,
Deduced, 0))
return Result;
@@ -1651,7 +1722,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
(P->isMemberPointerType() && P->isMemberPointerType()))
TDF |= TDF_IgnoreQualifiers;
if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(Context, TemplateParams,
+ = ::DeduceTemplateArguments(*this, TemplateParams,
P, A, Info, Deduced, TDF))
return Result;
@@ -1702,7 +1773,7 @@ enum DeductionQualifierComparison {
/// \brief Deduce the template arguments during partial ordering by comparing
/// the parameter type and the argument type (C++0x [temp.deduct.partial]).
///
-/// \param Context the AST context in which this deduction occurs.
+/// \param S the semantic analysis object within which we are deducing
///
/// \param TemplateParams the template parameters that we are deducing
///
@@ -1718,14 +1789,14 @@ enum DeductionQualifierComparison {
/// "success" result means that template argument deduction has not yet failed,
/// but it may still fail, later, for other reasons.
static Sema::TemplateDeductionResult
-DeduceTemplateArgumentsDuringPartialOrdering(ASTContext &Context,
+DeduceTemplateArgumentsDuringPartialOrdering(Sema &S,
TemplateParameterList *TemplateParams,
QualType ParamIn, QualType ArgIn,
Sema::TemplateDeductionInfo &Info,
llvm::SmallVectorImpl<TemplateArgument> &Deduced,
llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) {
- CanQualType Param = Context.getCanonicalType(ParamIn);
- CanQualType Arg = Context.getCanonicalType(ArgIn);
+ CanQualType Param = S.Context.getCanonicalType(ParamIn);
+ CanQualType Arg = S.Context.getCanonicalType(ArgIn);
// C++0x [temp.deduct.partial]p5:
// Before the partial ordering is done, certain transformations are
@@ -1772,7 +1843,7 @@ DeduceTemplateArgumentsDuringPartialOrdering(ASTContext &Context,
// described in 14.9.2.5. If deduction succeeds for a given type, the type
// from the argument template is considered to be at least as specialized
// as the type from the parameter template.
- return DeduceTemplateArguments(Context, TemplateParams, Param, Arg, Info,
+ return DeduceTemplateArguments(S, TemplateParams, Param, Arg, Info,
Deduced, TDF_None);
}
@@ -1785,6 +1856,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
/// \brief Determine whether the function template \p FT1 is at least as
/// specialized as \p FT2.
static bool isAtLeastAsSpecializedAs(Sema &S,
+ SourceLocation Loc,
FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
TemplatePartialOrderingContext TPOC,
@@ -1802,14 +1874,14 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
// C++0x [temp.deduct.partial]p3:
// The types used to determine the ordering depend on the context in which
// the partial ordering is done:
- Sema::TemplateDeductionInfo Info(S.Context);
+ Sema::TemplateDeductionInfo Info(S.Context, Loc);
switch (TPOC) {
case TPOC_Call: {
// - In the context of a function call, the function parameter types are
// used.
unsigned NumParams = std::min(Proto1->getNumArgs(), Proto2->getNumArgs());
for (unsigned I = 0; I != NumParams; ++I)
- if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context,
+ if (DeduceTemplateArgumentsDuringPartialOrdering(S,
TemplateParams,
Proto2->getArgType(I),
Proto1->getArgType(I),
@@ -1824,7 +1896,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
case TPOC_Conversion:
// - In the context of a call to a conversion operator, the return types
// of the conversion function templates are used.
- if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context,
+ if (DeduceTemplateArgumentsDuringPartialOrdering(S,
TemplateParams,
Proto2->getResultType(),
Proto1->getResultType(),
@@ -1837,7 +1909,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
case TPOC_Other:
// - In other contexts (14.6.6.2) the function template’s function type
// is used.
- if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context,
+ if (DeduceTemplateArgumentsDuringPartialOrdering(S,
TemplateParams,
FD2->getType(),
FD1->getType(),
@@ -1916,10 +1988,11 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
FunctionTemplateDecl *
Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
+ SourceLocation Loc,
TemplatePartialOrderingContext TPOC) {
llvm::SmallVector<DeductionQualifierComparison, 4> QualifierComparisons;
- bool Better1 = isAtLeastAsSpecializedAs(*this, FT1, FT2, TPOC, 0);
- bool Better2 = isAtLeastAsSpecializedAs(*this, FT2, FT1, TPOC,
+ bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, 0);
+ bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
&QualifierComparisons);
if (Better1 != Better2) // We have a clear winner
@@ -1987,11 +2060,11 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) {
/// \brief Retrieve the most specialized of the given function template
/// specializations.
///
-/// \param Specializations the set of function template specializations that
-/// we will be comparing.
+/// \param SpecBegin the start iterator of the function template
+/// specializations that we will be comparing.
///
-/// \param NumSpecializations the number of function template specializations in
-/// \p Specializations
+/// \param SpecEnd the end iterator of the function template
+/// specializations, paired with \p SpecBegin.
///
/// \param TPOC the partial ordering context to use to compare the function
/// template specializations.
@@ -2015,42 +2088,38 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) {
/// specialization.
///
/// \returns the most specialized function template specialization, if
-/// found. Otherwise, returns NULL.
+/// found. Otherwise, returns SpecEnd.
///
/// \todo FIXME: Consider passing in the "also-ran" candidates that failed
/// template argument deduction.
-FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations,
- unsigned NumSpecializations,
- TemplatePartialOrderingContext TPOC,
- SourceLocation Loc,
- const PartialDiagnostic &NoneDiag,
- const PartialDiagnostic &AmbigDiag,
- const PartialDiagnostic &CandidateDiag,
- unsigned *Index) {
- if (NumSpecializations == 0) {
+UnresolvedSetIterator
+Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin,
+ UnresolvedSetIterator SpecEnd,
+ TemplatePartialOrderingContext TPOC,
+ SourceLocation Loc,
+ const PartialDiagnostic &NoneDiag,
+ const PartialDiagnostic &AmbigDiag,
+ const PartialDiagnostic &CandidateDiag) {
+ if (SpecBegin == SpecEnd) {
Diag(Loc, NoneDiag);
- return 0;
+ return SpecEnd;
}
- if (NumSpecializations == 1) {
- if (Index)
- *Index = 0;
-
- return Specializations[0];
- }
-
+ if (SpecBegin + 1 == SpecEnd)
+ return SpecBegin;
// Find the function template that is better than all of the templates it
// has been compared to.
- unsigned Best = 0;
+ UnresolvedSetIterator Best = SpecBegin;
FunctionTemplateDecl *BestTemplate
- = Specializations[Best]->getPrimaryTemplate();
+ = cast<FunctionDecl>(*Best)->getPrimaryTemplate();
assert(BestTemplate && "Not a function template specialization?");
- for (unsigned I = 1; I != NumSpecializations; ++I) {
- FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate();
+ for (UnresolvedSetIterator I = SpecBegin + 1; I != SpecEnd; ++I) {
+ FunctionTemplateDecl *Challenger
+ = cast<FunctionDecl>(*I)->getPrimaryTemplate();
assert(Challenger && "Not a function template specialization?");
- if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
- TPOC),
+ if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
+ Loc, TPOC),
Challenger)) {
Best = I;
BestTemplate = Challenger;
@@ -2060,11 +2129,12 @@ FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations,
// Make sure that the "best" function template is more specialized than all
// of the others.
bool Ambiguous = false;
- for (unsigned I = 0; I != NumSpecializations; ++I) {
- FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate();
+ for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) {
+ FunctionTemplateDecl *Challenger
+ = cast<FunctionDecl>(*I)->getPrimaryTemplate();
if (I != Best &&
!isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
- TPOC),
+ Loc, TPOC),
BestTemplate)) {
Ambiguous = true;
break;
@@ -2073,22 +2143,20 @@ FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations,
if (!Ambiguous) {
// We found an answer. Return it.
- if (Index)
- *Index = Best;
- return Specializations[Best];
+ return Best;
}
// Diagnose the ambiguity.
Diag(Loc, AmbigDiag);
// FIXME: Can we order the candidates in some sane way?
- for (unsigned I = 0; I != NumSpecializations; ++I)
- Diag(Specializations[I]->getLocation(), CandidateDiag)
+ for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I)
+ Diag((*I)->getLocation(), CandidateDiag)
<< getTemplateArgumentBindingsText(
- Specializations[I]->getPrimaryTemplate()->getTemplateParameters(),
- *Specializations[I]->getTemplateSpecializationArgs());
+ cast<FunctionDecl>(*I)->getPrimaryTemplate()->getTemplateParameters(),
+ *cast<FunctionDecl>(*I)->getTemplateSpecializationArgs());
- return 0;
+ return SpecEnd;
}
/// \brief Returns the more specialized class template partial specialization
@@ -2104,7 +2172,8 @@ FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations,
ClassTemplatePartialSpecializationDecl *
Sema::getMoreSpecializedPartialSpecialization(
ClassTemplatePartialSpecializationDecl *PS1,
- ClassTemplatePartialSpecializationDecl *PS2) {
+ ClassTemplatePartialSpecializationDecl *PS2,
+ SourceLocation Loc) {
// C++ [temp.class.order]p1:
// For two class template partial specializations, the first is at least as
// specialized as the second if, given the following rewrite to two
@@ -2127,11 +2196,11 @@ Sema::getMoreSpecializedPartialSpecialization(
// template partial ordering, because class template partial specializations
// are more constrained. We know that every template parameter is deduc
llvm::SmallVector<TemplateArgument, 4> Deduced;
- Sema::TemplateDeductionInfo Info(Context);
+ Sema::TemplateDeductionInfo Info(Context, Loc);
// Determine whether PS1 is at least as specialized as PS2
Deduced.resize(PS2->getTemplateParameters()->size());
- bool Better1 = !DeduceTemplateArgumentsDuringPartialOrdering(Context,
+ bool Better1 = !DeduceTemplateArgumentsDuringPartialOrdering(*this,
PS2->getTemplateParameters(),
Context.getTypeDeclType(PS2),
Context.getTypeDeclType(PS1),
@@ -2142,7 +2211,7 @@ Sema::getMoreSpecializedPartialSpecialization(
// Determine whether PS2 is at least as specialized as PS1
Deduced.clear();
Deduced.resize(PS1->getTemplateParameters()->size());
- bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(Context,
+ bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(*this,
PS1->getTemplateParameters(),
Context.getTypeDeclType(PS1),
Context.getTypeDeclType(PS2),
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 2db0deb5098b..51e17fe472e5 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -33,9 +33,15 @@ using namespace clang;
/// arguments.
///
/// \param Innermost if non-NULL, the innermost template argument list.
+///
+/// \param RelativeToPrimary true if we should get the template
+/// arguments relative to the primary template, even when we're
+/// dealing with a specialization. This is only relevant for function
+/// template specializations.
MultiLevelTemplateArgumentList
Sema::getTemplateInstantiationArgs(NamedDecl *D,
- const TemplateArgumentList *Innermost) {
+ const TemplateArgumentList *Innermost,
+ bool RelativeToPrimary) {
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
@@ -64,8 +70,9 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
}
// Add template arguments from a function template specialization.
else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) {
- if (Function->getTemplateSpecializationKind()
- == TSK_ExplicitSpecialization)
+ if (!RelativeToPrimary &&
+ Function->getTemplateSpecializationKind()
+ == TSK_ExplicitSpecialization)
break;
if (const TemplateArgumentList *TemplateArgs
@@ -86,11 +93,13 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
if (Function->getFriendObjectKind() &&
Function->getDeclContext()->isFileContext()) {
Ctx = Function->getLexicalDeclContext();
+ RelativeToPrimary = false;
continue;
}
}
Ctx = Ctx->getParent();
+ RelativeToPrimary = false;
}
return Result;
@@ -555,6 +564,8 @@ namespace {
Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E);
Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E);
Sema::OwningExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E);
+ Sema::OwningExprResult TransformTemplateParmRefExpr(DeclRefExpr *E,
+ NonTypeTemplateParmDecl *D);
/// \brief Transforms a template type parameter type by performing
/// substitution of the corresponding template type argument.
@@ -569,6 +580,14 @@ Decl *TemplateInstantiator::TransformDecl(Decl *D) {
if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
if (TTP->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
+ // arguments left unspecified.
+ if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(),
+ TTP->getPosition()))
+ return D;
+
TemplateName Template
= TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsTemplate();
assert(!Template.isNull() && Template.getAsTemplateDecl() &&
@@ -576,14 +595,6 @@ Decl *TemplateInstantiator::TransformDecl(Decl *D) {
return Template.getAsTemplateDecl();
}
- // 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
- // arguments left unspecified.
- if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(),
- TTP->getPosition()))
- return D;
-
// Fall through to find the instantiated declaration for this template
// template parameter.
}
@@ -676,8 +687,7 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
PredefinedExpr::IdentType IT = E->getIdentType();
- unsigned Length =
- PredefinedExpr::ComputeName(getSema().Context, IT, currentDecl).length();
+ unsigned Length = PredefinedExpr::ComputeName(IT, currentDecl).length();
llvm::APInt LengthI(32, Length + 1);
QualType ResTy = getSema().Context.CharTy.withConst();
@@ -689,88 +699,145 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
}
Sema::OwningExprResult
-TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
- // FIXME: Clean this up a bit
- 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
- // arguments left unspecified.
- if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(),
- NTTP->getPosition()))
- return SemaRef.Owned(E->Retain());
+TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
+ NonTypeTemplateParmDecl *NTTP) {
+ // 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
+ // arguments left unspecified.
+ if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(),
+ NTTP->getPosition()))
+ return SemaRef.Owned(E->Retain());
- const TemplateArgument &Arg = TemplateArgs(NTTP->getDepth(),
- NTTP->getPosition());
+ const TemplateArgument &Arg = TemplateArgs(NTTP->getDepth(),
+ NTTP->getPosition());
- // The template argument itself might be an expression, in which
- // case we just return that expression.
- if (Arg.getKind() == TemplateArgument::Expression)
- return SemaRef.Owned(Arg.getAsExpr()->Retain());
+ // The template argument itself might be an expression, in which
+ // case we just return that expression.
+ if (Arg.getKind() == TemplateArgument::Expression)
+ return SemaRef.Owned(Arg.getAsExpr()->Retain());
- if (Arg.getKind() == TemplateArgument::Declaration) {
- ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
+ if (Arg.getKind() == TemplateArgument::Declaration) {
+ ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
- VD = cast_or_null<ValueDecl>(
+ // Find the instantiation of the template argument. This is
+ // required for nested templates.
+ VD = cast_or_null<ValueDecl>(
getSema().FindInstantiatedDecl(VD, TemplateArgs));
- if (!VD)
+ if (!VD)
+ return SemaRef.ExprError();
+
+ // Derive the type we want the substituted decl to have. This had
+ // better be non-dependent, or these checks will have serious problems.
+ QualType TargetType = SemaRef.SubstType(NTTP->getType(), TemplateArgs,
+ E->getLocation(),
+ DeclarationName());
+ assert(!TargetType.isNull() && "type substitution failed for param type");
+ assert(!TargetType->isDependentType() && "param type still dependent");
+
+ if (VD->getDeclContext()->isRecord() &&
+ (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD))) {
+ // 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 (TargetType->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(),
+ &SS);
+ if (RefExpr.isInvalid())
return SemaRef.ExprError();
- 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(),
- &SS);
- if (RefExpr.isInvalid())
- return SemaRef.ExprError();
-
- return SemaRef.CreateBuiltinUnaryOp(E->getLocation(),
- UnaryOperator::AddrOf,
- move(RefExpr));
- }
- }
+ RefExpr = SemaRef.CreateBuiltinUnaryOp(E->getLocation(),
+ UnaryOperator::AddrOf,
+ move(RefExpr));
+ assert(!RefExpr.isInvalid() &&
+ SemaRef.Context.hasSameType(((Expr*) RefExpr.get())->getType(),
+ TargetType));
+ return move(RefExpr);
+ }
+ }
- return SemaRef.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(),
- E->getLocation());
+ QualType T = VD->getType().getNonReferenceType();
+
+ if (TargetType->isPointerType()) {
+ // C++03 [temp.arg.nontype]p5:
+ // - For a non-type template-parameter of type pointer to
+ // object, qualification conversions and the array-to-pointer
+ // conversion are applied.
+ // - For a non-type template-parameter of type pointer to
+ // function, only the function-to-pointer conversion is
+ // applied.
+
+ OwningExprResult RefExpr
+ = SemaRef.BuildDeclRefExpr(VD, T, E->getLocation());
+ if (RefExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ // Decay functions and arrays.
+ Expr *RefE = (Expr *)RefExpr.get();
+ SemaRef.DefaultFunctionArrayConversion(RefE);
+ if (RefE != RefExpr.get()) {
+ RefExpr.release();
+ RefExpr = SemaRef.Owned(RefE);
}
- assert(Arg.getKind() == TemplateArgument::Integral);
- QualType T = Arg.getIntegralType();
- if (T->isCharType() || T->isWideCharType())
- return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral(
+ // Qualification conversions.
+ RefExpr.release();
+ SemaRef.ImpCastExprToType(RefE, TargetType.getUnqualifiedType(),
+ CastExpr::CK_NoOp);
+ return SemaRef.Owned(RefE);
+ }
+
+ // If the non-type template parameter has reference type, qualify the
+ // resulting declaration reference with the extra qualifiers on the
+ // type that the reference refers to.
+ if (const ReferenceType *TargetRef = TargetType->getAs<ReferenceType>())
+ T = SemaRef.Context.getQualifiedType(T,
+ TargetRef->getPointeeType().getQualifiers());
+
+ return SemaRef.BuildDeclRefExpr(VD, T, E->getLocation());
+ }
+
+ assert(Arg.getKind() == TemplateArgument::Integral);
+ QualType T = Arg.getIntegralType();
+ if (T->isCharType() || T->isWideCharType())
+ return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral(
Arg.getAsIntegral()->getZExtValue(),
T->isWideCharType(),
T,
E->getSourceRange().getBegin()));
- if (T->isBooleanType())
- return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr(
+ if (T->isBooleanType())
+ return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr(
Arg.getAsIntegral()->getBoolValue(),
T,
E->getSourceRange().getBegin()));
- assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T));
- return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral(
+ assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T));
+ return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral(
*Arg.getAsIntegral(),
T,
E->getSourceRange().getBegin()));
- }
+}
+
+
+Sema::OwningExprResult
+TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
+ NamedDecl *D = E->getDecl();
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
+ if (NTTP->getDepth() < TemplateArgs.getNumLevels())
+ return TransformTemplateParmRefExpr(E, NTTP);
// We have a non-type template parameter that isn't fully substituted;
// FindInstantiatedDecl will find it in the local instantiation scope.
@@ -986,7 +1053,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
bool Invalid = false;
CXXRecordDecl *PatternDef
- = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
+ = cast_or_null<CXXRecordDecl>(Pattern->getDefinition());
if (!PatternDef) {
if (!Complain) {
// Say nothing
@@ -1063,9 +1130,18 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// If this is a polymorphic C++ class without a key function, we'll
// have to mark all of the virtual members to allow emission of a vtable
// in this translation unit.
- if (Instantiation->isDynamicClass() && !Context.getKeyFunction(Instantiation))
+ if (Instantiation->isDynamicClass() &&
+ !Context.getKeyFunction(Instantiation)) {
+ // Local classes need to have their methods instantiated immediately in
+ // order to have the correct instantiation scope.
+ if (Instantiation->isLocalClass()) {
+ MarkVirtualMembersReferenced(PointOfInstantiation,
+ Instantiation);
+ } else {
ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Instantiation,
PointOfInstantiation));
+ }
+ }
if (!Invalid)
Consumer.HandleTagDeclDefinition(Instantiation);
@@ -1124,7 +1200,7 @@ Sema::InstantiateClassTemplateSpecialization(
PartialEnd = Template->getPartialSpecializations().end();
Partial != PartialEnd;
++Partial) {
- TemplateDeductionInfo Info(Context);
+ TemplateDeductionInfo Info(Context, PointOfInstantiation);
if (TemplateDeductionResult Result
= DeduceTemplateArguments(&*Partial,
ClassTemplateSpec->getTemplateArgs(),
@@ -1154,7 +1230,8 @@ Sema::InstantiateClassTemplateSpecialization(
for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1,
PEnd = Matched.end();
P != PEnd; ++P) {
- if (getMoreSpecializedPartialSpecialization(P->first, Best->first)
+ if (getMoreSpecializedPartialSpecialization(P->first, Best->first,
+ PointOfInstantiation)
== P->first)
Best = P;
}
@@ -1166,7 +1243,8 @@ Sema::InstantiateClassTemplateSpecialization(
PEnd = Matched.end();
P != PEnd; ++P) {
if (P != Best &&
- getMoreSpecializedPartialSpecialization(P->first, Best->first)
+ getMoreSpecializedPartialSpecialization(P->first, Best->first,
+ PointOfInstantiation)
!= Best->first) {
Ambiguous = true;
break;
@@ -1327,8 +1405,8 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass();
assert(Pattern && "Missing instantiated-from-template information");
- if (!Record->getDefinition(Context)) {
- if (!Pattern->getDefinition(Context)) {
+ if (!Record->getDefinition()) {
+ if (!Pattern->getDefinition()) {
// C++0x [temp.explicit]p8:
// An explicit instantiation definition that names a class template
// specialization explicitly instantiates the class template
@@ -1348,7 +1426,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
TSK);
}
- Pattern = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context));
+ Pattern = cast_or_null<CXXRecordDecl>(Record->getDefinition());
if (Pattern)
InstantiateClassMembers(PointOfInstantiation, Pattern, TemplateArgs,
TSK);
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 23a9430d746f..0b0efcb83327 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -43,6 +43,7 @@ namespace {
// clang/AST/DeclNodes.def.
Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
Decl *VisitNamespaceDecl(NamespaceDecl *D);
+ Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
Decl *VisitTypedefDecl(TypedefDecl *D);
Decl *VisitVarDecl(VarDecl *D);
Decl *VisitFieldDecl(FieldDecl *D);
@@ -126,6 +127,21 @@ TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) {
return D;
}
+Decl *
+TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
+ NamespaceAliasDecl *Inst
+ = NamespaceAliasDecl::Create(SemaRef.Context, Owner,
+ D->getNamespaceLoc(),
+ D->getAliasLoc(),
+ D->getNamespace()->getIdentifier(),
+ D->getQualifierRange(),
+ D->getQualifier(),
+ D->getTargetNameLoc(),
+ D->getNamespace());
+ Owner->addDecl(Inst);
+ return Inst;
+}
+
Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
bool Invalid = false;
TypeSourceInfo *DI = D->getTypeSourceInfo();
@@ -217,6 +233,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
// FIXME: having to fake up a LookupResult is dumb.
LookupResult Previous(SemaRef, Var->getDeclName(), Var->getLocation(),
Sema::LookupOrdinaryName);
+ if (D->isStaticDataMember())
+ SemaRef.LookupQualifiedName(Previous, Owner, false);
SemaRef.CheckVariableDeclaration(Var, Previous, Redeclaration);
if (D->isOutOfLine()) {
@@ -232,7 +250,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D,
TSK_ImplicitInstantiation);
- if (D->getInit()) {
+ if (Var->getAnyInitializer()) {
+ // We already have an initializer in the class.
+ } else if (D->getInit()) {
if (Var->isStaticDataMember() && !D->isOutOfLine())
SemaRef.PushExpressionEvaluationContext(Sema::Unevaluated);
else
@@ -241,6 +261,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
// Extract the initializer, skipping through any temporary-binding
// expressions and look at the subexpression as it was written.
Expr *DInit = D->getInit();
+ if (CXXExprWithTemporaries *ExprTemp
+ = dyn_cast<CXXExprWithTemporaries>(DInit))
+ DInit = ExprTemp->getSubExpr();
while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(DInit))
DInit = Binder->getSubExpr();
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(DInit))
@@ -408,9 +431,17 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
Decl *NewND;
// Hack to make this work almost well pending a rewrite.
- if (ND->getDeclContext()->isRecord())
- NewND = SemaRef.FindInstantiatedDecl(ND, TemplateArgs);
- else if (D->wasSpecialization()) {
+ if (ND->getDeclContext()->isRecord()) {
+ if (!ND->getDeclContext()->isDependentContext()) {
+ NewND = SemaRef.FindInstantiatedDecl(ND, TemplateArgs);
+ } else {
+ // FIXME: Hack to avoid crashing when incorrectly trying to instantiate
+ // templated friend declarations. This doesn't produce a correct AST;
+ // however this is sufficient for some AST analysis. The real solution
+ // must be put in place during the pending rewrite. See PR5848.
+ return 0;
+ }
+ } else if (D->wasSpecialization()) {
// Totally egregious hack to work around PR5866
return 0;
} else
@@ -493,6 +524,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
}
if (EnumConst) {
+ EnumConst->setAccess(Enum->getAccess());
Enum->addDecl(EnumConst);
Enumerators.push_back(Sema::DeclPtrTy::make(EnumConst));
LastEnumConst = EnumConst;
@@ -734,9 +766,14 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
if (T.isNull())
return 0;
- // Build the instantiated method declaration.
- DeclContext *DC = SemaRef.FindInstantiatedContext(D->getDeclContext(),
- TemplateArgs);
+ // If we're instantiating a local function declaration, put the result
+ // in the owner; otherwise we need to find the instantiated context.
+ DeclContext *DC;
+ if (D->getDeclContext()->isFunctionOrMethod())
+ DC = Owner;
+ else
+ DC = SemaRef.FindInstantiatedContext(D->getDeclContext(), TemplateArgs);
+
FunctionDecl *Function =
FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
D->getDeclName(), T, D->getTypeSourceInfo(),
@@ -747,7 +784,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
Params[P]->setOwningFunction(Function);
- Function->setParams(SemaRef.Context, Params.data(), Params.size());
+ Function->setParams(Params.data(), Params.size());
if (TemplateParams) {
// Our resulting instantiation is actually a function template, since we
@@ -772,8 +809,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
} else if (FunctionTemplate) {
// Record this function template specialization.
- Function->setFunctionTemplateSpecialization(SemaRef.Context,
- FunctionTemplate,
+ Function->setFunctionTemplateSpecialization(FunctionTemplate,
&TemplateArgs.getInnermost(),
InsertPos);
}
@@ -926,8 +962,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Method->setDescribedFunctionTemplate(FunctionTemplate);
} else if (FunctionTemplate) {
// Record this function template specialization.
- Method->setFunctionTemplateSpecialization(SemaRef.Context,
- FunctionTemplate,
+ Method->setFunctionTemplateSpecialization(FunctionTemplate,
&TemplateArgs.getInnermost(),
InsertPos);
} else {
@@ -944,7 +979,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
Params[P]->setOwningFunction(Method);
- Method->setParams(SemaRef.Context, Params.data(), Params.size());
+ Method->setParams(Params.data(), Params.size());
if (InitMethodInstantiation(Method, D))
Method->setInvalidDecl();
@@ -1804,7 +1839,6 @@ void Sema::InstantiateStaticDataMemberDefinition(
CurContext = PreviousContext;
if (Var) {
- Var->setPreviousDeclaration(OldVar);
MemberSpecializationInfo *MSInfo = OldVar->getMemberSpecializationInfo();
assert(MSInfo && "Missing member specialization information?");
Var->setTemplateSpecializationKind(MSInfo->getTemplateSpecializationKind(),
@@ -1829,7 +1863,8 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
const MultiLevelTemplateArgumentList &TemplateArgs) {
llvm::SmallVector<MemInitTy*, 4> NewInits;
-
+ bool AnyErrors = false;
+
// Instantiate all the initializers.
for (CXXConstructorDecl::init_const_iterator Inits = Tmpl->init_begin(),
InitsEnd = Tmpl->init_end();
@@ -1837,26 +1872,38 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
CXXBaseOrMemberInitializer *Init = *Inits;
ASTOwningVector<&ActionBase::DeleteExpr> NewArgs(*this);
+ llvm::SmallVector<SourceLocation, 4> CommaLocs;
// Instantiate all the arguments.
- for (ExprIterator Args = Init->arg_begin(), ArgsEnd = Init->arg_end();
- Args != ArgsEnd; ++Args) {
- OwningExprResult NewArg = SubstExpr(*Args, TemplateArgs);
-
- if (NewArg.isInvalid())
- New->setInvalidDecl();
- else
- NewArgs.push_back(NewArg.takeAs<Expr>());
+ Expr *InitE = Init->getInit();
+ if (!InitE) {
+ // Nothing to instantiate;
+ } else if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(InitE)) {
+ if (InstantiateInitializationArguments(*this, ParenList->getExprs(),
+ ParenList->getNumExprs(),
+ TemplateArgs, CommaLocs,
+ NewArgs)) {
+ AnyErrors = true;
+ continue;
+ }
+ } else {
+ OwningExprResult InitArg = SubstExpr(InitE, TemplateArgs);
+ if (InitArg.isInvalid()) {
+ AnyErrors = true;
+ continue;
+ }
+
+ NewArgs.push_back(InitArg.release());
}
-
+
MemInitResult NewInit;
-
if (Init->isBaseInitializer()) {
TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(),
TemplateArgs,
Init->getSourceLocation(),
New->getDeclName());
if (!BaseTInfo) {
+ AnyErrors = true;
New->setInvalidDecl();
continue;
}
@@ -1884,9 +1931,10 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
Init->getRParenLoc());
}
- if (NewInit.isInvalid())
+ if (NewInit.isInvalid()) {
+ AnyErrors = true;
New->setInvalidDecl();
- else {
+ } else {
// FIXME: It would be nice if ASTOwningVector had a release function.
NewArgs.take();
@@ -1898,7 +1946,8 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
ActOnMemInitializers(DeclPtrTy::make(New),
/*FIXME: ColonLoc */
SourceLocation(),
- NewInits.data(), NewInits.size());
+ NewInits.data(), NewInits.size(),
+ AnyErrors);
}
// TODO: this could be templated if the various decl types used the
@@ -2140,7 +2189,7 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs) {
DeclContext *ParentDC = D->getDeclContext();
if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
- isa<TemplateTypeParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
+ isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) ||
ParentDC->isFunctionOrMethod()) {
// D is a local of some kind. Look into the map of local
// declarations to their instantiations.
@@ -2151,10 +2200,11 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
if (!Record->isDependentContext())
return D;
- // If the RecordDecl is actually the injected-class-name or a "templated"
- // declaration for a class template or class template partial
- // specialization, substitute into the injected-class-name of the
- // class template or partial specialization to find the new DeclContext.
+ // If the RecordDecl is actually the injected-class-name or a
+ // "templated" declaration for a class template, class template
+ // partial specialization, or a member class of a class template,
+ // substitute into the injected-class-name of the class template
+ // or partial specialization to find the new DeclContext.
QualType T;
ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate();
@@ -2164,15 +2214,18 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
= dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) {
T = Context.getTypeDeclType(Record);
ClassTemplate = PartialSpec->getSpecializedTemplate();
- }
+ }
if (!T.isNull()) {
- // Substitute into the injected-class-name to get the type corresponding
- // to the instantiation we want. This substitution should never fail,
- // since we know we can instantiate the injected-class-name or we wouldn't
- // have gotten to the injected-class-name!
- // FIXME: Can we use the CurrentInstantiationScope to avoid this extra
- // instantiation in the common case?
+ // Substitute into the injected-class-name to get the type
+ // corresponding to the instantiation we want, which may also be
+ // the current instantiation (if we're in a template
+ // definition). This substitution should never fail, since we
+ // know we can instantiate the injected-class-name or we
+ // wouldn't have gotten to the injected-class-name!
+
+ // FIXME: Can we use the CurrentInstantiationScope to avoid this
+ // extra instantiation in the common case?
T = SubstType(T, TemplateArgs, SourceLocation(), DeclarationName());
assert(!T.isNull() && "Instantiation of injected-class-name cannot fail.");
@@ -2181,26 +2234,37 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
return T->getAs<RecordType>()->getDecl();
}
- // We are performing "partial" template instantiation to create the
- // member declarations for the members of a class template
- // specialization. Therefore, D is actually referring to something in
- // the current instantiation. Look through the current context,
- // which contains actual instantiations, to find the instantiation of
- // the "current instantiation" that D refers to.
+ // We are performing "partial" template instantiation to create
+ // the member declarations for the members of a class template
+ // specialization. Therefore, D is actually referring to something
+ // in the current instantiation. Look through the current
+ // context, which contains actual instantiations, to find the
+ // instantiation of the "current instantiation" that D refers
+ // to.
+ bool SawNonDependentContext = false;
for (DeclContext *DC = CurContext; !DC->isFileContext();
DC = DC->getParent()) {
if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(DC))
+ = dyn_cast<ClassTemplateSpecializationDecl>(DC))
if (isInstantiationOf(ClassTemplate,
Spec->getSpecializedTemplate()))
return Spec;
+
+ if (!DC->isDependentContext())
+ SawNonDependentContext = true;
}
- assert(false &&
+ // We're performing "instantiation" of a member of the current
+ // instantiation while we are type-checking the
+ // definition. Compute the declaration context and return that.
+ assert(!SawNonDependentContext &&
+ "No dependent context while instantiating record");
+ DeclContext *DC = computeDeclContext(T);
+ assert(DC &&
"Unable to find declaration for the current instantiation");
- return Record;
+ return cast<CXXRecordDecl>(DC);
}
-
+
// Fall through to deal with other dependent record types (e.g.,
// anonymous unions in class templates).
}
@@ -2275,6 +2339,24 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) {
VarDecl *Var = cast<VarDecl>(Inst.first);
assert(Var->isStaticDataMember() && "Not a static data member?");
+ // Don't try to instantiate declarations if the most recent redeclaration
+ // is invalid.
+ if (Var->getMostRecentDeclaration()->isInvalidDecl())
+ continue;
+
+ // Check if the most recent declaration has changed the specialization kind
+ // and removed the need for implicit instantiation.
+ switch (Var->getMostRecentDeclaration()->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ assert(false && "Cannot instantitiate an undeclared specialization.");
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ case TSK_ExplicitSpecialization:
+ continue; // No longer need implicit instantiation.
+ case TSK_ImplicitInstantiation:
+ break;
+ }
+
PrettyStackTraceActionsDecl CrashInfo(DeclPtrTy::make(Var),
Var->getLocation(), *this,
Context.getSourceManager(),
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 906576115a56..7911e76d446a 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -68,12 +68,41 @@ static bool isOmittedBlockReturnType(const Declarator &D) {
return false;
}
+typedef std::pair<const AttributeList*,QualType> DelayedAttribute;
+typedef llvm::SmallVectorImpl<DelayedAttribute> DelayedAttributeSet;
+
+static void ProcessTypeAttributeList(Sema &S, QualType &Type,
+ const AttributeList *Attrs,
+ DelayedAttributeSet &DelayedFnAttrs);
+static bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr);
+
+static void ProcessDelayedFnAttrs(Sema &S, QualType &Type,
+ DelayedAttributeSet &Attrs) {
+ for (DelayedAttributeSet::iterator I = Attrs.begin(),
+ E = Attrs.end(); I != E; ++I)
+ if (ProcessFnAttr(S, Type, *I->first))
+ S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type)
+ << I->first->getName() << I->second;
+ Attrs.clear();
+}
+
+static void DiagnoseDelayedFnAttrs(Sema &S, DelayedAttributeSet &Attrs) {
+ for (DelayedAttributeSet::iterator I = Attrs.begin(),
+ E = Attrs.end(); I != E; ++I) {
+ S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type)
+ << I->first->getName() << I->second;
+ }
+ Attrs.clear();
+}
+
/// \brief Convert the specified declspec to the appropriate type
/// object.
/// \param D the declarator containing the declaration specifier.
/// \returns The type described by the declaration specifiers. This function
/// never returns null.
-static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){
+static QualType ConvertDeclSpecToType(Sema &TheSema,
+ Declarator &TheDeclarator,
+ DelayedAttributeSet &Delayed) {
// FIXME: Should move the logic from DeclSpec::Finish to here for validity
// checking.
const DeclSpec &DS = TheDeclarator.getDeclSpec();
@@ -343,6 +372,11 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){
if (TheSema.getLangOptions().Freestanding)
TheSema.Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex);
Result = Context.getComplexType(Result);
+ } else if (DS.isTypeAltiVecVector()) {
+ unsigned typeSize = static_cast<unsigned>(Context.getTypeSize(Result));
+ assert(typeSize > 0 && "type size for vector must be greater than 0 bits");
+ Result = Context.getVectorType(Result, 128/typeSize, true,
+ DS.isTypeAltiVecPixel());
}
assert(DS.getTypeSpecComplex() != DeclSpec::TSC_imaginary &&
@@ -351,7 +385,7 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){
// See if there are any attributes on the declspec that apply to the type (as
// opposed to the decl).
if (const AttributeList *AL = DS.getAttributes())
- TheSema.ProcessTypeAttributeList(Result, AL);
+ ProcessTypeAttributeList(TheSema, Result, AL, Delayed);
// Apply const/volatile/restrict qualifiers to T.
if (unsigned TypeQuals = DS.getTypeQualifiers()) {
@@ -885,15 +919,23 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// have a type.
QualType T;
+ llvm::SmallVector<DelayedAttribute,4> FnAttrsFromDeclSpec;
+
switch (D.getName().getKind()) {
case UnqualifiedId::IK_Identifier:
case UnqualifiedId::IK_OperatorFunctionId:
case UnqualifiedId::IK_LiteralOperatorId:
case UnqualifiedId::IK_TemplateId:
- T = ConvertDeclSpecToType(D, *this);
+ T = ConvertDeclSpecToType(*this, D, FnAttrsFromDeclSpec);
- if (!D.isInvalidType() && OwnedDecl && D.getDeclSpec().isTypeSpecOwned())
- *OwnedDecl = cast<TagDecl>((Decl *)D.getDeclSpec().getTypeRep());
+ if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) {
+ TagDecl* Owned = cast<TagDecl>((Decl *)D.getDeclSpec().getTypeRep());
+ // Owned is embedded if it was defined here, or if it is the
+ // very first (i.e., canonical) declaration of this tag type.
+ Owned->setEmbeddedInDeclarator(Owned->isDefinition() ||
+ Owned->isCanonicalDecl());
+ if (OwnedDecl) *OwnedDecl = Owned;
+ }
break;
case UnqualifiedId::IK_ConstructorName:
@@ -962,6 +1004,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (D.getIdentifier())
Name = D.getIdentifier();
+ llvm::SmallVector<DelayedAttribute,4> FnAttrsFromPreviousChunk;
+
// Walk the DeclTypeInfo, building the recursive type as we go.
// DeclTypeInfos are ordered from the identifier out, which is
// opposite of what we want :).
@@ -1181,6 +1225,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
FTI.hasAnyExceptionSpec,
Exceptions.size(), Exceptions.data());
}
+
+ // For GCC compatibility, we allow attributes that apply only to
+ // function types to be placed on a function's return type
+ // instead (as long as that type doesn't happen to be function
+ // or function-pointer itself).
+ ProcessDelayedFnAttrs(*this, T, FnAttrsFromPreviousChunk);
+
break;
}
case DeclaratorChunk::MemberPointer:
@@ -1239,9 +1290,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
T = Context.IntTy;
}
+ DiagnoseDelayedFnAttrs(*this, FnAttrsFromPreviousChunk);
+
// See if there are any attributes on this declarator chunk.
if (const AttributeList *AL = DeclType.getAttrs())
- ProcessTypeAttributeList(T, AL);
+ ProcessTypeAttributeList(*this, T, AL, FnAttrsFromPreviousChunk);
}
if (getLangOptions().CPlusPlus && T->isFunctionType()) {
@@ -1271,10 +1324,18 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
}
- // If there were any type attributes applied to the decl itself (not the
- // type, apply the type attribute to the type!)
- if (const AttributeList *Attrs = D.getAttributes())
- ProcessTypeAttributeList(T, Attrs);
+ // Process any function attributes we might have delayed from the
+ // declaration-specifiers.
+ ProcessDelayedFnAttrs(*this, T, FnAttrsFromDeclSpec);
+
+ // If there were any type attributes applied to the decl itself, not
+ // the type, apply them to the result type. But don't do this for
+ // block-literal expressions, which are parsed wierdly.
+ if (D.getContext() != Declarator::BlockLiteralContext)
+ if (const AttributeList *Attrs = D.getAttributes())
+ ProcessTypeAttributeList(*this, T, Attrs, FnAttrsFromPreviousChunk);
+
+ DiagnoseDelayedFnAttrs(*this, FnAttrsFromPreviousChunk);
if (TInfo) {
if (D.isInvalidType())
@@ -1645,20 +1706,79 @@ static void HandleObjCGCTypeAttribute(QualType &Type,
Type = S.Context.getObjCGCQualType(Type, GCAttr);
}
-/// HandleNoReturnTypeAttribute - Process the noreturn attribute on the
-/// specified type. The attribute contains 0 arguments.
-static void HandleNoReturnTypeAttribute(QualType &Type,
- const AttributeList &Attr, Sema &S) {
- if (Attr.getNumArgs() != 0)
- return;
+/// Process an individual function attribute. Returns true if the
+/// attribute does not make sense to apply to this type.
+bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
+ if (Attr.getKind() == AttributeList::AT_noreturn) {
+ // Complain immediately if the arg count is wrong.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return false;
+ }
- // We only apply this to a pointer to function or a pointer to block.
- if (!Type->isFunctionPointerType()
- && !Type->isBlockPointerType()
- && !Type->isFunctionType())
- return;
+ // Delay if this is not a function or pointer to block.
+ if (!Type->isFunctionPointerType()
+ && !Type->isBlockPointerType()
+ && !Type->isFunctionType())
+ return true;
- Type = S.Context.getNoReturnType(Type);
+ // Otherwise we can process right away.
+ Type = S.Context.getNoReturnType(Type);
+ return false;
+ }
+
+ // Otherwise, a calling convention.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return false;
+ }
+
+ QualType T = Type;
+ if (const PointerType *PT = Type->getAs<PointerType>())
+ T = PT->getPointeeType();
+ const FunctionType *Fn = T->getAs<FunctionType>();
+
+ // Delay if the type didn't work out to a function.
+ if (!Fn) return true;
+
+ // TODO: diagnose uses of these conventions on the wrong target.
+ CallingConv CC;
+ switch (Attr.getKind()) {
+ case AttributeList::AT_cdecl: CC = CC_C; break;
+ case AttributeList::AT_fastcall: CC = CC_X86FastCall; break;
+ case AttributeList::AT_stdcall: CC = CC_X86StdCall; break;
+ default: llvm_unreachable("unexpected attribute kind"); return false;
+ }
+
+ CallingConv CCOld = Fn->getCallConv();
+ if (CC == CCOld) return false;
+
+ if (CCOld != CC_Default) {
+ // Should we diagnose reapplications of the same convention?
+ S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
+ << FunctionType::getNameForCallConv(CC)
+ << FunctionType::getNameForCallConv(CCOld);
+ return false;
+ }
+
+ // Diagnose the use of X86 fastcall on varargs or unprototyped functions.
+ if (CC == CC_X86FastCall) {
+ if (isa<FunctionNoProtoType>(Fn)) {
+ S.Diag(Attr.getLoc(), diag::err_cconv_knr)
+ << FunctionType::getNameForCallConv(CC);
+ return false;
+ }
+
+ const FunctionProtoType *FnP = cast<FunctionProtoType>(Fn);
+ if (FnP->isVariadic()) {
+ S.Diag(Attr.getLoc(), diag::err_cconv_varargs)
+ << FunctionType::getNameForCallConv(CC);
+ return false;
+ }
+ }
+
+ Type = S.Context.getCallConvType(Type, CC);
+ return false;
}
/// HandleVectorSizeAttribute - this attribute is only applicable to integral
@@ -1705,10 +1825,12 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S
// Success! Instantiate the vector type, the number of elements is > 0, and
// not required to be a power of 2, unlike GCC.
- CurType = S.Context.getVectorType(CurType, vectorSize/typeSize);
+ CurType = S.Context.getVectorType(CurType, vectorSize/typeSize, false, false);
}
-void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
+void ProcessTypeAttributeList(Sema &S, QualType &Result,
+ const AttributeList *AL,
+ DelayedAttributeSet &FnAttrs) {
// Scan through and apply attributes to this type where it makes sense. Some
// attributes (such as __address_space__, __vector_size__, etc) apply to the
// type, but others can be present in the type specifiers even though they
@@ -1718,17 +1840,23 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
// the LeftOverAttrs list for rechaining.
switch (AL->getKind()) {
default: break;
+
case AttributeList::AT_address_space:
- HandleAddressSpaceTypeAttribute(Result, *AL, *this);
+ HandleAddressSpaceTypeAttribute(Result, *AL, S);
break;
case AttributeList::AT_objc_gc:
- HandleObjCGCTypeAttribute(Result, *AL, *this);
- break;
- case AttributeList::AT_noreturn:
- HandleNoReturnTypeAttribute(Result, *AL, *this);
+ HandleObjCGCTypeAttribute(Result, *AL, S);
break;
case AttributeList::AT_vector_size:
- HandleVectorSizeAttr(Result, *AL, *this);
+ HandleVectorSizeAttr(Result, *AL, S);
+ break;
+
+ case AttributeList::AT_noreturn:
+ case AttributeList::AT_cdecl:
+ case AttributeList::AT_fastcall:
+ case AttributeList::AT_stdcall:
+ if (ProcessFnAttr(S, Result, *AL))
+ FnAttrs.push_back(DelayedAttribute(AL, Result));
break;
}
}
diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp
index 7c19bf6e4fd4..d45d0106ffe6 100644
--- a/lib/Sema/TargetAttributesSema.cpp
+++ b/lib/Sema/TargetAttributesSema.cpp
@@ -70,6 +70,48 @@ namespace {
};
}
+static void HandleX86ForceAlignArgPointerAttr(Decl *D,
+ const AttributeList& Attr,
+ Sema &S) {
+ // Check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ // If we try to apply it to a function pointer, warn. This is a special
+ // instance of the warn_attribute_ignored warning that can be turned
+ // off with -Wno-force-align-arg-pointer.
+ ValueDecl* VD = dyn_cast<ValueDecl>(D);
+ if (VD && VD->getType()->isFunctionPointerType()) {
+ S.Diag(Attr.getLoc(), diag::warn_faap_attribute_ignored);
+ return;
+ }
+ // Attribute can only be applied to function types.
+ if (!isa<FunctionDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << /* function */0;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr());
+}
+
+namespace {
+ class X86AttributesSema : public TargetAttributesSema {
+ public:
+ X86AttributesSema() { }
+ bool ProcessDeclAttribute(Scope *scope, Decl *D,
+ const AttributeList &Attr, Sema &S) const {
+ if (Attr.getName()->getName() == "force_align_arg_pointer") {
+ HandleX86ForceAlignArgPointerAttr(D, Attr, S);
+ return true;
+ }
+ return false;
+ }
+ };
+}
+
const TargetAttributesSema &Sema::getTargetAttributesSema() const {
if (TheTargetAttributesSema)
return *TheTargetAttributesSema;
@@ -81,6 +123,8 @@ const TargetAttributesSema &Sema::getTargetAttributesSema() const {
case llvm::Triple::msp430:
return *(TheTargetAttributesSema = new MSP430AttributesSema);
+ case llvm::Triple::x86:
+ return *(TheTargetAttributesSema = new X86AttributesSema);
}
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index b2102afdfc42..fc069f7ba38a 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -428,7 +428,8 @@ public:
///
/// By default, performs semantic analysis when building the vector type.
/// Subclasses may override this routine to provide different behavior.
- QualType RebuildVectorType(QualType ElementType, unsigned NumElements);
+ QualType RebuildVectorType(QualType ElementType, unsigned NumElements,
+ bool IsAltiVec, bool IsPixel);
/// \brief Build a new extended vector type given the element type and
/// number of elements.
@@ -524,9 +525,13 @@ public:
/// and the given type. Subclasses may override this routine to provide
/// different behavior.
QualType RebuildTypenameType(NestedNameSpecifier *NNS, QualType T) {
- if (NNS->isDependent())
- return SemaRef.Context.getTypenameType(NNS,
+ if (NNS->isDependent()) {
+ CXXScopeSpec SS;
+ SS.setScopeRep(NNS);
+ if (!SemaRef.computeDeclContext(SS))
+ return SemaRef.Context.getTypenameType(NNS,
cast<TemplateSpecializationType>(T));
+ }
return SemaRef.Context.getQualifiedNameType(NNS, T);
}
@@ -776,6 +781,28 @@ public:
StartLoc, EndLoc));
}
+ /// \brief Build a new inline asm statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildAsmStmt(SourceLocation AsmLoc,
+ bool IsSimple,
+ bool IsVolatile,
+ unsigned NumOutputs,
+ unsigned NumInputs,
+ IdentifierInfo **Names,
+ MultiExprArg Constraints,
+ MultiExprArg Exprs,
+ ExprArg AsmString,
+ MultiExprArg Clobbers,
+ SourceLocation RParenLoc,
+ bool MSAsm) {
+ return getSema().ActOnAsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs,
+ NumInputs, Names, move(Constraints),
+ move(Exprs), move(AsmString), move(Clobbers),
+ RParenLoc, MSAsm);
+ }
+
/// \brief Build a new C++ exception declaration.
///
/// By default, performs semantic analysis to build the new decaration.
@@ -1662,6 +1689,7 @@ Sema::OwningStmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) {
// Transform expressions by calling TransformExpr.
#define STMT(Node, Parent)
+#define ABSTRACT_EXPR(Node, Parent)
#define EXPR(Node, Parent) case Stmt::Node##Class:
#include "clang/AST/StmtNodes.def"
{
@@ -1685,6 +1713,7 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E) {
switch (E->getStmtClass()) {
case Stmt::NoStmtClass: break;
#define STMT(Node, Parent) case Stmt::Node##Class: break;
+#define ABSTRACT_EXPR(Node, Parent)
#define EXPR(Node, Parent) \
case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E));
#include "clang/AST/StmtNodes.def"
@@ -2448,7 +2477,8 @@ QualType TreeTransform<Derived>::TransformVectorType(TypeLocBuilder &TLB,
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
ElementType != T->getElementType()) {
- Result = getDerived().RebuildVectorType(ElementType, T->getNumElements());
+ Result = getDerived().RebuildVectorType(ElementType, T->getNumElements(),
+ T->isAltiVec(), T->isPixel());
if (Result.isNull())
return QualType();
}
@@ -3327,9 +3357,74 @@ TreeTransform<Derived>::TransformSwitchCase(SwitchCase *S) {
template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) {
- // FIXME: Implement!
- assert(false && "Inline assembly cannot be transformed");
- return SemaRef.Owned(S->Retain());
+
+ ASTOwningVector<&ActionBase::DeleteExpr> Constraints(getSema());
+ ASTOwningVector<&ActionBase::DeleteExpr> Exprs(getSema());
+ llvm::SmallVector<IdentifierInfo *, 4> Names;
+
+ OwningExprResult AsmString(SemaRef);
+ ASTOwningVector<&ActionBase::DeleteExpr> Clobbers(getSema());
+
+ bool ExprsChanged = false;
+
+ // Go through the outputs.
+ for (unsigned I = 0, E = S->getNumOutputs(); I != E; ++I) {
+ Names.push_back(S->getOutputIdentifier(I));
+
+ // No need to transform the constraint literal.
+ Constraints.push_back(S->getOutputConstraintLiteral(I)->Retain());
+
+ // Transform the output expr.
+ Expr *OutputExpr = S->getOutputExpr(I);
+ OwningExprResult Result = getDerived().TransformExpr(OutputExpr);
+ if (Result.isInvalid())
+ return SemaRef.StmtError();
+
+ ExprsChanged |= Result.get() != OutputExpr;
+
+ Exprs.push_back(Result.takeAs<Expr>());
+ }
+
+ // Go through the inputs.
+ for (unsigned I = 0, E = S->getNumInputs(); I != E; ++I) {
+ Names.push_back(S->getInputIdentifier(I));
+
+ // No need to transform the constraint literal.
+ Constraints.push_back(S->getInputConstraintLiteral(I)->Retain());
+
+ // Transform the input expr.
+ Expr *InputExpr = S->getInputExpr(I);
+ OwningExprResult Result = getDerived().TransformExpr(InputExpr);
+ if (Result.isInvalid())
+ return SemaRef.StmtError();
+
+ ExprsChanged |= Result.get() != InputExpr;
+
+ Exprs.push_back(Result.takeAs<Expr>());
+ }
+
+ if (!getDerived().AlwaysRebuild() && !ExprsChanged)
+ return SemaRef.Owned(S->Retain());
+
+ // Go through the clobbers.
+ for (unsigned I = 0, E = S->getNumClobbers(); I != E; ++I)
+ Clobbers.push_back(S->getClobber(I)->Retain());
+
+ // No need to transform the asm string literal.
+ AsmString = SemaRef.Owned(S->getAsmString());
+
+ return getDerived().RebuildAsmStmt(S->getAsmLoc(),
+ S->isSimple(),
+ S->isVolatile(),
+ S->getNumOutputs(),
+ S->getNumInputs(),
+ Names.data(),
+ move_arg(Constraints),
+ move_arg(Exprs),
+ move(AsmString),
+ move_arg(Clobbers),
+ S->getRParenLoc(),
+ S->isMSAsm());
}
@@ -3742,13 +3837,6 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCastExpr(CastExpr *E) {
- assert(false && "Cannot transform abstract class");
- return SemaRef.Owned(E->Retain());
-}
-
-template<typename Derived>
-Sema::OwningExprResult
TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) {
OwningExprResult LHS = getDerived().TransformExpr(E->getLHS());
if (LHS.isInvalid())
@@ -3812,13 +3900,6 @@ TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E) {
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E) {
- assert(false && "Cannot transform abstract class");
- return SemaRef.Owned(E->Retain());
-}
-
-template<typename Derived>
-Sema::OwningExprResult
TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) {
TypeSourceInfo *OldT;
TypeSourceInfo *NewT;
@@ -4433,7 +4514,7 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
if (!Param)
return SemaRef.ExprError();
- if (getDerived().AlwaysRebuild() &&
+ if (!getDerived().AlwaysRebuild() &&
Param == E->getParam())
return SemaRef.Owned(E->Retain());
@@ -4733,6 +4814,12 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
+ // CXXConstructExprs are always implicit, so when we have a
+ // 1-argument construction we just transform that argument.
+ if (E->getNumArgs() == 1 ||
+ (E->getNumArgs() > 1 && getDerived().DropCallArgument(E->getArg(1))))
+ return getDerived().TransformExpr(E->getArg(0));
+
TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
QualType T = getDerived().TransformType(E->getType());
@@ -4784,6 +4871,16 @@ TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
return getDerived().TransformExpr(E->getSubExpr());
}
+/// \brief Transform a C++ reference-binding expression.
+///
+/// Since CXXBindReferenceExpr nodes are implicitly generated, we just
+/// transform the subexpression and return that.
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXBindReferenceExpr(CXXBindReferenceExpr *E) {
+ return getDerived().TransformExpr(E->getSubExpr());
+}
+
/// \brief Transform a C++ expression that contains temporaries that should
/// be destroyed after the expression is evaluated.
///
@@ -5330,9 +5427,11 @@ TreeTransform<Derived>::RebuildDependentSizedArrayType(QualType ElementType,
template<typename Derived>
QualType TreeTransform<Derived>::RebuildVectorType(QualType ElementType,
- unsigned NumElements) {
+ unsigned NumElements,
+ bool IsAltiVec, bool IsPixel) {
// FIXME: semantic checking!
- return SemaRef.Context.getVectorType(ElementType, NumElements);
+ return SemaRef.Context.getVectorType(ElementType, NumElements,
+ IsAltiVec, IsPixel);
}
template<typename Derived>
@@ -5563,28 +5662,21 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
// Compute the transformed set of functions (and function templates) to be
// used during overload resolution.
- Sema::FunctionSet Functions;
+ UnresolvedSet<16> Functions;
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(CalleeExpr)) {
assert(ULE->requiresADL());
// FIXME: Do we have to check
// IsAcceptableNonMemberOperatorCandidate for each of these?
- for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(),
- E = ULE->decls_end(); I != E; ++I)
- Functions.insert(AnyFunctionDecl::getFromNamedDecl(*I));
+ Functions.append(ULE->decls_begin(), ULE->decls_end());
} else {
- Functions.insert(AnyFunctionDecl::getFromNamedDecl(
- cast<DeclRefExpr>(CalleeExpr)->getDecl()));
+ Functions.addDecl(cast<DeclRefExpr>(CalleeExpr)->getDecl());
}
// Add any functions found via argument-dependent lookup.
Expr *Args[2] = { FirstExpr, SecondExpr };
unsigned NumArgs = 1 + (SecondExpr != 0);
- DeclarationName OpName
- = SemaRef.Context.DeclarationNames.getCXXOperatorName(Op);
- SemaRef.ArgumentDependentLookup(OpName, /*Operator*/true, Args, NumArgs,
- Functions);
// Create the overloaded operator invocation for unary operators.
if (NumArgs == 1 || isPostIncDec) {