From 4c8b24812ddcd1dedaca343a6d4e76f91f398981 Mon Sep 17 00:00:00 2001 From: Roman Divacky Date: Wed, 14 Oct 2009 18:03:49 +0000 Subject: Update clang to r84119. --- lib/AST/APValue.cpp | 16 +- lib/AST/ASTContext.cpp | 2766 ++++++++------- lib/AST/CMakeLists.txt | 11 +- lib/AST/CXXInheritance.cpp | 244 ++ lib/AST/Decl.cpp | 509 ++- lib/AST/DeclBase.cpp | 164 +- lib/AST/DeclCXX.cpp | 610 +++- lib/AST/DeclObjC.cpp | 440 ++- lib/AST/DeclPrinter.cpp | 244 +- lib/AST/DeclTemplate.cpp | 206 +- lib/AST/DeclarationName.cpp | 44 +- lib/AST/Expr.cpp | 797 +++-- lib/AST/ExprCXX.cpp | 274 +- lib/AST/ExprConstant.cpp | 284 +- lib/AST/InheritViz.cpp | 10 +- lib/AST/NestedNameSpecifier.cpp | 61 +- lib/AST/ParentMap.cpp | 10 +- lib/AST/RecordLayoutBuilder.cpp | 674 ++++ lib/AST/RecordLayoutBuilder.h | 146 + lib/AST/Stmt.cpp | 80 +- lib/AST/StmtDumper.cpp | 143 +- lib/AST/StmtIterator.cpp | 40 +- lib/AST/StmtPrinter.cpp | 191 +- lib/AST/StmtProfile.cpp | 720 ++++ lib/AST/StmtViz.cpp | 17 +- lib/AST/TemplateName.cpp | 42 +- lib/AST/Type.cpp | 987 +++--- lib/AST/TypeLoc.cpp | 370 ++ lib/Analysis/AnalysisContext.cpp | 138 + lib/Analysis/AnalysisManager.cpp | 35 + lib/Analysis/BasicConstraintManager.cpp | 62 +- lib/Analysis/BasicObjCFoundationChecks.cpp | 329 +- lib/Analysis/BasicObjCFoundationChecks.h | 21 +- lib/Analysis/BasicStore.cpp | 380 ++- lib/Analysis/BasicValueFactory.cpp | 138 +- lib/Analysis/BugReporter.cpp | 994 +++--- lib/Analysis/BugReporterVisitors.cpp | 349 ++ lib/Analysis/CFG.cpp | 2084 ++++++++++++ lib/Analysis/CFRefCount.cpp | 1882 +++++------ lib/Analysis/CMakeLists.txt | 10 +- lib/Analysis/CallGraph.cpp | 150 + lib/Analysis/CallInliner.cpp | 75 + lib/Analysis/CheckDeadStores.cpp | 99 +- lib/Analysis/CheckNSError.cpp | 166 +- lib/Analysis/CheckObjCDealloc.cpp | 134 +- lib/Analysis/CheckObjCInstMethSignature.cpp | 47 +- lib/Analysis/CheckObjCUnusedIVars.cpp | 64 +- lib/Analysis/CheckSecuritySyntaxOnly.cpp | 409 +++ lib/Analysis/Environment.cpp | 141 +- lib/Analysis/ExplodedGraph.cpp | 200 +- lib/Analysis/GRBlockCounter.cpp | 2 +- lib/Analysis/GRCoreEngine.cpp | 439 +-- lib/Analysis/GRExprEngine.cpp | 2541 +++++++------- lib/Analysis/GRExprEngineInternalChecks.cpp | 844 ++--- lib/Analysis/GRState.cpp | 158 +- lib/Analysis/LiveVariables.cpp | 122 +- lib/Analysis/MemRegion.cpp | 212 +- lib/Analysis/PathDiagnostic.cpp | 96 +- lib/Analysis/RangeConstraintManager.cpp | 60 +- lib/Analysis/RegionStore.cpp | 1811 ++++++---- lib/Analysis/SVals.cpp | 163 +- lib/Analysis/SValuator.cpp | 160 + lib/Analysis/SimpleConstraintManager.cpp | 64 +- lib/Analysis/SimpleConstraintManager.h | 24 +- lib/Analysis/SimpleSValuator.cpp | 158 +- lib/Analysis/Store.cpp | 246 +- lib/Analysis/SymbolManager.cpp | 139 +- lib/Analysis/UninitializedValues.cpp | 84 +- lib/Analysis/ValueManager.cpp | 114 +- lib/Basic/Builtins.cpp | 18 +- lib/Basic/CMakeLists.txt | 11 + lib/Basic/ConvertUTF.c | 606 ++-- lib/Basic/Diagnostic.cpp | 121 +- lib/Basic/FileManager.cpp | 88 +- lib/Basic/IdentifierTable.cpp | 58 +- lib/Basic/Makefile | 11 + lib/Basic/SourceLocation.cpp | 4 +- lib/Basic/SourceManager.cpp | 302 +- lib/Basic/TargetInfo.cpp | 57 +- lib/Basic/Targets.cpp | 1092 ++++-- lib/Basic/Version.cpp | 49 + lib/CMakeLists.txt | 1 + lib/CodeGen/ABIInfo.h | 22 +- lib/CodeGen/CGBlocks.cpp | 196 +- lib/CodeGen/CGBlocks.h | 40 +- lib/CodeGen/CGBuiltin.cpp | 255 +- lib/CodeGen/CGCXX.cpp | 1639 +++++++-- lib/CodeGen/CGCXX.h | 2 +- lib/CodeGen/CGCXXClass.cpp | 176 + lib/CodeGen/CGCXXExpr.cpp | 304 ++ lib/CodeGen/CGCXXTemp.cpp | 102 +- lib/CodeGen/CGCall.cpp | 268 +- lib/CodeGen/CGCall.h | 33 +- lib/CodeGen/CGDebugInfo.cpp | 686 +++- lib/CodeGen/CGDebugInfo.h | 56 +- lib/CodeGen/CGDecl.cpp | 291 +- lib/CodeGen/CGExpr.cpp | 889 ++--- lib/CodeGen/CGExprAgg.cpp | 251 +- lib/CodeGen/CGExprComplex.cpp | 177 +- lib/CodeGen/CGExprConstant.cpp | 868 +++-- lib/CodeGen/CGExprScalar.cpp | 684 ++-- lib/CodeGen/CGObjC.cpp | 259 +- lib/CodeGen/CGObjCGNU.cpp | 999 ++++-- lib/CodeGen/CGObjCMac.cpp | 2817 ++++++++-------- lib/CodeGen/CGObjCRuntime.h | 49 +- lib/CodeGen/CGRecordLayoutBuilder.cpp | 386 +++ lib/CodeGen/CGRecordLayoutBuilder.h | 134 + lib/CodeGen/CGRtti.cpp | 47 + lib/CodeGen/CGStmt.cpp | 330 +- lib/CodeGen/CGValue.h | 124 +- lib/CodeGen/CGVtable.cpp | 557 +++ lib/CodeGen/CGVtable.h | 61 + lib/CodeGen/CMakeLists.txt | 11 +- lib/CodeGen/CodeGenFunction.cpp | 437 ++- lib/CodeGen/CodeGenFunction.h | 291 +- lib/CodeGen/CodeGenModule.cpp | 846 +++-- lib/CodeGen/CodeGenModule.h | 132 +- lib/CodeGen/CodeGenTypes.cpp | 376 +-- lib/CodeGen/CodeGenTypes.h | 124 +- lib/CodeGen/Makefile | 3 + lib/CodeGen/Mangle.cpp | 1098 ++++-- lib/CodeGen/Mangle.h | 48 +- lib/CodeGen/ModuleBuilder.cpp | 16 +- lib/CodeGen/README.txt | 18 - lib/CodeGen/TargetABIInfo.cpp | 647 +++- lib/Driver/Action.cpp | 12 +- lib/Driver/Arg.cpp | 23 +- lib/Driver/ArgList.cpp | 54 +- lib/Driver/Compilation.cpp | 46 +- lib/Driver/Driver.cpp | 580 ++-- lib/Driver/HostInfo.cpp | 257 +- lib/Driver/Job.cpp | 6 +- lib/Driver/Makefile | 16 +- lib/Driver/OptTable.cpp | 18 +- lib/Driver/Option.cpp | 57 +- lib/Driver/Tool.cpp | 2 +- lib/Driver/ToolChain.cpp | 12 +- lib/Driver/ToolChains.cpp | 392 ++- lib/Driver/ToolChains.h | 138 +- lib/Driver/Tools.cpp | 1082 ++++-- lib/Driver/Tools.h | 174 +- lib/Driver/Types.cpp | 48 +- lib/Frontend/ASTConsumers.cpp | 209 +- lib/Frontend/ASTUnit.cpp | 63 +- lib/Frontend/AnalysisConsumer.cpp | 536 ++- lib/Frontend/Backend.cpp | 85 +- lib/Frontend/CMakeLists.txt | 11 +- lib/Frontend/CacheTokens.cpp | 189 +- lib/Frontend/DeclXML.cpp | 74 +- lib/Frontend/DependencyFile.cpp | 16 +- lib/Frontend/DiagChecker.cpp | 32 +- lib/Frontend/DocumentXML.cpp | 157 +- lib/Frontend/FixItRewriter.cpp | 44 +- lib/Frontend/GeneratePCH.cpp | 21 +- lib/Frontend/HTMLDiagnostics.cpp | 371 +- lib/Frontend/HTMLPrint.cpp | 10 +- lib/Frontend/InitHeaderSearch.cpp | 459 ++- lib/Frontend/InitPreprocessor.cpp | 111 +- lib/Frontend/PCHReader.cpp | 612 ++-- lib/Frontend/PCHReaderDecl.cpp | 174 +- lib/Frontend/PCHReaderStmt.cpp | 127 +- lib/Frontend/PCHWriter.cpp | 547 +-- lib/Frontend/PCHWriterDecl.cpp | 221 +- lib/Frontend/PCHWriterStmt.cpp | 101 +- lib/Frontend/PlistDiagnostics.cpp | 148 +- lib/Frontend/PrintParserCallbacks.cpp | 85 +- lib/Frontend/PrintPreprocessedOutput.cpp | 96 +- lib/Frontend/RewriteBlocks.cpp | 311 +- lib/Frontend/RewriteMacros.cpp | 49 +- lib/Frontend/RewriteObjC.cpp | 1306 ++++---- lib/Frontend/RewriteTest.cpp | 4 +- lib/Frontend/StmtXML.cpp | 78 +- lib/Frontend/TextDiagnosticBuffer.cpp | 2 +- lib/Frontend/TextDiagnosticPrinter.cpp | 138 +- lib/Frontend/TypeXML.cpp | 72 +- lib/Frontend/Warnings.cpp | 16 +- lib/Headers/CMakeLists.txt | 7 +- lib/Headers/Makefile | 8 +- lib/Headers/emmintrin.h | 34 +- lib/Headers/mmintrin.h | 12 +- lib/Headers/stdarg.h | 2 +- lib/Index/ASTLocation.cpp | 117 + lib/Index/ASTVisitor.h | 144 + lib/Index/Analyzer.cpp | 438 +++ lib/Index/CMakeLists.txt | 15 + lib/Index/DeclReferenceMap.cpp | 91 + lib/Index/Entity.cpp | 225 ++ lib/Index/EntityImpl.h | 70 + lib/Index/GlobalSelector.cpp | 73 + lib/Index/Handlers.cpp | 22 + lib/Index/IndexProvider.cpp | 20 + lib/Index/Indexer.cpp | 104 + lib/Index/Makefile | 28 + lib/Index/Program.cpp | 50 + lib/Index/ProgramImpl.h | 56 + lib/Index/ResolveLocation.cpp | 505 +++ lib/Index/SelectorMap.cpp | 85 + lib/Lex/CMakeLists.txt | 4 +- lib/Lex/HeaderMap.cpp | 44 +- lib/Lex/HeaderSearch.cpp | 112 +- lib/Lex/Lexer.cpp | 436 ++- lib/Lex/LiteralSupport.cpp | 267 +- lib/Lex/MacroArgs.cpp | 34 +- lib/Lex/MacroArgs.h | 26 +- lib/Lex/MacroInfo.cpp | 12 +- lib/Lex/PPCaching.cpp | 5 +- lib/Lex/PPDirectives.cpp | 352 +- lib/Lex/PPExpressions.cpp | 100 +- lib/Lex/PPLexerChange.cpp | 68 +- lib/Lex/PPMacroExpansion.cpp | 169 +- lib/Lex/PTHLexer.cpp | 220 +- lib/Lex/Pragma.cpp | 170 +- lib/Lex/Preprocessor.cpp | 134 +- lib/Lex/PreprocessorLexer.cpp | 4 +- lib/Lex/ScratchBuffer.cpp | 10 +- lib/Lex/TokenConcatenation.cpp | 42 +- lib/Lex/TokenLexer.cpp | 120 +- lib/Makefile | 2 +- lib/Parse/AttributeList.cpp | 20 +- lib/Parse/CMakeLists.txt | 4 +- lib/Parse/DeclSpec.cpp | 186 +- lib/Parse/ExtensionRAIIObject.h | 2 +- lib/Parse/MinimalAction.cpp | 70 +- lib/Parse/ParseCXXInlineMethods.cpp | 44 +- lib/Parse/ParseDecl.cpp | 858 +++-- lib/Parse/ParseDeclCXX.cpp | 533 +-- lib/Parse/ParseExpr.cpp | 255 +- lib/Parse/ParseExprCXX.cpp | 220 +- lib/Parse/ParseInit.cpp | 40 +- lib/Parse/ParseObjc.cpp | 301 +- lib/Parse/ParsePragma.cpp | 65 +- lib/Parse/ParsePragma.h | 18 +- lib/Parse/ParseStmt.cpp | 109 +- lib/Parse/ParseTemplate.cpp | 221 +- lib/Parse/ParseTentative.cpp | 24 +- lib/Parse/Parser.cpp | 137 +- lib/Rewrite/CMakeLists.txt | 2 +- lib/Rewrite/DeltaTree.cpp | 106 +- lib/Rewrite/HTMLRewrite.cpp | 227 +- lib/Rewrite/RewriteRope.cpp | 184 +- lib/Rewrite/Rewriter.cpp | 74 +- lib/Rewrite/TokenRewriter.cpp | 20 +- lib/Sema/CMakeLists.txt | 12 +- lib/Sema/CodeCompleteConsumer.cpp | 184 + lib/Sema/IdentifierResolver.cpp | 18 +- lib/Sema/IdentifierResolver.h | 10 +- lib/Sema/JumpDiagnostics.cpp | 62 +- lib/Sema/ParseAST.cpp | 37 +- lib/Sema/Sema.cpp | 329 +- lib/Sema/Sema.h | 1874 +++++++---- lib/Sema/SemaAccess.cpp | 89 +- lib/Sema/SemaAttr.cpp | 84 +- lib/Sema/SemaCXXCast.cpp | 1128 +++++++ lib/Sema/SemaCXXScopeSpec.cpp | 381 ++- lib/Sema/SemaChecking.cpp | 530 +-- lib/Sema/SemaCodeComplete.cpp | 1432 ++++++++ lib/Sema/SemaDecl.cpp | 2593 +++++++++----- lib/Sema/SemaDeclAttr.cpp | 544 +-- lib/Sema/SemaDeclCXX.cpp | 2665 +++++++++++---- lib/Sema/SemaDeclObjC.cpp | 832 +++-- lib/Sema/SemaExceptionSpec.cpp | 320 ++ lib/Sema/SemaExpr.cpp | 2812 ++++++++++------ lib/Sema/SemaExprCXX.cpp | 1129 +++++-- lib/Sema/SemaExprObjC.cpp | 446 +-- lib/Sema/SemaInit.cpp | 462 +-- lib/Sema/SemaLookup.cpp | 1482 ++++---- lib/Sema/SemaOverload.cpp | 2271 ++++++++----- lib/Sema/SemaOverload.h | 37 +- lib/Sema/SemaStmt.cpp | 405 ++- lib/Sema/SemaTemplate.cpp | 2545 ++++++++++---- lib/Sema/SemaTemplate.h | 104 + lib/Sema/SemaTemplateDeduction.cpp | 1931 ++++++++--- lib/Sema/SemaTemplateInstantiate.cpp | 1238 +++---- lib/Sema/SemaTemplateInstantiateDecl.cpp | 1342 ++++++-- lib/Sema/SemaType.cpp | 797 +++-- lib/Sema/TreeTransform.h | 4829 +++++++++++++++++++++++++++ 276 files changed, 66592 insertions(+), 30522 deletions(-) create mode 100644 lib/AST/CXXInheritance.cpp create mode 100644 lib/AST/RecordLayoutBuilder.cpp create mode 100644 lib/AST/RecordLayoutBuilder.h create mode 100644 lib/AST/StmtProfile.cpp create mode 100644 lib/AST/TypeLoc.cpp create mode 100644 lib/Analysis/AnalysisContext.cpp create mode 100644 lib/Analysis/AnalysisManager.cpp create mode 100644 lib/Analysis/BugReporterVisitors.cpp create mode 100644 lib/Analysis/CFG.cpp create mode 100644 lib/Analysis/CallGraph.cpp create mode 100644 lib/Analysis/CallInliner.cpp create mode 100644 lib/Analysis/CheckSecuritySyntaxOnly.cpp create mode 100644 lib/Analysis/SValuator.cpp create mode 100644 lib/Basic/Version.cpp create mode 100644 lib/CodeGen/CGCXXClass.cpp create mode 100644 lib/CodeGen/CGCXXExpr.cpp create mode 100644 lib/CodeGen/CGRecordLayoutBuilder.cpp create mode 100644 lib/CodeGen/CGRecordLayoutBuilder.h create mode 100644 lib/CodeGen/CGRtti.cpp create mode 100644 lib/CodeGen/CGVtable.cpp create mode 100644 lib/CodeGen/CGVtable.h create mode 100644 lib/Index/ASTLocation.cpp create mode 100644 lib/Index/ASTVisitor.h create mode 100644 lib/Index/Analyzer.cpp create mode 100644 lib/Index/CMakeLists.txt create mode 100644 lib/Index/DeclReferenceMap.cpp create mode 100644 lib/Index/Entity.cpp create mode 100644 lib/Index/EntityImpl.h create mode 100644 lib/Index/GlobalSelector.cpp create mode 100644 lib/Index/Handlers.cpp create mode 100644 lib/Index/IndexProvider.cpp create mode 100644 lib/Index/Indexer.cpp create mode 100644 lib/Index/Makefile create mode 100644 lib/Index/Program.cpp create mode 100644 lib/Index/ProgramImpl.h create mode 100644 lib/Index/ResolveLocation.cpp create mode 100644 lib/Index/SelectorMap.cpp create mode 100644 lib/Sema/CodeCompleteConsumer.cpp create mode 100644 lib/Sema/SemaCXXCast.cpp create mode 100644 lib/Sema/SemaCodeComplete.cpp create mode 100644 lib/Sema/SemaExceptionSpec.cpp create mode 100644 lib/Sema/SemaTemplate.h create mode 100644 lib/Sema/TreeTransform.h (limited to 'lib') diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index 4df7671c5a95..772a884c90d3 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -37,7 +37,7 @@ const APValue &APValue::operator=(const APValue &RHS) { else if (isFloat()) setFloat(RHS.getFloat()); else if (isVector()) - setVector(((Vec*)(void*)RHS.Data)->Elts, RHS.getVectorLength()); + setVector(((Vec*)(char*)RHS.Data)->Elts, RHS.getVectorLength()); else if (isComplexInt()) setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag()); else if (isComplexFloat()) @@ -49,17 +49,17 @@ const APValue &APValue::operator=(const APValue &RHS) { void APValue::MakeUninit() { if (Kind == Int) - ((APSInt*)(void*)Data)->~APSInt(); + ((APSInt*)(char*)Data)->~APSInt(); else if (Kind == Float) - ((APFloat*)(void*)Data)->~APFloat(); + ((APFloat*)(char*)Data)->~APFloat(); else if (Kind == Vector) - ((Vec*)(void*)Data)->~Vec(); + ((Vec*)(char*)Data)->~Vec(); else if (Kind == ComplexInt) - ((ComplexAPSInt*)(void*)Data)->~ComplexAPSInt(); + ((ComplexAPSInt*)(char*)Data)->~ComplexAPSInt(); else if (Kind == ComplexFloat) - ((ComplexAPFloat*)(void*)Data)->~ComplexAPFloat(); + ((ComplexAPFloat*)(char*)Data)->~ComplexAPFloat(); else if (Kind == LValue) { - ((LV*)(void*)Data)->~LV(); + ((LV*)(char*)Data)->~LV(); } Kind = Uninitialized; } @@ -91,7 +91,7 @@ void APValue::print(llvm::raw_ostream &OS) const { return; case Vector: OS << "Vector: " << getVectorElt(0); - for (unsigned i = 1; i != getVectorLength(); ++i) + for (unsigned i = 1; i != getVectorLength(); ++i) OS << ", " << getVectorElt(i); return; case ComplexInt: diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 2877cc3b7fe7..85b4fd6d6cc0 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -15,6 +15,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/TypeLoc.h" #include "clang/AST/Expr.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/RecordLayout.h" @@ -24,6 +25,8 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" +#include "RecordLayoutBuilder.h" + using namespace clang; enum FloatingRank { @@ -34,15 +37,18 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, TargetInfo &t, IdentifierTable &idents, SelectorTable &sels, Builtin::Context &builtins, - bool FreeMem, unsigned size_reserve) : - GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0), - ObjCFastEnumerationStateTypeDecl(0), SourceMgr(SM), LangOpts(LOpts), - LoadedExternalComments(false), FreeMemory(FreeMem), Target(t), + bool FreeMem, unsigned size_reserve) : + GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0), + ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), + sigjmp_bufDecl(0), SourceMgr(SM), LangOpts(LOpts), + LoadedExternalComments(false), FreeMemory(FreeMem), Target(t), Idents(idents), Selectors(sels), - BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) { - if (size_reserve > 0) Types.reserve(size_reserve); - InitBuiltinTypes(); + BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) { + ObjCIdRedefinitionType = QualType(); + ObjCClassRedefinitionType = QualType(); + if (size_reserve > 0) Types.reserve(size_reserve); TUDecl = TranslationUnitDecl::Create(*this); + InitBuiltinTypes(); } ASTContext::~ASTContext() { @@ -52,6 +58,13 @@ ASTContext::~ASTContext() { Types.pop_back(); } + { + llvm::FoldingSet::iterator + I = ExtQualNodes.begin(), E = ExtQualNodes.end(); + while (I != E) + Deallocate(&*I++); + } + { llvm::DenseMap::iterator I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end(); @@ -73,8 +86,8 @@ ASTContext::~ASTContext() { // Destroy nested-name-specifiers. for (llvm::FoldingSet::iterator NNS = NestedNameSpecifiers.begin(), - NNSEnd = NestedNameSpecifiers.end(); - NNS != NNSEnd; + NNSEnd = NestedNameSpecifiers.end(); + NNS != NNSEnd; /* Increment in loop */) (*NNS++).Destroy(*this); @@ -84,7 +97,7 @@ ASTContext::~ASTContext() { TUDecl->Destroy(*this); } -void +void ASTContext::setExternalSource(llvm::OwningPtr &Source) { ExternalSource.reset(Source.take()); } @@ -94,7 +107,7 @@ void ASTContext::PrintStats() const { fprintf(stderr, " %d types total.\n", (int)Types.size()); unsigned counts[] = { -#define TYPE(Name, Parent) 0, +#define TYPE(Name, Parent) 0, #define ABSTRACT_TYPE(Name, Parent) #include "clang/AST/TypeNodes.def" 0 // Extra @@ -114,7 +127,7 @@ void ASTContext::PrintStats() const { ++Idx; #define ABSTRACT_TYPE(Name, Parent) #include "clang/AST/TypeNodes.def" - + fprintf(stderr, "Total bytes = %d\n", int(TotalBytes)); if (ExternalSource.get()) { @@ -125,15 +138,17 @@ void ASTContext::PrintStats() const { void ASTContext::InitBuiltinType(QualType &R, BuiltinType::Kind K) { - Types.push_back((R = QualType(new (*this,8) BuiltinType(K),0)).getTypePtr()); + BuiltinType *Ty = new (*this, TypeAlignment) BuiltinType(K); + R = QualType(Ty, 0); + Types.push_back(Ty); } void ASTContext::InitBuiltinTypes() { assert(VoidTy.isNull() && "Context reinitialized?"); - + // C99 6.2.5p19. InitBuiltinType(VoidTy, BuiltinType::Void); - + // C99 6.2.5p2. InitBuiltinType(BoolTy, BuiltinType::Bool); // C99 6.2.5p3. @@ -147,14 +162,14 @@ void ASTContext::InitBuiltinTypes() { InitBuiltinType(IntTy, BuiltinType::Int); InitBuiltinType(LongTy, BuiltinType::Long); InitBuiltinType(LongLongTy, BuiltinType::LongLong); - + // C99 6.2.5p6. InitBuiltinType(UnsignedCharTy, BuiltinType::UChar); InitBuiltinType(UnsignedShortTy, BuiltinType::UShort); InitBuiltinType(UnsignedIntTy, BuiltinType::UInt); InitBuiltinType(UnsignedLongTy, BuiltinType::ULong); InitBuiltinType(UnsignedLongLongTy, BuiltinType::ULongLong); - + // C99 6.2.5p10. InitBuiltinType(FloatTy, BuiltinType::Float); InitBuiltinType(DoubleTy, BuiltinType::Double); @@ -169,6 +184,16 @@ void ASTContext::InitBuiltinTypes() { else // C99 WCharTy = getFromTargetType(Target.getWCharType()); + if (LangOpts.CPlusPlus) // C++0x 3.9.1p5, extension for C++ + InitBuiltinType(Char16Ty, BuiltinType::Char16); + else // C99 + Char16Ty = getFromTargetType(Target.getChar16Type()); + + if (LangOpts.CPlusPlus) // C++0x 3.9.1p5, extension for C++ + InitBuiltinType(Char32Ty, BuiltinType::Char32); + else // C99 + Char32Ty = getFromTargetType(Target.getChar32Type()); + // Placeholder type for functions. InitBuiltinType(OverloadTy, BuiltinType::Overload); @@ -179,23 +204,27 @@ void ASTContext::InitBuiltinTypes() { // expressions. InitBuiltinType(DependentTy, BuiltinType::Dependent); - // Placeholder type for C++0x auto declarations whose real type has + // Placeholder type for C++0x auto declarations whose real type has // not yet been deduced. InitBuiltinType(UndeducedAutoTy, BuiltinType::UndeducedAuto); - + // C99 6.2.5p11. FloatComplexTy = getComplexType(FloatTy); DoubleComplexTy = getComplexType(DoubleTy); LongDoubleComplexTy = getComplexType(LongDoubleTy); BuiltinVaListType = QualType(); - ObjCIdType = QualType(); - IdStructType = 0; - ObjCClassType = QualType(); - ClassStructType = 0; - + + // "Builtin" typedefs set by Sema::ActOnTranslationUnitScope(). + ObjCIdTypedefType = QualType(); + ObjCClassTypedefType = QualType(); + + // Builtin types for 'id' and 'Class'. + InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId); + InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass); + ObjCConstantStringType = QualType(); - + // void * type VoidPtrTy = getPointerType(VoidTy); @@ -203,14 +232,73 @@ void ASTContext::InitBuiltinTypes() { InitBuiltinType(NullPtrTy, BuiltinType::NullPtr); } +MemberSpecializationInfo * +ASTContext::getInstantiatedFromStaticDataMember(VarDecl *Var) { + assert(Var->isStaticDataMember() && "Not a static data member"); + llvm::DenseMap::iterator Pos + = InstantiatedFromStaticDataMember.find(Var); + if (Pos == InstantiatedFromStaticDataMember.end()) + return 0; + + return Pos->second; +} + +void +ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, + TemplateSpecializationKind TSK) { + assert(Inst->isStaticDataMember() && "Not a static data member"); + assert(Tmpl->isStaticDataMember() && "Not a static data member"); + assert(!InstantiatedFromStaticDataMember[Inst] && + "Already noted what static data member was instantiated from"); + InstantiatedFromStaticDataMember[Inst] + = new (*this) MemberSpecializationInfo(Tmpl, TSK); +} + +UnresolvedUsingDecl * +ASTContext::getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD) { + llvm::DenseMap::iterator Pos + = InstantiatedFromUnresolvedUsingDecl.find(UUD); + if (Pos == InstantiatedFromUnresolvedUsingDecl.end()) + return 0; + + return Pos->second; +} + +void +ASTContext::setInstantiatedFromUnresolvedUsingDecl(UsingDecl *UD, + UnresolvedUsingDecl *UUD) { + assert(!InstantiatedFromUnresolvedUsingDecl[UD] && + "Already noted what using decl what instantiated from"); + InstantiatedFromUnresolvedUsingDecl[UD] = UUD; +} + +FieldDecl *ASTContext::getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) { + llvm::DenseMap::iterator Pos + = InstantiatedFromUnnamedFieldDecl.find(Field); + if (Pos == InstantiatedFromUnnamedFieldDecl.end()) + return 0; + + return Pos->second; +} + +void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, + FieldDecl *Tmpl) { + assert(!Inst->getDeclName() && "Instantiated field decl is not unnamed"); + assert(!Tmpl->getDeclName() && "Template field decl is not unnamed"); + assert(!InstantiatedFromUnnamedFieldDecl[Inst] && + "Already noted what unnamed field was instantiated from"); + + InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl; +} + namespace { - class BeforeInTranslationUnit + class BeforeInTranslationUnit : std::binary_function { SourceManager *SourceMgr; - + public: explicit BeforeInTranslationUnit(SourceManager *SM) : SourceMgr(SM) { } - + bool operator()(SourceRange X, SourceRange Y) { return SourceMgr->isBeforeInTranslationUnit(X.getBegin(), Y.getBegin()); } @@ -226,14 +314,14 @@ namespace { /// \param Member whether we want to check whether this is a member comment /// (which requires a < after the Doxygen-comment delimiter). Otherwise, /// we only return true when we find a non-member comment. -static bool -isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment, +static bool +isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment, bool Member = false) { - const char *BufferStart + const char *BufferStart = SourceMgr.getBufferData(SourceMgr.getFileID(Comment.getBegin())).first; const char *Start = BufferStart + SourceMgr.getFileOffset(Comment.getBegin()); const char* End = BufferStart + SourceMgr.getFileOffset(Comment.getEnd()); - + if (End - Start < 4) return false; @@ -247,32 +335,32 @@ isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment, } /// \brief Retrieve the comment associated with the given declaration, if -/// it has one. +/// it has one. const char *ASTContext::getCommentForDecl(const Decl *D) { if (!D) return 0; - + // Check whether we have cached a comment string for this declaration // already. - llvm::DenseMap::iterator Pos + llvm::DenseMap::iterator Pos = DeclComments.find(D); if (Pos != DeclComments.end()) return Pos->second.c_str(); - // If we have an external AST source and have not yet loaded comments from + // If we have an external AST source and have not yet loaded comments from // that source, do so now. if (ExternalSource && !LoadedExternalComments) { std::vector LoadedComments; ExternalSource->ReadComments(LoadedComments); - + if (!LoadedComments.empty()) Comments.insert(Comments.begin(), LoadedComments.begin(), LoadedComments.end()); - + LoadedExternalComments = true; } - - // If there are no comments anywhere, we won't find anything. + + // If there are no comments anywhere, we won't find anything. if (Comments.empty()) return 0; @@ -284,17 +372,17 @@ const char *ASTContext::getCommentForDecl(const Decl *D) { // Find the comment that occurs just before this declaration. std::vector::iterator LastComment - = std::lower_bound(Comments.begin(), Comments.end(), + = std::lower_bound(Comments.begin(), Comments.end(), SourceRange(DeclStartLoc), BeforeInTranslationUnit(&SourceMgr)); - + // Decompose the location for the start of the declaration and find the // beginning of the file buffer. - std::pair DeclStartDecomp + std::pair DeclStartDecomp = SourceMgr.getDecomposedLoc(DeclStartLoc); - const char *FileBufferStart + const char *FileBufferStart = SourceMgr.getBufferData(DeclStartDecomp.first).first; - + // First check whether we have a comment for a member. if (LastComment != Comments.end() && !isa(D) && !isa(D) && @@ -303,19 +391,19 @@ const char *ASTContext::getCommentForDecl(const Decl *D) { = SourceMgr.getDecomposedLoc(LastComment->getEnd()); if (DeclStartDecomp.first == LastCommentEndDecomp.first && SourceMgr.getLineNumber(DeclStartDecomp.first, DeclStartDecomp.second) - == SourceMgr.getLineNumber(LastCommentEndDecomp.first, + == SourceMgr.getLineNumber(LastCommentEndDecomp.first, LastCommentEndDecomp.second)) { // The Doxygen member comment comes after the declaration starts and // is on the same line and in the same file as the declaration. This // is the comment we want. std::string &Result = DeclComments[D]; - Result.append(FileBufferStart + - SourceMgr.getFileOffset(LastComment->getBegin()), + Result.append(FileBufferStart + + SourceMgr.getFileOffset(LastComment->getBegin()), FileBufferStart + LastCommentEndDecomp.second + 1); return Result.c_str(); } } - + if (LastComment == Comments.begin()) return 0; --LastComment; @@ -323,33 +411,33 @@ const char *ASTContext::getCommentForDecl(const Decl *D) { // Decompose the end of the comment. std::pair LastCommentEndDecomp = SourceMgr.getDecomposedLoc(LastComment->getEnd()); - + // If the comment and the declaration aren't in the same file, then they // aren't related. if (DeclStartDecomp.first != LastCommentEndDecomp.first) return 0; - + // Check that we actually have a Doxygen comment. if (!isDoxygenComment(SourceMgr, *LastComment)) return 0; - + // Compute the starting line for the declaration and for the end of the // comment (this is expensive). - unsigned DeclStartLine + unsigned DeclStartLine = SourceMgr.getLineNumber(DeclStartDecomp.first, DeclStartDecomp.second); unsigned CommentEndLine - = SourceMgr.getLineNumber(LastCommentEndDecomp.first, + = SourceMgr.getLineNumber(LastCommentEndDecomp.first, LastCommentEndDecomp.second); - + // If the comment does not end on the line prior to the declaration, then // the comment is not associated with the declaration at all. if (CommentEndLine + 1 != DeclStartLine) return 0; - + // We have a comment, but there may be more comments on the previous lines. // Keep looking so long as the comments are still Doxygen comments and are // still adjacent. - unsigned ExpectedLine + unsigned ExpectedLine = SourceMgr.getSpellingLineNumber(LastComment->getBegin()) - 1; std::vector::iterator FirstComment = LastComment; while (FirstComment != Comments.begin()) { @@ -357,31 +445,31 @@ const char *ASTContext::getCommentForDecl(const Decl *D) { --FirstComment; std::pair Decomp = SourceMgr.getDecomposedLoc(FirstComment->getEnd()); - + // If this previous comment is in a different file, we're done. if (Decomp.first != DeclStartDecomp.first) { ++FirstComment; break; } - + // If this comment is not a Doxygen comment, we're done. if (!isDoxygenComment(SourceMgr, *FirstComment)) { ++FirstComment; break; } - + // If the line number is not what we expected, we're done. unsigned Line = SourceMgr.getLineNumber(Decomp.first, Decomp.second); if (Line != ExpectedLine) { ++FirstComment; break; } - + // Set the next expected line number. - ExpectedLine + ExpectedLine = SourceMgr.getSpellingLineNumber(FirstComment->getBegin()) - 1; } - + // The iterator range [FirstComment, LastComment] contains all of the // BCPL comments that, together, are associated with this declaration. // Form a single comment block string for this declaration that concatenates @@ -396,10 +484,10 @@ const char *ASTContext::getCommentForDecl(const Decl *D) { FileBufferStart + DecompEnd.second + 1); ++FirstComment; } - + // Append the last comment line. - Result.append(FileBufferStart + - SourceMgr.getFileOffset(LastComment->getBegin()), + Result.append(FileBufferStart + + SourceMgr.getFileOffset(LastComment->getBegin()), FileBufferStart + LastCommentEndDecomp.second + 1); return Result.c_str(); } @@ -411,7 +499,7 @@ const char *ASTContext::getCommentForDecl(const Decl *D) { /// getFloatTypeSemantics - Return the APFloat 'semantics' for the specified /// scalar floating point type. const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { - const BuiltinType *BT = T->getAsBuiltinType(); + const BuiltinType *BT = T->getAs(); assert(BT && "Not a floating point type!"); switch (BT->getKind()) { default: assert(0 && "Not a floating point type!"); @@ -421,7 +509,7 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { } } -/// getDeclAlign - Return a conservative estimate of the alignment of the +/// getDeclAlignInBytes - 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. unsigned ASTContext::getDeclAlignInBytes(const Decl *D) { @@ -432,7 +520,7 @@ unsigned ASTContext::getDeclAlignInBytes(const Decl *D) { if (const ValueDecl *VD = dyn_cast(D)) { QualType T = VD->getType(); - if (const ReferenceType* RT = T->getAsReferenceType()) { + if (const ReferenceType* RT = T->getAs()) { unsigned AS = RT->getPointeeType().getAddressSpace(); Align = Target.getPointerAlign(AS); } else if (!T->isIncompleteType() && !T->isFunctionType()) { @@ -449,6 +537,10 @@ unsigned ASTContext::getDeclAlignInBytes(const Decl *D) { /// getTypeSize - Return the size of the specified type, in bits. This method /// does not work on incomplete types. +/// +/// FIXME: Pointers into different addr spaces could have different sizes and +/// alignment requirements: getPointerInfo should take an AddrSpace, this +/// should take a QualType, &c. std::pair ASTContext::getTypeInfo(const Type *T) { uint64_t Width=0; @@ -462,6 +554,10 @@ ASTContext::getTypeInfo(const Type *T) { assert(false && "Should not see dependent types"); break; + case Type::ObjCProtocolList: + assert(false && "Should not see protocol list types"); + break; + case Type::FunctionNoProto: case Type::FunctionProto: // GCC extension: alignof(function) = 32 bits @@ -475,9 +571,11 @@ ASTContext::getTypeInfo(const Type *T) { Align = getTypeAlign(cast(T)->getElementType()); break; + case Type::ConstantArrayWithExpr: + case Type::ConstantArrayWithoutExpr: case Type::ConstantArray: { const ConstantArrayType *CAT = cast(T); - + std::pair EltInfo = getTypeInfo(CAT->getElementType()); Width = EltInfo.first*CAT->getSize().getZExtValue(); Align = EltInfo.second; @@ -485,7 +583,7 @@ ASTContext::getTypeInfo(const Type *T) { } case Type::ExtVector: case Type::Vector: { - std::pair EltInfo = + std::pair EltInfo = getTypeInfo(cast(T)->getElementType()); Width = EltInfo.first*cast(T)->getNumElements(); Align = Width; @@ -520,6 +618,14 @@ ASTContext::getTypeInfo(const Type *T) { Width = Target.getWCharWidth(); Align = Target.getWCharAlign(); break; + case BuiltinType::Char16: + Width = Target.getChar16Width(); + Align = Target.getChar16Align(); + break; + case BuiltinType::Char32: + Width = Target.getChar32Width(); + Align = Target.getChar32Align(); + break; case BuiltinType::UShort: case BuiltinType::Short: Width = Target.getShortWidth(); @@ -570,12 +676,7 @@ ASTContext::getTypeInfo(const Type *T) { Width = std::max(llvm::NextPowerOf2(Width - 1), (uint64_t)8); Align = Width; break; - case Type::ExtQual: - // FIXME: Pointers into different addr spaces could have different sizes and - // alignment requirements: getPointerInfo should take an AddrSpace. - return getTypeInfo(QualType(cast(T)->getBaseType(), 0)); case Type::ObjCObjectPointer: - case Type::ObjCQualifiedInterface: Width = Target.getPointerWidth(0); Align = Target.getPointerAlign(0); break; @@ -604,7 +705,7 @@ ASTContext::getTypeInfo(const Type *T) { // If we ever want to support other ABIs this needs to be abstracted. QualType Pointee = cast(T)->getPointeeType(); - std::pair PtrDiffInfo = + std::pair PtrDiffInfo = getTypeInfo(getPointerDiffType()); Width = PtrDiffInfo.first; if (Pointee->isFunctionType()) @@ -615,7 +716,7 @@ ASTContext::getTypeInfo(const Type *T) { case Type::Complex: { // Complex types have the same alignment as their elements, but twice the // size. - std::pair EltInfo = + std::pair EltInfo = getTypeInfo(cast(T)->getElementType()); Width = EltInfo.first*2; Align = EltInfo.second; @@ -637,7 +738,7 @@ ASTContext::getTypeInfo(const Type *T) { Align = 1; break; } - + if (const EnumType *ET = dyn_cast(TT)) return getTypeInfo(ET->getDecl()->getIntegerType()); @@ -648,6 +749,10 @@ ASTContext::getTypeInfo(const Type *T) { break; } + case Type::Elaborated: { + return getTypeInfo(cast(T)->getUnderlyingType().getTypePtr()); + } + case Type::Typedef: { const TypedefDecl *Typedef = cast(T)->getDecl(); if (const AlignedAttr *Aligned = Typedef->getAttr()) { @@ -671,16 +776,16 @@ ASTContext::getTypeInfo(const Type *T) { case Type::QualifiedName: return getTypeInfo(cast(T)->getNamedType().getTypePtr()); - + case Type::TemplateSpecialization: - assert(getCanonicalType(T) != T && + assert(getCanonicalType(T) != T && "Cannot request the size of a dependent type"); // FIXME: this is likely to be wrong once we support template // aliases, since a template alias could refer to a typedef that // has an __aligned__ attribute on it. return getTypeInfo(getCanonicalType(T)); } - + assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2"); return std::make_pair(Width, Align); } @@ -693,7 +798,7 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) { unsigned ABIAlign = getTypeAlign(T); // Double and long long should be naturally aligned if possible. - if (const ComplexType* CT = T->getAsComplexType()) + if (const ComplexType* CT = T->getAs()) T = CT->getElementType().getTypePtr(); if (T->isSpecificBuiltinType(BuiltinType::Double) || T->isSpecificBuiltinType(BuiltinType::LongLong)) @@ -702,102 +807,6 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) { return ABIAlign; } - -/// LayoutField - Field layout. -void ASTRecordLayout::LayoutField(const FieldDecl *FD, unsigned FieldNo, - bool IsUnion, unsigned StructPacking, - ASTContext &Context) { - unsigned FieldPacking = StructPacking; - uint64_t FieldOffset = IsUnion ? 0 : Size; - uint64_t FieldSize; - unsigned FieldAlign; - - // FIXME: Should this override struct packing? Probably we want to - // take the minimum? - if (const PackedAttr *PA = FD->getAttr()) - FieldPacking = PA->getAlignment(); - - if (const Expr *BitWidthExpr = FD->getBitWidth()) { - // TODO: Need to check this algorithm on other targets! - // (tested on Linux-X86) - FieldSize = BitWidthExpr->EvaluateAsInt(Context).getZExtValue(); - - std::pair FieldInfo = - Context.getTypeInfo(FD->getType()); - uint64_t TypeSize = FieldInfo.first; - - // Determine the alignment of this bitfield. The packing - // attributes define a maximum and the alignment attribute defines - // a minimum. - // FIXME: What is the right behavior when the specified alignment - // is smaller than the specified packing? - FieldAlign = FieldInfo.second; - if (FieldPacking) - FieldAlign = std::min(FieldAlign, FieldPacking); - if (const AlignedAttr *AA = FD->getAttr()) - FieldAlign = std::max(FieldAlign, AA->getAlignment()); - - // Check if we need to add padding to give the field the correct - // alignment. - if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize) - FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); - - // Padding members don't affect overall alignment - if (!FD->getIdentifier()) - FieldAlign = 1; - } else { - if (FD->getType()->isIncompleteArrayType()) { - // This is a flexible array member; we can't directly - // query getTypeInfo about these, so we figure it out here. - // Flexible array members don't have any size, but they - // have to be aligned appropriately for their element type. - FieldSize = 0; - const ArrayType* ATy = Context.getAsArrayType(FD->getType()); - FieldAlign = Context.getTypeAlign(ATy->getElementType()); - } else if (const ReferenceType *RT = FD->getType()->getAsReferenceType()) { - unsigned AS = RT->getPointeeType().getAddressSpace(); - FieldSize = Context.Target.getPointerWidth(AS); - FieldAlign = Context.Target.getPointerAlign(AS); - } else { - std::pair FieldInfo = - Context.getTypeInfo(FD->getType()); - FieldSize = FieldInfo.first; - FieldAlign = FieldInfo.second; - } - - // Determine the alignment of this bitfield. The packing - // attributes define a maximum and the alignment attribute defines - // a minimum. Additionally, the packing alignment must be at least - // a byte for non-bitfields. - // - // FIXME: What is the right behavior when the specified alignment - // is smaller than the specified packing? - if (FieldPacking) - FieldAlign = std::min(FieldAlign, std::max(8U, FieldPacking)); - if (const AlignedAttr *AA = FD->getAttr()) - FieldAlign = std::max(FieldAlign, AA->getAlignment()); - - // Round up the current record size to the field's alignment boundary. - FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); - } - - // Place this field at the current location. - FieldOffsets[FieldNo] = FieldOffset; - - // Reserve space for this field. - if (IsUnion) { - Size = std::max(Size, FieldSize); - } else { - Size = FieldOffset + FieldSize; - } - - // Remember the next available offset. - NextOffset = Size; - - // Remember max struct/class alignment. - Alignment = std::max(Alignment, FieldAlign); -} - static void CollectLocalObjCIvars(ASTContext *Ctx, const ObjCInterfaceDecl *OI, llvm::SmallVectorImpl &Fields) { @@ -836,7 +845,7 @@ void ASTContext::CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD, E = PD->prop_end(); I != E; ++I) if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl()) Ivars.push_back(Ivar); - + // Also look into nested protocols. for (ObjCProtocolDecl::protocol_iterator P = PD->protocol_begin(), E = PD->protocol_end(); P != E; ++P) @@ -876,8 +885,7 @@ unsigned ASTContext::CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD) { return count; } -unsigned ASTContext::CountSynthesizedIvars(const ObjCInterfaceDecl *OI) -{ +unsigned ASTContext::CountSynthesizedIvars(const ObjCInterfaceDecl *OI) { unsigned count = 0; for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(), E = OI->prop_end(); I != E; ++I) { @@ -894,6 +902,52 @@ unsigned ASTContext::CountSynthesizedIvars(const ObjCInterfaceDecl *OI) return count; } +/// \brief Get the implementation of ObjCInterfaceDecl,or NULL if none exists. +ObjCImplementationDecl *ASTContext::getObjCImplementation(ObjCInterfaceDecl *D) { + llvm::DenseMap::iterator + I = ObjCImpls.find(D); + if (I != ObjCImpls.end()) + return cast(I->second); + return 0; +} +/// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists. +ObjCCategoryImplDecl *ASTContext::getObjCImplementation(ObjCCategoryDecl *D) { + llvm::DenseMap::iterator + I = ObjCImpls.find(D); + if (I != ObjCImpls.end()) + return cast(I->second); + return 0; +} + +/// \brief Set the implementation of ObjCInterfaceDecl. +void ASTContext::setObjCImplementation(ObjCInterfaceDecl *IFaceD, + ObjCImplementationDecl *ImplD) { + assert(IFaceD && ImplD && "Passed null params"); + ObjCImpls[IFaceD] = ImplD; +} +/// \brief Set the implementation of ObjCCategoryDecl. +void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD, + ObjCCategoryImplDecl *ImplD) { + assert(CatD && ImplD && "Passed null params"); + ObjCImpls[CatD] = ImplD; +} + +/// \brief Allocate an uninitialized DeclaratorInfo. +/// +/// The caller should initialize the memory held by DeclaratorInfo using +/// the TypeLoc wrappers. +/// +/// \param T the type that will be the basis for type source info. This type +/// should refer to how the declarator was written in source code, not to +/// what type semantic analysis resolved the declarator to. +DeclaratorInfo *ASTContext::CreateDeclaratorInfo(QualType T) { + unsigned DataSize = TypeLoc::getFullDataSizeForType(T); + DeclaratorInfo *DInfo = + (DeclaratorInfo*)BumpAlloc.Allocate(sizeof(DeclaratorInfo) + DataSize, 8); + new (DInfo) DeclaratorInfo(T); + return DInfo; +} + /// getInterfaceLayoutImpl - Get or compute information about the /// layout of the given interface. /// @@ -905,14 +959,14 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, assert(!D->isForwardDecl() && "Invalid interface decl!"); // Look up this layout, if already laid out, return what we have. - ObjCContainerDecl *Key = + ObjCContainerDecl *Key = Impl ? (ObjCContainerDecl*) Impl : (ObjCContainerDecl*) D; if (const ASTRecordLayout *Entry = ObjCLayouts[Key]) return *Entry; - unsigned FieldCount = D->ivar_size(); // Add in synthesized ivar count if laying out an implementation. if (Impl) { + unsigned FieldCount = D->ivar_size(); unsigned SynthCount = CountSynthesizedIvars(D); FieldCount += SynthCount; // If there aren't any sythesized ivars then reuse the interface @@ -923,40 +977,10 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, return getObjCLayout(D, 0); } - ASTRecordLayout *NewEntry = NULL; - if (ObjCInterfaceDecl *SD = D->getSuperClass()) { - const ASTRecordLayout &SL = getASTObjCInterfaceLayout(SD); - unsigned Alignment = SL.getAlignment(); - - // We start laying out ivars not at the end of the superclass - // structure, but at the next byte following the last field. - uint64_t Size = llvm::RoundUpToAlignment(SL.NextOffset, 8); + const ASTRecordLayout *NewEntry = + ASTRecordLayoutBuilder::ComputeLayout(*this, D, Impl); + ObjCLayouts[Key] = NewEntry; - ObjCLayouts[Key] = NewEntry = new ASTRecordLayout(Size, Alignment); - NewEntry->InitializeLayout(FieldCount); - } else { - ObjCLayouts[Key] = NewEntry = new ASTRecordLayout(); - NewEntry->InitializeLayout(FieldCount); - } - - unsigned StructPacking = 0; - if (const PackedAttr *PA = D->getAttr()) - StructPacking = PA->getAlignment(); - - if (const AlignedAttr *AA = D->getAttr()) - NewEntry->SetAlignment(std::max(NewEntry->getAlignment(), - AA->getAlignment())); - - // Layout each ivar sequentially. - unsigned i = 0; - llvm::SmallVector Ivars; - ShallowCollectObjCIvars(D, Ivars, Impl); - for (unsigned k = 0, e = Ivars.size(); k != e; ++k) - NewEntry->LayoutField(Ivars[k], i++, false, StructPacking, *this); - - // Finally, round the size of the total struct up to the alignment of the - // struct itself. - NewEntry->FinalizeLayout(); return *NewEntry; } @@ -978,37 +1002,15 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { assert(D && "Cannot get layout of forward declarations!"); // Look up this layout, if already laid out, return what we have. - const ASTRecordLayout *&Entry = ASTRecordLayouts[D]; + // Note that we can't save a reference to the entry because this function + // is recursive. + const ASTRecordLayout *Entry = ASTRecordLayouts[D]; if (Entry) return *Entry; - // Allocate and assign into ASTRecordLayouts here. The "Entry" reference can - // be invalidated (dangle) if the ASTRecordLayouts hashtable is inserted into. - ASTRecordLayout *NewEntry = new ASTRecordLayout(); - Entry = NewEntry; - - // FIXME: Avoid linear walk through the fields, if possible. - NewEntry->InitializeLayout(std::distance(D->field_begin(), D->field_end())); - bool IsUnion = D->isUnion(); - - unsigned StructPacking = 0; - if (const PackedAttr *PA = D->getAttr()) - StructPacking = PA->getAlignment(); - - if (const AlignedAttr *AA = D->getAttr()) - NewEntry->SetAlignment(std::max(NewEntry->getAlignment(), - AA->getAlignment())); - - // Layout each field, for now, just sequentially, respecting alignment. In - // the future, this will need to be tweakable by targets. - unsigned FieldIdx = 0; - for (RecordDecl::field_iterator Field = D->field_begin(), - FieldEnd = D->field_end(); - Field != FieldEnd; (void)++Field, ++FieldIdx) - NewEntry->LayoutField(*Field, FieldIdx, IsUnion, StructPacking, *this); - - // Finally, round the size of the total struct up to the alignment of the - // struct itself. - NewEntry->FinalizeLayout(getLangOptions().CPlusPlus); + const ASTRecordLayout *NewEntry = + ASTRecordLayoutBuilder::ComputeLayout(*this, D); + ASTRecordLayouts[D] = NewEntry; + return *NewEntry; } @@ -1016,102 +1018,111 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { // Type creation/memoization methods //===----------------------------------------------------------------------===// +QualType ASTContext::getExtQualType(const Type *TypeNode, Qualifiers Quals) { + unsigned Fast = Quals.getFastQualifiers(); + Quals.removeFastQualifiers(); + + // Check if we've already instantiated this type. + llvm::FoldingSetNodeID ID; + ExtQuals::Profile(ID, TypeNode, Quals); + void *InsertPos = 0; + if (ExtQuals *EQ = ExtQualNodes.FindNodeOrInsertPos(ID, InsertPos)) { + assert(EQ->getQualifiers() == Quals); + QualType T = QualType(EQ, Fast); + return T; + } + + ExtQuals *New = new (*this, TypeAlignment) ExtQuals(*this, TypeNode, Quals); + ExtQualNodes.InsertNode(New, InsertPos); + QualType T = QualType(New, Fast); + return T; +} + +QualType ASTContext::getVolatileType(QualType T) { + QualType CanT = getCanonicalType(T); + if (CanT.isVolatileQualified()) return T; + + QualifierCollector Quals; + const Type *TypeNode = Quals.strip(T); + Quals.addVolatile(); + + return getExtQualType(TypeNode, Quals); +} + QualType ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) { QualType CanT = getCanonicalType(T); if (CanT.getAddressSpace() == AddressSpace) return T; - // If we are composing extended qualifiers together, merge together into one - // ExtQualType node. - unsigned CVRQuals = T.getCVRQualifiers(); - QualType::GCAttrTypes GCAttr = QualType::GCNone; - Type *TypeNode = T.getTypePtr(); - - if (ExtQualType *EQT = dyn_cast(TypeNode)) { - // If this type already has an address space specified, it cannot get - // another one. - assert(EQT->getAddressSpace() == 0 && - "Type cannot be in multiple addr spaces!"); - GCAttr = EQT->getObjCGCAttr(); - TypeNode = EQT->getBaseType(); - } - - // Check if we've already instantiated this type. - llvm::FoldingSetNodeID ID; - ExtQualType::Profile(ID, TypeNode, AddressSpace, GCAttr); - void *InsertPos = 0; - if (ExtQualType *EXTQy = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(EXTQy, CVRQuals); + // If we are composing extended qualifiers together, merge together + // into one ExtQuals node. + QualifierCollector Quals; + const Type *TypeNode = Quals.strip(T); - // If the base type isn't canonical, this won't be a canonical type either, - // so fill in the canonical type field. - QualType Canonical; - if (!TypeNode->isCanonical()) { - Canonical = getAddrSpaceQualType(CanT, AddressSpace); - - // Update InsertPos, the previous call could have invalidated it. - ExtQualType *NewIP = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; - } - ExtQualType *New = - new (*this, 8) ExtQualType(TypeNode, Canonical, AddressSpace, GCAttr); - ExtQualTypes.InsertNode(New, InsertPos); - Types.push_back(New); - return QualType(New, CVRQuals); + // If this type already has an address space specified, it cannot get + // another one. + assert(!Quals.hasAddressSpace() && + "Type cannot be in multiple addr spaces!"); + Quals.addAddressSpace(AddressSpace); + + return getExtQualType(TypeNode, Quals); } QualType ASTContext::getObjCGCQualType(QualType T, - QualType::GCAttrTypes GCAttr) { + Qualifiers::GC GCAttr) { QualType CanT = getCanonicalType(T); if (CanT.getObjCGCAttr() == GCAttr) return T; - + if (T->isPointerType()) { - QualType Pointee = T->getAsPointerType()->getPointeeType(); - if (Pointee->isPointerType()) { + QualType Pointee = T->getAs()->getPointeeType(); + if (Pointee->isAnyPointerType()) { QualType ResultType = getObjCGCQualType(Pointee, GCAttr); return getPointerType(ResultType); } } - // If we are composing extended qualifiers together, merge together into one - // ExtQualType node. - unsigned CVRQuals = T.getCVRQualifiers(); - Type *TypeNode = T.getTypePtr(); - unsigned AddressSpace = 0; - - if (ExtQualType *EQT = dyn_cast(TypeNode)) { - // If this type already has an address space specified, it cannot get - // another one. - assert(EQT->getObjCGCAttr() == QualType::GCNone && - "Type cannot be in multiple addr spaces!"); - AddressSpace = EQT->getAddressSpace(); - TypeNode = EQT->getBaseType(); - } - - // Check if we've already instantiated an gc qual'd type of this type. - llvm::FoldingSetNodeID ID; - ExtQualType::Profile(ID, TypeNode, AddressSpace, GCAttr); - void *InsertPos = 0; - if (ExtQualType *EXTQy = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(EXTQy, CVRQuals); - - // If the base type isn't canonical, this won't be a canonical type either, - // so fill in the canonical type field. - // FIXME: Isn't this also not canonical if the base type is a array - // or pointer type? I can't find any documentation for objc_gc, though... - QualType Canonical; - if (!T->isCanonical()) { - Canonical = getObjCGCQualType(CanT, GCAttr); - - // Update InsertPos, the previous call could have invalidated it. - ExtQualType *NewIP = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + + // If we are composing extended qualifiers together, merge together + // into one ExtQuals node. + QualifierCollector Quals; + const Type *TypeNode = Quals.strip(T); + + // If this type already has an ObjCGC specified, it cannot get + // another one. + assert(!Quals.hasObjCGCAttr() && + "Type cannot have multiple ObjCGCs!"); + Quals.addObjCGCAttr(GCAttr); + + return getExtQualType(TypeNode, Quals); +} + +QualType ASTContext::getNoReturnType(QualType T) { + QualType ResultType; + if (T->isPointerType()) { + QualType Pointee = T->getAs()->getPointeeType(); + ResultType = getNoReturnType(Pointee); + ResultType = getPointerType(ResultType); + } else if (T->isBlockPointerType()) { + QualType Pointee = T->getAs()->getPointeeType(); + ResultType = getNoReturnType(Pointee); + ResultType = getBlockPointerType(ResultType); + } else { + assert (T->isFunctionType() + && "can't noreturn qualify non-pointer to function or block type"); + + if (const FunctionNoProtoType *FNPT = T->getAs()) { + ResultType = getFunctionNoProtoType(FNPT->getResultType(), true); + } else { + const FunctionProtoType *F = T->getAs(); + ResultType + = getFunctionType(F->getResultType(), F->arg_type_begin(), + F->getNumArgs(), F->isVariadic(), F->getTypeQuals(), + F->hasExceptionSpec(), F->hasAnyExceptionSpec(), + F->getNumExceptions(), F->exception_begin(), true); + } } - ExtQualType *New = - new (*this, 8) ExtQualType(TypeNode, Canonical, AddressSpace, GCAttr); - ExtQualTypes.InsertNode(New, InsertPos); - Types.push_back(New); - return QualType(New, CVRQuals); + + return getQualifiedType(ResultType, T.getQualifiers()); } /// getComplexType - Return the uniqued reference to the type for a complex @@ -1121,22 +1132,22 @@ QualType ASTContext::getComplexType(QualType T) { // structure. llvm::FoldingSetNodeID ID; ComplexType::Profile(ID, T); - + void *InsertPos = 0; if (ComplexType *CT = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(CT, 0); - + // If the pointee type isn't canonical, this won't be a canonical type either, // so fill in the canonical type field. QualType Canonical; if (!T->isCanonical()) { Canonical = getComplexType(getCanonicalType(T)); - + // Get the new insert position for the node we care about. ComplexType *NewIP = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - ComplexType *New = new (*this,8) ComplexType(T, Canonical); + ComplexType *New = new (*this, TypeAlignment) ComplexType(T, Canonical); Types.push_back(New); ComplexTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -1158,28 +1169,28 @@ QualType ASTContext::getPointerType(QualType T) { // structure. llvm::FoldingSetNodeID ID; PointerType::Profile(ID, T); - + void *InsertPos = 0; if (PointerType *PT = PointerTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(PT, 0); - + // If the pointee type isn't canonical, this won't be a canonical type either, // so fill in the canonical type field. QualType Canonical; if (!T->isCanonical()) { Canonical = getPointerType(getCanonicalType(T)); - + // Get the new insert position for the node we care about. PointerType *NewIP = PointerTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - PointerType *New = new (*this,8) PointerType(T, Canonical); + PointerType *New = new (*this, TypeAlignment) PointerType(T, Canonical); Types.push_back(New); PointerTypes.InsertNode(New, InsertPos); return QualType(New, 0); } -/// getBlockPointerType - Return the uniqued reference to the type for +/// getBlockPointerType - Return the uniqued reference to the type for /// a pointer to the specified block. QualType ASTContext::getBlockPointerType(QualType T) { assert(T->isFunctionType() && "block of function types only"); @@ -1187,24 +1198,25 @@ QualType ASTContext::getBlockPointerType(QualType T) { // structure. llvm::FoldingSetNodeID ID; BlockPointerType::Profile(ID, T); - + void *InsertPos = 0; if (BlockPointerType *PT = BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(PT, 0); - - // If the block pointee type isn't canonical, this won't be a canonical + + // If the block pointee type isn't canonical, this won't be a canonical // type either so fill in the canonical type field. QualType Canonical; if (!T->isCanonical()) { Canonical = getBlockPointerType(getCanonicalType(T)); - + // Get the new insert position for the node we care about. BlockPointerType *NewIP = BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - BlockPointerType *New = new (*this,8) BlockPointerType(T, Canonical); + BlockPointerType *New + = new (*this, TypeAlignment) BlockPointerType(T, Canonical); Types.push_back(New); BlockPointerTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -1235,7 +1247,8 @@ QualType ASTContext::getLValueReferenceType(QualType T) { assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - LValueReferenceType *New = new (*this,8) LValueReferenceType(T, Canonical); + LValueReferenceType *New + = new (*this, TypeAlignment) LValueReferenceType(T, Canonical); Types.push_back(New); LValueReferenceTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -1266,7 +1279,8 @@ QualType ASTContext::getRValueReferenceType(QualType T) { assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - RValueReferenceType *New = new (*this,8) RValueReferenceType(T, Canonical); + RValueReferenceType *New + = new (*this, TypeAlignment) RValueReferenceType(T, Canonical); Types.push_back(New); RValueReferenceTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -1274,8 +1288,7 @@ QualType ASTContext::getRValueReferenceType(QualType T) { /// getMemberPointerType - Return the uniqued reference to the type for a /// member pointer to the specified type, in the specified class. -QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) -{ +QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) { // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; @@ -1297,15 +1310,16 @@ QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - MemberPointerType *New = new (*this,8) MemberPointerType(T, Cls, Canonical); + MemberPointerType *New + = new (*this, TypeAlignment) MemberPointerType(T, Cls, Canonical); Types.push_back(New); MemberPointerTypes.InsertNode(New, InsertPos); return QualType(New, 0); } -/// getConstantArrayType - Return the unique reference to the type for an +/// getConstantArrayType - Return the unique reference to the type for an /// array of the specified element type. -QualType ASTContext::getConstantArrayType(QualType EltTy, +QualType ASTContext::getConstantArrayType(QualType EltTy, const llvm::APInt &ArySizeIn, ArrayType::ArraySizeModifier ASM, unsigned EltTypeQuals) { @@ -1316,44 +1330,93 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, // the target. llvm::APInt ArySize(ArySizeIn); ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace())); - + llvm::FoldingSetNodeID ID; ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, EltTypeQuals); - + void *InsertPos = 0; - if (ConstantArrayType *ATP = + if (ConstantArrayType *ATP = ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(ATP, 0); - + // 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 (!EltTy->isCanonical()) { - Canonical = getConstantArrayType(getCanonicalType(EltTy), ArySize, + Canonical = getConstantArrayType(getCanonicalType(EltTy), ArySize, ASM, EltTypeQuals); // Get the new insert position for the node we care about. - ConstantArrayType *NewIP = + ConstantArrayType *NewIP = ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - - ConstantArrayType *New = - new(*this,8)ConstantArrayType(EltTy, Canonical, ArySize, ASM, EltTypeQuals); + + ConstantArrayType *New = new(*this,TypeAlignment) + ConstantArrayType(EltTy, Canonical, ArySize, ASM, EltTypeQuals); ConstantArrayTypes.InsertNode(New, InsertPos); Types.push_back(New); return QualType(New, 0); } +/// getConstantArrayWithExprType - Return a reference to the type for +/// an array of the specified element type. +QualType +ASTContext::getConstantArrayWithExprType(QualType EltTy, + const llvm::APInt &ArySizeIn, + Expr *ArySizeExpr, + ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals, + SourceRange Brackets) { + // Convert the array size into a canonical width matching the pointer + // size for the target. + llvm::APInt ArySize(ArySizeIn); + ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace())); + + // Compute the canonical ConstantArrayType. + QualType Canonical = getConstantArrayType(getCanonicalType(EltTy), + ArySize, ASM, EltTypeQuals); + // Since we don't unique expressions, it isn't possible to unique VLA's + // that have an expression provided for their size. + ConstantArrayWithExprType *New = new(*this, TypeAlignment) + ConstantArrayWithExprType(EltTy, Canonical, ArySize, ArySizeExpr, + ASM, EltTypeQuals, Brackets); + Types.push_back(New); + return QualType(New, 0); +} + +/// getConstantArrayWithoutExprType - Return a reference to the type for +/// an array of the specified element type. +QualType +ASTContext::getConstantArrayWithoutExprType(QualType EltTy, + const llvm::APInt &ArySizeIn, + ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals) { + // Convert the array size into a canonical width matching the pointer + // size for the target. + llvm::APInt ArySize(ArySizeIn); + ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace())); + + // Compute the canonical ConstantArrayType. + QualType Canonical = getConstantArrayType(getCanonicalType(EltTy), + ArySize, ASM, EltTypeQuals); + ConstantArrayWithoutExprType *New = new(*this, TypeAlignment) + ConstantArrayWithoutExprType(EltTy, Canonical, ArySize, ASM, EltTypeQuals); + Types.push_back(New); + return QualType(New, 0); +} + /// getVariableArrayType - Returns a non-unique reference to the type for a /// variable array of the specified element type. -QualType ASTContext::getVariableArrayType(QualType EltTy, Expr *NumElts, +QualType ASTContext::getVariableArrayType(QualType EltTy, + Expr *NumElts, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals) { + unsigned EltTypeQuals, + SourceRange Brackets) { // Since we don't unique expressions, it isn't possible to unique VLA's // that have an expression provided for their size. - VariableArrayType *New = - new(*this,8)VariableArrayType(EltTy,QualType(), NumElts, ASM, EltTypeQuals); + VariableArrayType *New = new(*this, TypeAlignment) + VariableArrayType(EltTy, QualType(), NumElts, ASM, EltTypeQuals, Brackets); VariableArrayTypes.push_back(New); Types.push_back(New); @@ -1362,22 +1425,46 @@ QualType ASTContext::getVariableArrayType(QualType EltTy, Expr *NumElts, /// getDependentSizedArrayType - Returns a non-unique reference to /// the type for a dependently-sized array of the specified element -/// type. FIXME: We will need these to be uniqued, or at least -/// comparable, at some point. -QualType ASTContext::getDependentSizedArrayType(QualType EltTy, Expr *NumElts, +/// type. +QualType ASTContext::getDependentSizedArrayType(QualType EltTy, + Expr *NumElts, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals) { - assert((NumElts->isTypeDependent() || NumElts->isValueDependent()) && + unsigned EltTypeQuals, + SourceRange Brackets) { + assert((NumElts->isTypeDependent() || NumElts->isValueDependent()) && "Size must be type- or value-dependent!"); - // Since we don't unique expressions, it isn't possible to unique - // dependently-sized array types. + llvm::FoldingSetNodeID ID; + DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM, + EltTypeQuals, NumElts); - DependentSizedArrayType *New = - new (*this,8) DependentSizedArrayType(EltTy, QualType(), NumElts, - ASM, EltTypeQuals); + void *InsertPos = 0; + DependentSizedArrayType *Canon + = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos); + DependentSizedArrayType *New; + if (Canon) { + // We already have a canonical version of this array type; use it as + // the canonical type for a newly-built type. + New = new (*this, TypeAlignment) + DependentSizedArrayType(*this, EltTy, QualType(Canon, 0), + NumElts, ASM, EltTypeQuals, Brackets); + } else { + QualType CanonEltTy = getCanonicalType(EltTy); + if (CanonEltTy == EltTy) { + New = new (*this, TypeAlignment) + DependentSizedArrayType(*this, EltTy, QualType(), + NumElts, ASM, EltTypeQuals, Brackets); + DependentSizedArrayTypes.InsertNode(New, InsertPos); + } else { + QualType Canon = getDependentSizedArrayType(CanonEltTy, NumElts, + ASM, EltTypeQuals, + SourceRange()); + New = new (*this, TypeAlignment) + DependentSizedArrayType(*this, EltTy, Canon, + NumElts, ASM, EltTypeQuals, Brackets); + } + } - DependentSizedArrayTypes.push_back(New); Types.push_back(New); return QualType(New, 0); } @@ -1389,7 +1476,7 @@ QualType ASTContext::getIncompleteArrayType(QualType EltTy, IncompleteArrayType::Profile(ID, EltTy, ASM, EltTypeQuals); void *InsertPos = 0; - if (IncompleteArrayType *ATP = + if (IncompleteArrayType *ATP = IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(ATP, 0); @@ -1407,8 +1494,8 @@ QualType ASTContext::getIncompleteArrayType(QualType EltTy, assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - IncompleteArrayType *New = new (*this,8) IncompleteArrayType(EltTy, Canonical, - ASM, EltTypeQuals); + IncompleteArrayType *New = new (*this, TypeAlignment) + IncompleteArrayType(EltTy, Canonical, ASM, EltTypeQuals); IncompleteArrayTypes.InsertNode(New, InsertPos); Types.push_back(New); @@ -1419,13 +1506,13 @@ QualType ASTContext::getIncompleteArrayType(QualType EltTy, /// the specified element type and size. VectorType must be a built-in type. QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) { BuiltinType *baseType; - + baseType = dyn_cast(getCanonicalType(vecType).getTypePtr()); assert(baseType != 0 && "getVectorType(): Expecting a built-in type"); - + // 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); void *InsertPos = 0; if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(VTP, 0); @@ -1435,12 +1522,13 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) { QualType Canonical; if (!vecType->isCanonical()) { Canonical = getVectorType(getCanonicalType(vecType), NumElts); - + // 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,8) VectorType(vecType, NumElts, Canonical); + VectorType *New = new (*this, TypeAlignment) + VectorType(vecType, NumElts, Canonical); VectorTypes.InsertNode(New, InsertPos); Types.push_back(New); return QualType(New, 0); @@ -1450,13 +1538,13 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) { /// the specified element type and size. VectorType must be a built-in type. QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) { BuiltinType *baseType; - + baseType = dyn_cast(getCanonicalType(vecType).getTypePtr()); assert(baseType != 0 && "getExtVectorType(): Expecting a built-in type"); - + // 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); void *InsertPos = 0; if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(VTP, 0); @@ -1466,53 +1554,79 @@ QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) { QualType Canonical; if (!vecType->isCanonical()) { Canonical = getExtVectorType(getCanonicalType(vecType), NumElts); - + // 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; } - ExtVectorType *New = new (*this,8) ExtVectorType(vecType, NumElts, Canonical); + ExtVectorType *New = new (*this, TypeAlignment) + ExtVectorType(vecType, NumElts, Canonical); VectorTypes.InsertNode(New, InsertPos); Types.push_back(New); return QualType(New, 0); } -QualType ASTContext::getDependentSizedExtVectorType(QualType vecType, +QualType ASTContext::getDependentSizedExtVectorType(QualType vecType, Expr *SizeExpr, SourceLocation AttrLoc) { - DependentSizedExtVectorType *New = - new (*this,8) DependentSizedExtVectorType(vecType, QualType(), - SizeExpr, AttrLoc); + llvm::FoldingSetNodeID ID; + DependentSizedExtVectorType::Profile(ID, *this, getCanonicalType(vecType), + SizeExpr); + + void *InsertPos = 0; + DependentSizedExtVectorType *Canon + = DependentSizedExtVectorTypes.FindNodeOrInsertPos(ID, InsertPos); + DependentSizedExtVectorType *New; + if (Canon) { + // We already have a canonical version of this array type; use it as + // the canonical type for a newly-built type. + New = new (*this, TypeAlignment) + DependentSizedExtVectorType(*this, vecType, QualType(Canon, 0), + SizeExpr, AttrLoc); + } else { + QualType CanonVecTy = getCanonicalType(vecType); + if (CanonVecTy == vecType) { + New = new (*this, TypeAlignment) + DependentSizedExtVectorType(*this, vecType, QualType(), SizeExpr, + AttrLoc); + DependentSizedExtVectorTypes.InsertNode(New, InsertPos); + } else { + QualType Canon = getDependentSizedExtVectorType(CanonVecTy, SizeExpr, + SourceLocation()); + New = new (*this, TypeAlignment) + DependentSizedExtVectorType(*this, vecType, Canon, SizeExpr, AttrLoc); + } + } - DependentSizedExtVectorTypes.push_back(New); Types.push_back(New); return QualType(New, 0); } /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// -QualType ASTContext::getFunctionNoProtoType(QualType ResultTy) { +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); - + FunctionNoProtoType::Profile(ID, ResultTy, NoReturn); + void *InsertPos = 0; - if (FunctionNoProtoType *FT = + if (FunctionNoProtoType *FT = FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(FT, 0); - + QualType Canonical; if (!ResultTy->isCanonical()) { - Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy)); - + Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn); + // Get the new insert position for the node we care about. FunctionNoProtoType *NewIP = FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - - FunctionNoProtoType *New =new(*this,8)FunctionNoProtoType(ResultTy,Canonical); + + FunctionNoProtoType *New = new (*this, TypeAlignment) + FunctionNoProtoType(ResultTy, Canonical, NoReturn); Types.push_back(New); FunctionNoProtoTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -1524,16 +1638,22 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, unsigned NumArgs, bool isVariadic, unsigned TypeQuals, bool hasExceptionSpec, bool hasAnyExceptionSpec, unsigned NumExs, - const QualType *ExArray) { + const QualType *ExArray, bool NoReturn) { + if (LangOpts.CPlusPlus) { + for (unsigned i = 0; i != NumArgs; ++i) + assert(!ArgArray[i].hasQualifiers() && + "C++ arguments can't have toplevel qualifiers!"); + } + // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic, TypeQuals, hasExceptionSpec, hasAnyExceptionSpec, - NumExs, ExArray); + NumExs, ExArray, NoReturn); void *InsertPos = 0; - if (FunctionProtoType *FTP = + if (FunctionProtoType *FTP = FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(FTP, 0); @@ -1556,7 +1676,8 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, Canonical = getFunctionType(getCanonicalType(ResultTy), CanonicalArgs.data(), NumArgs, - isVariadic, TypeQuals); + isVariadic, TypeQuals, false, + false, 0, 0, NoReturn); // Get the new insert position for the node we care about. FunctionProtoType *NewIP = @@ -1567,13 +1688,13 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, // FunctionProtoType objects are allocated with extra bytes after them // for two variable size arrays (for parameter and exception types) at the // end of them. - FunctionProtoType *FTP = + FunctionProtoType *FTP = (FunctionProtoType*)Allocate(sizeof(FunctionProtoType) + NumArgs*sizeof(QualType) + - NumExs*sizeof(QualType), 8); + NumExs*sizeof(QualType), TypeAlignment); new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic, TypeQuals, hasExceptionSpec, hasAnyExceptionSpec, - ExArray, NumExs, Canonical); + ExArray, NumExs, Canonical, NoReturn); Types.push_back(FTP); FunctionProtoTypes.InsertNode(FTP, InsertPos); return QualType(FTP, 0); @@ -1584,27 +1705,26 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) { assert(Decl && "Passed null for Decl param"); if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); - + if (TypedefDecl *Typedef = dyn_cast(Decl)) return getTypedefType(Typedef); else if (isa(Decl)) { assert(false && "Template type parameter types are always available."); - } else if (ObjCInterfaceDecl *ObjCInterface = dyn_cast(Decl)) + } else if (ObjCInterfaceDecl *ObjCInterface + = dyn_cast(Decl)) return getObjCInterfaceType(ObjCInterface); if (RecordDecl *Record = dyn_cast(Decl)) { if (PrevDecl) Decl->TypeForDecl = PrevDecl->TypeForDecl; else - Decl->TypeForDecl = new (*this,8) RecordType(Record); - } - else if (EnumDecl *Enum = dyn_cast(Decl)) { + Decl->TypeForDecl = new (*this, TypeAlignment) RecordType(Record); + } else if (EnumDecl *Enum = dyn_cast(Decl)) { if (PrevDecl) Decl->TypeForDecl = PrevDecl->TypeForDecl; else - Decl->TypeForDecl = new (*this,8) EnumType(Enum); - } - else + Decl->TypeForDecl = new (*this, TypeAlignment) EnumType(Enum); + } else assert(false && "TypeDecl without a type?"); if (!PrevDecl) Types.push_back(Decl->TypeForDecl); @@ -1615,45 +1735,36 @@ QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) { /// specified typename decl. QualType ASTContext::getTypedefType(TypedefDecl *Decl) { if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); - + QualType Canonical = getCanonicalType(Decl->getUnderlyingType()); - Decl->TypeForDecl = new(*this,8) TypedefType(Type::Typedef, Decl, Canonical); - Types.push_back(Decl->TypeForDecl); - return QualType(Decl->TypeForDecl, 0); -} - -/// getObjCInterfaceType - Return the unique reference to the type for the -/// specified ObjC interface decl. -QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl) { - if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); - - ObjCInterfaceDecl *OID = const_cast(Decl); - Decl->TypeForDecl = new(*this,8) ObjCInterfaceType(Type::ObjCInterface, OID); + Decl->TypeForDecl = new(*this, TypeAlignment) + TypedefType(Type::Typedef, Decl, Canonical); Types.push_back(Decl->TypeForDecl); return QualType(Decl->TypeForDecl, 0); } /// \brief Retrieve the template type parameter type for a template -/// parameter or parameter pack with the given depth, index, and (optionally) +/// parameter or parameter pack with the given depth, index, and (optionally) /// name. -QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, +QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, bool ParameterPack, IdentifierInfo *Name) { llvm::FoldingSetNodeID ID; TemplateTypeParmType::Profile(ID, Depth, Index, ParameterPack, Name); void *InsertPos = 0; - TemplateTypeParmType *TypeParm + TemplateTypeParmType *TypeParm = TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); if (TypeParm) return QualType(TypeParm, 0); - + if (Name) { QualType Canon = getTemplateTypeParmType(Depth, Index, ParameterPack); - TypeParm = new (*this, 8) TemplateTypeParmType(Depth, Index, ParameterPack, - Name, Canon); + TypeParm = new (*this, TypeAlignment) + TemplateTypeParmType(Depth, Index, ParameterPack, Name, Canon); } else - TypeParm = new (*this, 8) TemplateTypeParmType(Depth, Index, ParameterPack); + TypeParm = new (*this, TypeAlignment) + TemplateTypeParmType(Depth, Index, ParameterPack); Types.push_back(TypeParm); TemplateTypeParmTypes.InsertNode(TypeParm, InsertPos); @@ -1661,54 +1772,83 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, return QualType(TypeParm, 0); } -QualType +QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgument *Args, unsigned NumArgs, QualType Canon) { if (!Canon.isNull()) Canon = getCanonicalType(Canon); + else { + // Build the canonical template specialization type. + TemplateName CanonTemplate = getCanonicalTemplateName(Template); + llvm::SmallVector CanonArgs; + CanonArgs.reserve(NumArgs); + for (unsigned I = 0; I != NumArgs; ++I) + CanonArgs.push_back(getCanonicalTemplateArgument(Args[I])); + + // Determine whether this canonical template specialization type already + // exists. + llvm::FoldingSetNodeID ID; + TemplateSpecializationType::Profile(ID, CanonTemplate, + CanonArgs.data(), NumArgs, *this); + + void *InsertPos = 0; + TemplateSpecializationType *Spec + = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); + + if (!Spec) { + // Allocate a new canonical template specialization type. + void *Mem = Allocate((sizeof(TemplateSpecializationType) + + sizeof(TemplateArgument) * NumArgs), + TypeAlignment); + Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate, + CanonArgs.data(), NumArgs, + Canon); + Types.push_back(Spec); + TemplateSpecializationTypes.InsertNode(Spec, InsertPos); + } - llvm::FoldingSetNodeID ID; - TemplateSpecializationType::Profile(ID, Template, Args, NumArgs); + if (Canon.isNull()) + Canon = QualType(Spec, 0); + assert(Canon->isDependentType() && + "Non-dependent template-id type must have a canonical type"); + } - void *InsertPos = 0; + // Allocate the (non-canonical) template specialization type, but don't + // try to unique it: these types typically have location information that + // we don't unique and don't want to lose. + void *Mem = Allocate((sizeof(TemplateSpecializationType) + + sizeof(TemplateArgument) * NumArgs), + TypeAlignment); TemplateSpecializationType *Spec - = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); + = new (Mem) TemplateSpecializationType(*this, Template, Args, NumArgs, + Canon); - if (Spec) - return QualType(Spec, 0); - - void *Mem = Allocate((sizeof(TemplateSpecializationType) + - sizeof(TemplateArgument) * NumArgs), - 8); - Spec = new (Mem) TemplateSpecializationType(Template, Args, NumArgs, Canon); Types.push_back(Spec); - TemplateSpecializationTypes.InsertNode(Spec, InsertPos); - - return QualType(Spec, 0); + return QualType(Spec, 0); } -QualType +QualType ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS, QualType NamedType) { llvm::FoldingSetNodeID ID; QualifiedNameType::Profile(ID, NNS, NamedType); void *InsertPos = 0; - QualifiedNameType *T + QualifiedNameType *T = QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos); if (T) return QualType(T, 0); - T = new (*this) QualifiedNameType(NNS, NamedType, + T = new (*this) QualifiedNameType(NNS, NamedType, getCanonicalType(NamedType)); Types.push_back(T); QualifiedNameTypes.InsertNode(T, InsertPos); return QualType(T, 0); } -QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS, +QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo *Name, QualType Canon) { assert(NNS->isDependent() && "nested-name-specifier must be dependent"); @@ -1723,7 +1863,7 @@ QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS, TypenameType::Profile(ID, NNS, Name); void *InsertPos = 0; - TypenameType *T + TypenameType *T = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos); if (T) return QualType(T, 0); @@ -1731,11 +1871,11 @@ QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS, T = new (*this) TypenameType(NNS, Name, Canon); Types.push_back(T); TypenameTypes.InsertNode(T, InsertPos); - return QualType(T, 0); + return QualType(T, 0); } -QualType -ASTContext::getTypenameType(NestedNameSpecifier *NNS, +QualType +ASTContext::getTypenameType(NestedNameSpecifier *NNS, const TemplateSpecializationType *TemplateId, QualType Canon) { assert(NNS->isDependent() && "nested-name-specifier must be dependent"); @@ -1745,7 +1885,7 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS, QualType CanonType = getCanonicalType(QualType(TemplateId, 0)); if (CanonNNS != NNS || CanonType != QualType(TemplateId, 0)) { const TemplateSpecializationType *CanonTemplateId - = CanonType->getAsTemplateSpecializationType(); + = CanonType->getAs(); assert(CanonTemplateId && "Canonical type must also be a template specialization type"); Canon = getTypenameType(CanonNNS, CanonTemplateId); @@ -1756,7 +1896,7 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS, TypenameType::Profile(ID, NNS, TemplateId); void *InsertPos = 0; - TypenameType *T + TypenameType *T = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos); if (T) return QualType(T, 0); @@ -1764,7 +1904,26 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS, T = new (*this) TypenameType(NNS, TemplateId, Canon); Types.push_back(T); TypenameTypes.InsertNode(T, InsertPos); - return QualType(T, 0); + return QualType(T, 0); +} + +QualType +ASTContext::getElaboratedType(QualType UnderlyingType, + ElaboratedType::TagKind Tag) { + llvm::FoldingSetNodeID ID; + ElaboratedType::Profile(ID, UnderlyingType, Tag); + + void *InsertPos = 0; + ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return QualType(T, 0); + + QualType Canon = getCanonicalType(UnderlyingType); + + T = new (*this) ElaboratedType(UnderlyingType, Tag, Canon); + Types.push_back(T); + ElaboratedTypes.InsertNode(T, InsertPos); + return QualType(T, 0); } /// CmpProtocolNames - Comparison predicate for sorting protocols @@ -1777,7 +1936,7 @@ static bool CmpProtocolNames(const ObjCProtocolDecl *LHS, static void SortAndUniqueProtocols(ObjCProtocolDecl **&Protocols, unsigned &NumProtocols) { ObjCProtocolDecl **ProtocolsEnd = Protocols+NumProtocols; - + // Sort protocols, keyed by name. std::sort(Protocols, Protocols+NumProtocols, CmpProtocolNames); @@ -1788,15 +1947,15 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **&Protocols, /// getObjCObjectPointerType - Return a ObjCObjectPointerType type for /// the given interface decl and the conforming protocol list. -QualType ASTContext::getObjCObjectPointerType(ObjCInterfaceDecl *Decl, - ObjCProtocolDecl **Protocols, +QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT, + ObjCProtocolDecl **Protocols, unsigned NumProtocols) { // Sort the protocol list alphabetically to canonicalize it. if (NumProtocols) SortAndUniqueProtocols(Protocols, NumProtocols); llvm::FoldingSetNodeID ID; - ObjCObjectPointerType::Profile(ID, Decl, Protocols, NumProtocols); + ObjCObjectPointerType::Profile(ID, InterfaceT, Protocols, NumProtocols); void *InsertPos = 0; if (ObjCObjectPointerType *QT = @@ -1804,46 +1963,89 @@ QualType ASTContext::getObjCObjectPointerType(ObjCInterfaceDecl *Decl, return QualType(QT, 0); // No Match; - ObjCObjectPointerType *QType = - new (*this,8) ObjCObjectPointerType(Decl, Protocols, NumProtocols); - + ObjCObjectPointerType *QType = new (*this, TypeAlignment) + ObjCObjectPointerType(InterfaceT, Protocols, NumProtocols); + Types.push_back(QType); ObjCObjectPointerTypes.InsertNode(QType, InsertPos); return QualType(QType, 0); } -/// getObjCQualifiedInterfaceType - Return a ObjCQualifiedInterfaceType type for -/// the given interface decl and the conforming protocol list. -QualType ASTContext::getObjCQualifiedInterfaceType(ObjCInterfaceDecl *Decl, +/// getObjCInterfaceType - Return the unique reference to the type for the +/// specified ObjC interface decl. The list of protocols is optional. +QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl, ObjCProtocolDecl **Protocols, unsigned NumProtocols) { - // Sort the protocol list alphabetically to canonicalize it. - SortAndUniqueProtocols(Protocols, NumProtocols); - + if (NumProtocols) + // Sort the protocol list alphabetically to canonicalize it. + SortAndUniqueProtocols(Protocols, NumProtocols); + llvm::FoldingSetNodeID ID; - ObjCQualifiedInterfaceType::Profile(ID, Decl, Protocols, NumProtocols); - + ObjCInterfaceType::Profile(ID, Decl, Protocols, NumProtocols); + void *InsertPos = 0; - if (ObjCQualifiedInterfaceType *QT = - ObjCQualifiedInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos)) + if (ObjCInterfaceType *QT = + ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(QT, 0); - + // No Match; - ObjCQualifiedInterfaceType *QType = - new (*this,8) ObjCQualifiedInterfaceType(Decl, Protocols, NumProtocols); + ObjCInterfaceType *QType = new (*this, TypeAlignment) + ObjCInterfaceType(const_cast(Decl), + Protocols, NumProtocols); + Types.push_back(QType); + ObjCInterfaceTypes.InsertNode(QType, InsertPos); + return QualType(QType, 0); +} +QualType ASTContext::getObjCProtocolListType(QualType T, + ObjCProtocolDecl **Protocols, + unsigned NumProtocols) { + llvm::FoldingSetNodeID ID; + ObjCProtocolListType::Profile(ID, T, Protocols, NumProtocols); + + void *InsertPos = 0; + if (ObjCProtocolListType *QT = + ObjCProtocolListTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(QT, 0); + + // No Match; + ObjCProtocolListType *QType = new (*this, TypeAlignment) + ObjCProtocolListType(T, Protocols, NumProtocols); Types.push_back(QType); - ObjCQualifiedInterfaceTypes.InsertNode(QType, InsertPos); + ObjCProtocolListTypes.InsertNode(QType, InsertPos); return QualType(QType, 0); } /// getTypeOfExprType - Unlike many "get" functions, we can't unique /// TypeOfExprType AST's (since expression's are never shared). For example, /// multiple declarations that refer to "typeof(x)" all contain different -/// DeclRefExpr's. This doesn't effect the type checker, since it operates +/// DeclRefExpr's. This doesn't effect the type checker, since it operates /// on canonical type's (which are always unique). QualType ASTContext::getTypeOfExprType(Expr *tofExpr) { - QualType Canonical = getCanonicalType(tofExpr->getType()); - TypeOfExprType *toe = new (*this,8) TypeOfExprType(tofExpr, Canonical); + TypeOfExprType *toe; + if (tofExpr->isTypeDependent()) { + llvm::FoldingSetNodeID ID; + DependentTypeOfExprType::Profile(ID, *this, tofExpr); + + void *InsertPos = 0; + DependentTypeOfExprType *Canon + = DependentTypeOfExprTypes.FindNodeOrInsertPos(ID, InsertPos); + if (Canon) { + // We already have a "canonical" version of an identical, dependent + // typeof(expr) type. Use that as our canonical type. + toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr, + QualType((TypeOfExprType*)Canon, 0)); + } + else { + // Build a new, canonical typeof(expr) type. + Canon + = new (*this, TypeAlignment) DependentTypeOfExprType(*this, tofExpr); + DependentTypeOfExprTypes.InsertNode(Canon, InsertPos); + toe = Canon; + } + } else { + QualType Canonical = getCanonicalType(tofExpr->getType()); + toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr, Canonical); + } Types.push_back(toe); return QualType(toe, 0); } @@ -1851,11 +2053,11 @@ QualType ASTContext::getTypeOfExprType(Expr *tofExpr) { /// getTypeOfType - Unlike many "get" functions, we don't unique /// TypeOfType AST's. The only motivation to unique these nodes would be /// memory savings. Since typeof(t) is fairly uncommon, space shouldn't be -/// an issue. This doesn't effect the type checker, since it operates +/// an issue. This doesn't effect the type checker, since it operates /// on canonical type's (which are always unique). QualType ASTContext::getTypeOfType(QualType tofType) { QualType Canonical = getCanonicalType(tofType); - TypeOfType *tot = new (*this,8) TypeOfType(tofType, Canonical); + TypeOfType *tot = new (*this, TypeAlignment) TypeOfType(tofType, Canonical); Types.push_back(tot); return QualType(tot, 0); } @@ -1865,7 +2067,7 @@ QualType ASTContext::getTypeOfType(QualType tofType) { static QualType getDecltypeForExpr(const Expr *e, ASTContext &Context) { if (e->isTypeDependent()) return Context.DependentTy; - + // If e is an id expression or a class member access, decltype(e) is defined // as the type of the entity named by e. if (const DeclRefExpr *DRE = dyn_cast(e)) { @@ -1881,39 +2083,63 @@ static QualType getDecltypeForExpr(const Expr *e, ASTContext &Context) { // return type of that function. if (const CallExpr *CE = dyn_cast(e->IgnoreParens())) return CE->getCallReturnType(); - + QualType T = e->getType(); - - // Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is + + // Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is // defined as T&, otherwise decltype(e) is defined as T. if (e->isLvalue(Context) == Expr::LV_Valid) T = Context.getLValueReferenceType(T); - + return T; } /// getDecltypeType - Unlike many "get" functions, we don't unique /// DecltypeType AST's. The only motivation to unique these nodes would be /// memory savings. Since decltype(t) is fairly uncommon, space shouldn't be -/// an issue. This doesn't effect the type checker, since it operates +/// an issue. This doesn't effect the type checker, since it operates /// on canonical type's (which are always unique). QualType ASTContext::getDecltypeType(Expr *e) { - QualType T = getDecltypeForExpr(e, *this); - DecltypeType *dt = new (*this, 8) DecltypeType(e, getCanonicalType(T)); + DecltypeType *dt; + if (e->isTypeDependent()) { + llvm::FoldingSetNodeID ID; + DependentDecltypeType::Profile(ID, *this, e); + + void *InsertPos = 0; + DependentDecltypeType *Canon + = DependentDecltypeTypes.FindNodeOrInsertPos(ID, InsertPos); + if (Canon) { + // We already have a "canonical" version of an equivalent, dependent + // decltype type. Use that as our canonical type. + dt = new (*this, TypeAlignment) DecltypeType(e, DependentTy, + QualType((DecltypeType*)Canon, 0)); + } + else { + // Build a new, canonical typeof(expr) type. + Canon = new (*this, TypeAlignment) DependentDecltypeType(*this, e); + DependentDecltypeTypes.InsertNode(Canon, InsertPos); + dt = Canon; + } + } else { + QualType T = getDecltypeForExpr(e, *this); + dt = new (*this, TypeAlignment) DecltypeType(e, T, getCanonicalType(T)); + } Types.push_back(dt); return QualType(dt, 0); } /// getTagDeclType - Return the unique reference to the type for the /// specified TagDecl (struct/union/class/enum) decl. -QualType ASTContext::getTagDeclType(TagDecl *Decl) { +QualType ASTContext::getTagDeclType(const TagDecl *Decl) { assert (Decl); - return getTypeDeclType(Decl); + // FIXME: What is the design on getTagDeclType when it requires casting + // away const? mutable? + return getTypeDeclType(const_cast(Decl)); } -/// getSizeType - Return the unique type for "size_t" (C99 7.17), the result -/// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and -/// needs to agree with the definition in . +/// getSizeType - Return the unique type for "size_t" (C99 7.17), the result +/// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and +/// needs to agree with the definition in . QualType ASTContext::getSizeType() const { return getFromTargetType(Target.getSizeType()); } @@ -1948,99 +2174,143 @@ QualType ASTContext::getPointerDiffType() const { /// include typedefs, 'typeof' operators, etc. The returned type is guaranteed /// to be free of any of these, allowing two canonical types to be compared /// for exact equality with a simple pointer comparison. -QualType ASTContext::getCanonicalType(QualType T) { - QualType CanType = T.getTypePtr()->getCanonicalTypeInternal(); - - // If the result has type qualifiers, make sure to canonicalize them as well. - unsigned TypeQuals = T.getCVRQualifiers() | CanType.getCVRQualifiers(); - if (TypeQuals == 0) return CanType; +CanQualType ASTContext::getCanonicalType(QualType T) { + QualifierCollector Quals; + const Type *Ptr = Quals.strip(T); + QualType CanType = Ptr->getCanonicalTypeInternal(); + + // The canonical internal type will be the canonical type *except* + // that we push type qualifiers down through array types. + + // If there are no new qualifiers to push down, stop here. + if (!Quals.hasQualifiers()) + return CanQualType::CreateUnsafe(CanType); - // If the type qualifiers are on an array type, get the canonical type of the - // array with the qualifiers applied to the element type. + // If the type qualifiers are on an array type, get the canonical + // type of the array with the qualifiers applied to the element + // type. ArrayType *AT = dyn_cast(CanType); if (!AT) - return CanType.getQualifiedType(TypeQuals); - + return CanQualType::CreateUnsafe(getQualifiedType(CanType, Quals)); + // Get the canonical version of the element with the extra qualifiers on it. // This can recursively sink qualifiers through multiple levels of arrays. - QualType NewEltTy=AT->getElementType().getWithAdditionalQualifiers(TypeQuals); + QualType NewEltTy = getQualifiedType(AT->getElementType(), Quals); NewEltTy = getCanonicalType(NewEltTy); - + if (ConstantArrayType *CAT = dyn_cast(AT)) - return getConstantArrayType(NewEltTy, CAT->getSize(),CAT->getSizeModifier(), - CAT->getIndexTypeQualifier()); + return CanQualType::CreateUnsafe( + getConstantArrayType(NewEltTy, CAT->getSize(), + CAT->getSizeModifier(), + CAT->getIndexTypeCVRQualifiers())); if (IncompleteArrayType *IAT = dyn_cast(AT)) - return getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), - IAT->getIndexTypeQualifier()); - + return CanQualType::CreateUnsafe( + getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), + IAT->getIndexTypeCVRQualifiers())); + if (DependentSizedArrayType *DSAT = dyn_cast(AT)) - return getDependentSizedArrayType(NewEltTy, DSAT->getSizeExpr(), - DSAT->getSizeModifier(), - DSAT->getIndexTypeQualifier()); + return CanQualType::CreateUnsafe( + getDependentSizedArrayType(NewEltTy, + DSAT->getSizeExpr() ? + DSAT->getSizeExpr()->Retain() : 0, + DSAT->getSizeModifier(), + DSAT->getIndexTypeCVRQualifiers(), + DSAT->getBracketsRange())); VariableArrayType *VAT = cast(AT); - return getVariableArrayType(NewEltTy, VAT->getSizeExpr(), - VAT->getSizeModifier(), - VAT->getIndexTypeQualifier()); -} - -Decl *ASTContext::getCanonicalDecl(Decl *D) { - if (!D) - return 0; - - if (TagDecl *Tag = dyn_cast(D)) { - QualType T = getTagDeclType(Tag); - return cast(cast(T.getTypePtr()->CanonicalType) - ->getDecl()); - } - - if (ClassTemplateDecl *Template = dyn_cast(D)) { - while (Template->getPreviousDeclaration()) - Template = Template->getPreviousDeclaration(); - return Template; - } - - if (const FunctionDecl *Function = dyn_cast(D)) { - while (Function->getPreviousDeclaration()) - Function = Function->getPreviousDeclaration(); - return const_cast(Function); - } - - if (FunctionTemplateDecl *FunTmpl = dyn_cast(D)) { - while (FunTmpl->getPreviousDeclaration()) - FunTmpl = FunTmpl->getPreviousDeclaration(); - return FunTmpl; - } - - if (const VarDecl *Var = dyn_cast(D)) { - while (Var->getPreviousDeclaration()) - Var = Var->getPreviousDeclaration(); - return const_cast(Var); - } - - return D; + return CanQualType::CreateUnsafe(getVariableArrayType(NewEltTy, + VAT->getSizeExpr() ? + VAT->getSizeExpr()->Retain() : 0, + VAT->getSizeModifier(), + VAT->getIndexTypeCVRQualifiers(), + VAT->getBracketsRange())); } TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) { // If this template name refers to a template, the canonical // template name merely stores the template itself. if (TemplateDecl *Template = Name.getAsTemplateDecl()) - return TemplateName(cast(getCanonicalDecl(Template))); + return TemplateName(cast(Template->getCanonicalDecl())); + + // If this template name refers to a set of overloaded function templates, + /// the canonical template name merely stores the set of function templates. + if (OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl()) { + OverloadedFunctionDecl *CanonOvl = 0; + for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), + FEnd = Ovl->function_end(); + F != FEnd; ++F) { + Decl *Canon = F->get()->getCanonicalDecl(); + if (CanonOvl || Canon != F->get()) { + if (!CanonOvl) + CanonOvl = OverloadedFunctionDecl::Create(*this, + Ovl->getDeclContext(), + Ovl->getDeclName()); + + CanonOvl->addOverload( + AnyFunctionDecl::getFromNamedDecl(cast(Canon))); + } + } + + return TemplateName(CanonOvl? CanonOvl : Ovl); + } DependentTemplateName *DTN = Name.getAsDependentTemplateName(); assert(DTN && "Non-dependent template names must refer to template decls."); return DTN->CanonicalTemplateName; } +TemplateArgument +ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + return Arg; + + case TemplateArgument::Expression: + // FIXME: Build canonical expression? + return Arg; + + case TemplateArgument::Declaration: + return TemplateArgument(SourceLocation(), + Arg.getAsDecl()->getCanonicalDecl()); + + case TemplateArgument::Integral: + return TemplateArgument(SourceLocation(), + *Arg.getAsIntegral(), + getCanonicalType(Arg.getIntegralType())); + + case TemplateArgument::Type: + return TemplateArgument(SourceLocation(), + getCanonicalType(Arg.getAsType())); + + case TemplateArgument::Pack: { + // FIXME: Allocate in ASTContext + TemplateArgument *CanonArgs = new TemplateArgument[Arg.pack_size()]; + unsigned Idx = 0; + for (TemplateArgument::pack_iterator A = Arg.pack_begin(), + AEnd = Arg.pack_end(); + A != AEnd; (void)++A, ++Idx) + CanonArgs[Idx] = getCanonicalTemplateArgument(*A); + + TemplateArgument Result; + Result.setArgumentPack(CanonArgs, Arg.pack_size(), false); + return Result; + } + } + + // Silence GCC warning + assert(false && "Unhandled template argument kind"); + return TemplateArgument(); +} + NestedNameSpecifier * ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) { - if (!NNS) + if (!NNS) return 0; switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: // Canonicalize the prefix but keep the identifier the same. - return NestedNameSpecifier::Create(*this, + return NestedNameSpecifier::Create(*this, getCanonicalNestedNameSpecifier(NNS->getPrefix()), NNS->getAsIdentifier()); @@ -2052,14 +2322,8 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) { case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { QualType T = getCanonicalType(QualType(NNS->getAsType(), 0)); - NestedNameSpecifier *Prefix = 0; - - // FIXME: This isn't the right check! - if (T->isDependentType()) - Prefix = getCanonicalNestedNameSpecifier(NNS->getPrefix()); - - return NestedNameSpecifier::Create(*this, Prefix, - NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate, + return NestedNameSpecifier::Create(*this, 0, + NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate, T.getTypePtr()); } @@ -2075,81 +2339,65 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) { const ArrayType *ASTContext::getAsArrayType(QualType T) { // Handle the non-qualified case efficiently. - if (T.getCVRQualifiers() == 0) { + if (!T.hasQualifiers()) { // Handle the common positive case fast. if (const ArrayType *AT = dyn_cast(T)) return AT; } - - // Handle the common negative case fast, ignoring CVR qualifiers. + + // Handle the common negative case fast. QualType CType = T->getCanonicalTypeInternal(); - - // Make sure to look through type qualifiers (like ExtQuals) for the negative - // test. - if (!isa(CType) && - !isa(CType.getUnqualifiedType())) + if (!isa(CType)) return 0; - - // Apply any CVR qualifiers from the array type to the element type. This + + // Apply any qualifiers from the array type to the element type. This // implements C99 6.7.3p8: "If the specification of an array type includes // any type qualifiers, the element type is so qualified, not the array type." - + // If we get here, we either have type qualifiers on the type, or we have // sugar such as a typedef in the way. If we have type qualifiers on the type - // we must propagate them down into the elemeng type. - unsigned CVRQuals = T.getCVRQualifiers(); - unsigned AddrSpace = 0; - Type *Ty = T.getTypePtr(); - - // Rip through ExtQualType's and typedefs to get to a concrete type. - while (1) { - if (const ExtQualType *EXTQT = dyn_cast(Ty)) { - AddrSpace = EXTQT->getAddressSpace(); - Ty = EXTQT->getBaseType(); - } else { - T = Ty->getDesugaredType(); - if (T.getTypePtr() == Ty && T.getCVRQualifiers() == 0) - break; - CVRQuals |= T.getCVRQualifiers(); - Ty = T.getTypePtr(); - } - } - + // we must propagate them down into the element type. + + QualifierCollector Qs; + const Type *Ty = Qs.strip(T.getDesugaredType()); + // If we have a simple case, just return now. const ArrayType *ATy = dyn_cast(Ty); - if (ATy == 0 || (AddrSpace == 0 && CVRQuals == 0)) + if (ATy == 0 || Qs.empty()) return ATy; - + // Otherwise, we have an array and we have qualifiers on it. Push the // qualifiers into the array element type and return a new array type. // Get the canonical version of the element with the extra qualifiers on it. // This can recursively sink qualifiers through multiple levels of arrays. - QualType NewEltTy = ATy->getElementType(); - if (AddrSpace) - NewEltTy = getAddrSpaceQualType(NewEltTy, AddrSpace); - NewEltTy = NewEltTy.getWithAdditionalQualifiers(CVRQuals); - + QualType NewEltTy = getQualifiedType(ATy->getElementType(), Qs); + if (const ConstantArrayType *CAT = dyn_cast(ATy)) return cast(getConstantArrayType(NewEltTy, CAT->getSize(), CAT->getSizeModifier(), - CAT->getIndexTypeQualifier())); + CAT->getIndexTypeCVRQualifiers())); if (const IncompleteArrayType *IAT = dyn_cast(ATy)) return cast(getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), - IAT->getIndexTypeQualifier())); + IAT->getIndexTypeCVRQualifiers())); - if (const DependentSizedArrayType *DSAT + if (const DependentSizedArrayType *DSAT = dyn_cast(ATy)) return cast( - getDependentSizedArrayType(NewEltTy, - DSAT->getSizeExpr(), + getDependentSizedArrayType(NewEltTy, + DSAT->getSizeExpr() ? + DSAT->getSizeExpr()->Retain() : 0, DSAT->getSizeModifier(), - DSAT->getIndexTypeQualifier())); - + DSAT->getIndexTypeCVRQualifiers(), + DSAT->getBracketsRange())); + const VariableArrayType *VAT = cast(ATy); - return cast(getVariableArrayType(NewEltTy, VAT->getSizeExpr(), + return cast(getVariableArrayType(NewEltTy, + VAT->getSizeExpr() ? + VAT->getSizeExpr()->Retain() : 0, VAT->getSizeModifier(), - VAT->getIndexTypeQualifier())); + VAT->getIndexTypeCVRQualifiers(), + VAT->getBracketsRange())); } @@ -2166,30 +2414,53 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) { // (C99 6.7.3p8). const ArrayType *PrettyArrayType = getAsArrayType(Ty); assert(PrettyArrayType && "Not an array type!"); - + QualType PtrTy = getPointerType(PrettyArrayType->getElementType()); // int x[restrict 4] -> int *restrict - return PtrTy.getQualifiedType(PrettyArrayType->getIndexTypeQualifier()); + return getQualifiedType(PtrTy, PrettyArrayType->getIndexTypeQualifiers()); } -QualType ASTContext::getBaseElementType(const VariableArrayType *VAT) { - QualType ElemTy = VAT->getElementType(); - - if (const VariableArrayType *VAT = getAsVariableArrayType(ElemTy)) - return getBaseElementType(VAT); - +QualType ASTContext::getBaseElementType(QualType QT) { + QualifierCollector Qs; + while (true) { + const Type *UT = Qs.strip(QT); + if (const ArrayType *AT = getAsArrayType(QualType(UT,0))) { + QT = AT->getElementType(); + } else { + return Qs.apply(QT); + } + } +} + +QualType ASTContext::getBaseElementType(const ArrayType *AT) { + QualType ElemTy = AT->getElementType(); + + if (const ArrayType *AT = getAsArrayType(ElemTy)) + return getBaseElementType(AT); + return ElemTy; } +/// getConstantArrayElementCount - Returns number of constant array elements. +uint64_t +ASTContext::getConstantArrayElementCount(const ConstantArrayType *CA) const { + uint64_t ElementCount = 1; + do { + ElementCount *= CA->getSize().getZExtValue(); + CA = dyn_cast(CA->getElementType()); + } while (CA); + return ElementCount; +} + /// getFloatingRank - Return a relative rank for floating point types. /// This routine will assert if passed a built-in type that isn't a float. static FloatingRank getFloatingRank(QualType T) { - if (const ComplexType *CT = T->getAsComplexType()) + if (const ComplexType *CT = T->getAs()) return getFloatingRank(CT->getElementType()); - assert(T->getAsBuiltinType() && "getFloatingRank(): not a floating type"); - switch (T->getAsBuiltinType()->getKind()) { + assert(T->getAs() && "getFloatingRank(): not a floating type"); + switch (T->getAs()->getKind()) { default: assert(0 && "getFloatingRank(): not a floating type"); case BuiltinType::Float: return FloatRank; case BuiltinType::Double: return DoubleRank; @@ -2197,8 +2468,8 @@ static FloatingRank getFloatingRank(QualType T) { } } -/// getFloatingTypeOfSizeWithinDomain - Returns a real floating -/// point or a complex type (based on typeDomain/typeSize). +/// getFloatingTypeOfSizeWithinDomain - Returns a real floating +/// point or a complex type (based on typeDomain/typeSize). /// 'typeDomain' is a real floating point or complex type. /// 'typeSize' is a real floating point or complex type. QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size, @@ -2225,11 +2496,11 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size, /// getFloatingTypeOrder - Compare the rank of the two specified floating /// point types, ignoring the domain of the type (i.e. 'double' == /// '_Complex double'). If LHS > RHS, return 1. If LHS == RHS, return 0. If -/// LHS < RHS, return -1. +/// LHS < RHS, return -1. int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) { FloatingRank LHSR = getFloatingRank(LHS); FloatingRank RHSR = getFloatingRank(RHS); - + if (LHSR == RHSR) return 0; if (LHSR > RHSR) @@ -2245,6 +2516,15 @@ unsigned ASTContext::getIntegerRank(Type *T) { if (EnumType* ET = dyn_cast(T)) T = ET->getDecl()->getIntegerType().getTypePtr(); + if (T->isSpecificBuiltinType(BuiltinType::WChar)) + T = getFromTargetType(Target.getWCharType()).getTypePtr(); + + if (T->isSpecificBuiltinType(BuiltinType::Char16)) + T = getFromTargetType(Target.getChar16Type()).getTypePtr(); + + if (T->isSpecificBuiltinType(BuiltinType::Char32)) + T = getFromTargetType(Target.getChar32Type()).getTypePtr(); + // There are two things which impact the integer rank: the width, and // the ordering of builtins. The builtin ordering is encoded in the // bottom three bits; the width is encoded in the bits above that. @@ -2278,117 +2558,163 @@ unsigned ASTContext::getIntegerRank(Type *T) { } } -/// getIntegerTypeOrder - Returns the highest ranked integer type: +/// \brief Whether this is a promotable bitfield reference according +/// to C99 6.3.1.1p2, bullet 2 (and GCC extensions). +/// +/// \returns the type this bit-field will promote to, or NULL if no +/// promotion occurs. +QualType ASTContext::isPromotableBitField(Expr *E) { + FieldDecl *Field = E->getBitField(); + if (!Field) + return QualType(); + + QualType FT = Field->getType(); + + llvm::APSInt BitWidthAP = Field->getBitWidth()->EvaluateAsInt(*this); + uint64_t BitWidth = BitWidthAP.getZExtValue(); + uint64_t IntSize = getTypeSize(IntTy); + // GCC extension compatibility: if the bit-field size is less than or equal + // to the size of int, it gets promoted no matter what its type is. + // For instance, unsigned long bf : 4 gets promoted to signed int. + if (BitWidth < IntSize) + return IntTy; + + if (BitWidth == IntSize) + return FT->isSignedIntegerType() ? IntTy : UnsignedIntTy; + + // Types bigger than int are not subject to promotions, and therefore act + // like the base type. + // FIXME: This doesn't quite match what gcc does, but what gcc does here + // is ridiculous. + return QualType(); +} + +/// getPromotedIntegerType - Returns the type that Promotable will +/// promote to: C99 6.3.1.1p2, assuming that Promotable is a promotable +/// integer type. +QualType ASTContext::getPromotedIntegerType(QualType Promotable) { + assert(!Promotable.isNull()); + assert(Promotable->isPromotableIntegerType()); + if (Promotable->isSignedIntegerType()) + return IntTy; + uint64_t PromotableSize = getTypeSize(Promotable); + uint64_t IntSize = getTypeSize(IntTy); + assert(Promotable->isUnsignedIntegerType() && PromotableSize <= IntSize); + return (PromotableSize != IntSize) ? IntTy : UnsignedIntTy; +} + +/// getIntegerTypeOrder - Returns the highest ranked integer type: /// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If -/// LHS < RHS, return -1. +/// LHS < RHS, return -1. int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) { Type *LHSC = getCanonicalType(LHS).getTypePtr(); Type *RHSC = getCanonicalType(RHS).getTypePtr(); if (LHSC == RHSC) return 0; - + bool LHSUnsigned = LHSC->isUnsignedIntegerType(); bool RHSUnsigned = RHSC->isUnsignedIntegerType(); - + unsigned LHSRank = getIntegerRank(LHSC); unsigned RHSRank = getIntegerRank(RHSC); - + if (LHSUnsigned == RHSUnsigned) { // Both signed or both unsigned. if (LHSRank == RHSRank) return 0; return LHSRank > RHSRank ? 1 : -1; } - + // Otherwise, the LHS is signed and the RHS is unsigned or visa versa. if (LHSUnsigned) { // If the unsigned [LHS] type is larger, return it. if (LHSRank >= RHSRank) return 1; - + // If the signed type can represent all values of the unsigned type, it // wins. Because we are dealing with 2's complement and types that are - // powers of two larger than each other, this is always safe. + // powers of two larger than each other, this is always safe. return -1; } // If the unsigned [RHS] type is larger, return it. if (RHSRank >= LHSRank) return -1; - + // If the signed type can represent all values of the unsigned type, it // wins. Because we are dealing with 2's complement and types that are - // powers of two larger than each other, this is always safe. + // powers of two larger than each other, this is always safe. return 1; } -// getCFConstantStringType - Return the type used for constant CFStrings. +// getCFConstantStringType - Return the type used for constant CFStrings. QualType ASTContext::getCFConstantStringType() { if (!CFConstantStringTypeDecl) { - CFConstantStringTypeDecl = - RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + CFConstantStringTypeDecl = + RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), &Idents.get("NSConstantString")); QualType FieldTypes[4]; - + // const int *isa; - FieldTypes[0] = getPointerType(IntTy.getQualifiedType(QualType::Const)); + FieldTypes[0] = getPointerType(IntTy.withConst()); // int flags; FieldTypes[1] = IntTy; // const char *str; - FieldTypes[2] = getPointerType(CharTy.getQualifiedType(QualType::Const)); + FieldTypes[2] = getPointerType(CharTy.withConst()); // long length; - FieldTypes[3] = LongTy; - + FieldTypes[3] = LongTy; + // Create fields for (unsigned i = 0; i < 4; ++i) { - FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl, + FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl, SourceLocation(), 0, - FieldTypes[i], /*BitWidth=*/0, + FieldTypes[i], /*DInfo=*/0, + /*BitWidth=*/0, /*Mutable=*/false); CFConstantStringTypeDecl->addDecl(Field); } CFConstantStringTypeDecl->completeDefinition(*this); } - + return getTagDeclType(CFConstantStringTypeDecl); } void ASTContext::setCFConstantStringType(QualType T) { - const RecordType *Rec = T->getAsRecordType(); + const RecordType *Rec = T->getAs(); assert(Rec && "Invalid CFConstantStringType"); CFConstantStringTypeDecl = Rec->getDecl(); } -QualType ASTContext::getObjCFastEnumerationStateType() -{ +QualType ASTContext::getObjCFastEnumerationStateType() { if (!ObjCFastEnumerationStateTypeDecl) { ObjCFastEnumerationStateTypeDecl = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), &Idents.get("__objcFastEnumerationState")); - + QualType FieldTypes[] = { UnsignedLongTy, - getPointerType(ObjCIdType), + getPointerType(ObjCIdTypedefType), getPointerType(UnsignedLongTy), getConstantArrayType(UnsignedLongTy, llvm::APInt(32, 5), ArrayType::Normal, 0) }; - + for (size_t i = 0; i < 4; ++i) { - FieldDecl *Field = FieldDecl::Create(*this, - ObjCFastEnumerationStateTypeDecl, - SourceLocation(), 0, - FieldTypes[i], /*BitWidth=*/0, + FieldDecl *Field = FieldDecl::Create(*this, + ObjCFastEnumerationStateTypeDecl, + SourceLocation(), 0, + FieldTypes[i], /*DInfo=*/0, + /*BitWidth=*/0, /*Mutable=*/false); ObjCFastEnumerationStateTypeDecl->addDecl(Field); } - + ObjCFastEnumerationStateTypeDecl->completeDefinition(*this); } - + return getTagDeclType(ObjCFastEnumerationStateTypeDecl); } void ASTContext::setObjCFastEnumerationStateType(QualType T) { - const RecordType *Rec = T->getAsRecordType(); + const RecordType *Rec = T->getAs(); assert(Rec && "Invalid ObjCFAstEnumerationStateType"); ObjCFastEnumerationStateTypeDecl = Rec->getDecl(); } @@ -2399,7 +2725,7 @@ static bool isTypeTypedefedAsBOOL(QualType T) { if (const TypedefType *TT = dyn_cast(T)) if (IdentifierInfo *II = TT->getDecl()->getIdentifier()) return II->isStr("BOOL"); - + return false; } @@ -2407,7 +2733,7 @@ static bool isTypeTypedefedAsBOOL(QualType T) { /// purpose. int ASTContext::getObjCEncodingTypeSize(QualType type) { uint64_t sz = getTypeSize(type); - + // Make all integer and enum types at least as large as an int if (sz > 0 && type->isIntegralType()) sz = std::max(sz, getTypeSize(IntTy)); @@ -2419,7 +2745,7 @@ int ASTContext::getObjCEncodingTypeSize(QualType type) { /// getObjCEncodingForMethodDecl - Return the encoded type for this method /// declaration. -void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, +void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string& S) { // FIXME: This is not very efficient. // Encode type qualifer, 'in', 'inout', etc. for the return type. @@ -2444,13 +2770,13 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, S += llvm::utostr(ParmOffset); S += "@0:"; S += llvm::utostr(PtrSize); - + // Argument types. ParmOffset = 2 * PtrSize; for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), E = Decl->param_end(); PI != E; ++PI) { ParmVarDecl *PVDecl = *PI; - QualType PType = PVDecl->getOriginalType(); + QualType PType = PVDecl->getOriginalType(); if (const ArrayType *AT = dyn_cast(PType->getCanonicalTypeInternal())) { // Use array's original type only if it has known number of @@ -2472,11 +2798,11 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, /// property declaration. If non-NULL, Container must be either an /// ObjCCategoryImplDecl or ObjCImplementationDecl; it should only be /// NULL when getting encodings for protocol properties. -/// Property attributes are stored as a comma-delimited C string. The simple -/// attributes readonly and bycopy are encoded as single characters. The -/// parametrized attributes, getter=name, setter=name, and ivar=name, are -/// encoded as single characters, followed by an identifier. Property types -/// are also encoded as a parametrized attribute. The characters used to encode +/// Property attributes are stored as a comma-delimited C string. The simple +/// attributes readonly and bycopy are encoded as single characters. The +/// parametrized attributes, getter=name, setter=name, and ivar=name, are +/// encoded as single characters, followed by an identifier. Property types +/// are also encoded as a parametrized attribute. The characters used to encode /// these attributes are defined by the following enumeration: /// @code /// enum PropertyAttributes { @@ -2493,7 +2819,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, /// kPropertyNonAtomic = 'N' // property non-atomic /// }; /// @endcode -void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, +void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, const Decl *Container, std::string& S) { // Collect information from the property implementation decl(s). @@ -2502,7 +2828,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, // FIXME: Duplicated code due to poor abstraction. if (Container) { - if (const ObjCCategoryImplDecl *CID = + if (const ObjCCategoryImplDecl *CID = dyn_cast(Container)) { for (ObjCCategoryImplDecl::propimpl_iterator i = CID->propimpl_begin(), e = CID->propimpl_end(); @@ -2529,7 +2855,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, SynthesizePID = PID; } } - } + } } } @@ -2539,7 +2865,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, // Encode result type. // GCC has some special rules regarding encoding of properties which // closely resembles encoding of ivars. - getObjCEncodingForTypeImpl(PD->getType(), S, true, true, 0, + getObjCEncodingForTypeImpl(PD->getType(), S, true, true, 0, true /* outermost type */, true /* encoding for property */); @@ -2549,7 +2875,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, switch (PD->getSetterKind()) { case ObjCPropertyDecl::Assign: break; case ObjCPropertyDecl::Copy: S += ",C"; break; - case ObjCPropertyDecl::Retain: S += ",&"; break; + case ObjCPropertyDecl::Retain: S += ",&"; break; } } @@ -2560,7 +2886,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) S += ",N"; - + if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) { S += ",G"; S += PD->getGetterName().getAsString(); @@ -2581,17 +2907,17 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, } /// getLegacyIntegralTypeEncoding - -/// Another legacy compatibility encoding: 32-bit longs are encoded as -/// 'l' or 'L' , but not always. For typedefs, we need to use +/// Another legacy compatibility encoding: 32-bit longs are encoded as +/// 'l' or 'L' , but not always. For typedefs, we need to use /// 'i' or 'I' instead if encoding a struct field, or a pointer! /// void ASTContext::getLegacyIntegralTypeEncoding (QualType &PointeeTy) const { - if (dyn_cast(PointeeTy.getTypePtr())) { - if (const BuiltinType *BT = PointeeTy->getAsBuiltinType()) { + if (isa(PointeeTy.getTypePtr())) { + if (const BuiltinType *BT = PointeeTy->getAs()) { if (BT->getKind() == BuiltinType::ULong && ((const_cast(this))->getIntWidth(PointeeTy) == 32)) PointeeTy = UnsignedIntTy; - else + else if (BT->getKind() == BuiltinType::Long && ((const_cast(this))->getIntWidth(PointeeTy) == 32)) PointeeTy = IntTy; @@ -2605,11 +2931,11 @@ void ASTContext::getObjCEncodingForType(QualType T, std::string& S, // directly pointed to, and expanding embedded structures. Note that // these rules are sufficient to prevent recursive encoding of the // same type. - getObjCEncodingForTypeImpl(T, S, true, true, Field, + getObjCEncodingForTypeImpl(T, S, true, true, Field, true /* outermost type */); } -static void EncodeBitField(const ASTContext *Context, std::string& S, +static void EncodeBitField(const ASTContext *Context, std::string& S, const FieldDecl *FD) { const Expr *E = FD->getBitWidth(); assert(E && "bitfield width not there - getObjCEncodingForTypeImpl"); @@ -2625,83 +2951,66 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, const FieldDecl *FD, bool OutermostType, bool EncodingProperty) { - if (const BuiltinType *BT = T->getAsBuiltinType()) { - if (FD && FD->isBitField()) { - EncodeBitField(this, S, FD); - } - else { - char encoding; - switch (BT->getKind()) { - default: assert(0 && "Unhandled builtin type kind"); - case BuiltinType::Void: encoding = 'v'; break; - case BuiltinType::Bool: encoding = 'B'; break; - case BuiltinType::Char_U: - case BuiltinType::UChar: encoding = 'C'; break; - case BuiltinType::UShort: encoding = 'S'; break; - case BuiltinType::UInt: encoding = 'I'; break; - case BuiltinType::ULong: - encoding = - (const_cast(this))->getIntWidth(T) == 32 ? 'L' : 'Q'; - break; - case BuiltinType::UInt128: encoding = 'T'; break; - case BuiltinType::ULongLong: encoding = 'Q'; break; - case BuiltinType::Char_S: - case BuiltinType::SChar: encoding = 'c'; break; - case BuiltinType::Short: encoding = 's'; break; - case BuiltinType::Int: encoding = 'i'; break; - case BuiltinType::Long: - encoding = - (const_cast(this))->getIntWidth(T) == 32 ? 'l' : 'q'; + if (const BuiltinType *BT = T->getAs()) { + if (FD && FD->isBitField()) + return EncodeBitField(this, S, FD); + char encoding; + switch (BT->getKind()) { + default: assert(0 && "Unhandled builtin type kind"); + case BuiltinType::Void: encoding = 'v'; break; + case BuiltinType::Bool: encoding = 'B'; break; + case BuiltinType::Char_U: + case BuiltinType::UChar: encoding = 'C'; break; + case BuiltinType::UShort: encoding = 'S'; break; + case BuiltinType::UInt: encoding = 'I'; break; + case BuiltinType::ULong: + encoding = + (const_cast(this))->getIntWidth(T) == 32 ? 'L' : 'Q'; break; - case BuiltinType::LongLong: encoding = 'q'; break; - case BuiltinType::Int128: encoding = 't'; break; - case BuiltinType::Float: encoding = 'f'; break; - case BuiltinType::Double: encoding = 'd'; break; - case BuiltinType::LongDouble: encoding = 'd'; break; - } - - S += encoding; + case BuiltinType::UInt128: encoding = 'T'; break; + case BuiltinType::ULongLong: encoding = 'Q'; break; + case BuiltinType::Char_S: + case BuiltinType::SChar: encoding = 'c'; break; + case BuiltinType::Short: encoding = 's'; break; + case BuiltinType::Int: encoding = 'i'; break; + case BuiltinType::Long: + encoding = + (const_cast(this))->getIntWidth(T) == 32 ? 'l' : 'q'; + break; + case BuiltinType::LongLong: encoding = 'q'; break; + case BuiltinType::Int128: encoding = 't'; break; + case BuiltinType::Float: encoding = 'f'; break; + case BuiltinType::Double: encoding = 'd'; break; + case BuiltinType::LongDouble: encoding = 'd'; break; } - } else if (const ComplexType *CT = T->getAsComplexType()) { + + S += encoding; + return; + } + + if (const ComplexType *CT = T->getAs()) { S += 'j'; - getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false, + getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false, false); - } else if (T->isObjCQualifiedIdType()) { - getObjCEncodingForTypeImpl(getObjCIdType(), S, - ExpandPointedToStructures, - ExpandStructures, FD); - if (FD || EncodingProperty) { - // Note that we do extended encoding of protocol qualifer list - // Only when doing ivar or property encoding. - const ObjCObjectPointerType *QIDT = T->getAsObjCQualifiedIdType(); - S += '"'; - for (ObjCObjectPointerType::qual_iterator I = QIDT->qual_begin(), - E = QIDT->qual_end(); I != E; ++I) { - S += '<'; - S += (*I)->getNameAsString(); - S += '>'; - } - S += '"'; - } return; } - else if (const PointerType *PT = T->getAsPointerType()) { + + if (const PointerType *PT = T->getAs()) { QualType PointeeTy = PT->getPointeeType(); bool isReadOnly = false; // For historical/compatibility reasons, the read-only qualifier of the // pointee gets emitted _before_ the '^'. The read-only qualifier of // the pointer itself gets ignored, _unless_ we are looking at a typedef! - // Also, do not emit the 'r' for anything but the outermost type! - if (dyn_cast(T.getTypePtr())) { + // Also, do not emit the 'r' for anything but the outermost type! + if (isa(T.getTypePtr())) { if (OutermostType && T.isConstQualified()) { isReadOnly = true; S += 'r'; } - } - else if (OutermostType) { + } else if (OutermostType) { QualType P = PointeeTy; - while (P->getAsPointerType()) - P = P->getAsPointerType()->getPointeeType(); + while (P->getAs()) + P = P->getAs()->getPointeeType(); if (P.isConstQualified()) { isReadOnly = true; S += 'r'; @@ -2718,46 +3027,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S.replace(S.end()-2, S.end(), replace); } } - if (isObjCIdStructType(PointeeTy)) { - S += '@'; - return; - } - else if (PointeeTy->isObjCInterfaceType()) { - if (!EncodingProperty && - isa(PointeeTy.getTypePtr())) { - // Another historical/compatibility reason. - // We encode the underlying type which comes out as - // {...}; - S += '^'; - getObjCEncodingForTypeImpl(PointeeTy, S, - false, ExpandPointedToStructures, - NULL); - return; - } - S += '@'; - if (FD || EncodingProperty) { - const ObjCInterfaceType *OIT = - PointeeTy.getUnqualifiedType()->getAsObjCInterfaceType(); - ObjCInterfaceDecl *OI = OIT->getDecl(); - S += '"'; - S += OI->getNameAsCString(); - for (ObjCInterfaceType::qual_iterator I = OIT->qual_begin(), - E = OIT->qual_end(); I != E; ++I) { - S += '<'; - S += (*I)->getNameAsString(); - S += '>'; - } - S += '"'; - } - return; - } else if (isObjCClassStructType(PointeeTy)) { - S += '#'; - return; - } else if (isObjCSelType(PointeeTy)) { + if (isObjCSelType(PointeeTy)) { S += ':'; return; } - + if (PointeeTy->isCharType()) { // char pointer types should be encoded as '*' unless it is a // type that has been typedef'd to 'BOOL'. @@ -2765,26 +3039,39 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S += '*'; return; } + } else if (const RecordType *RTy = PointeeTy->getAs()) { + // GCC binary compat: Need to convert "struct objc_class *" to "#". + if (RTy->getDecl()->getIdentifier() == &Idents.get("objc_class")) { + S += '#'; + return; + } + // GCC binary compat: Need to convert "struct objc_object *" to "@". + if (RTy->getDecl()->getIdentifier() == &Idents.get("objc_object")) { + S += '@'; + return; + } + // fall through... } - S += '^'; getLegacyIntegralTypeEncoding(PointeeTy); - getObjCEncodingForTypeImpl(PointeeTy, S, - false, ExpandPointedToStructures, + getObjCEncodingForTypeImpl(PointeeTy, S, false, ExpandPointedToStructures, NULL); - } else if (const ArrayType *AT = - // Ignore type qualifiers etc. - dyn_cast(T->getCanonicalTypeInternal())) { + return; + } + + if (const ArrayType *AT = + // Ignore type qualifiers etc. + dyn_cast(T->getCanonicalTypeInternal())) { if (isa(AT)) { // Incomplete arrays are encoded as a pointer to the array element. S += '^'; - getObjCEncodingForTypeImpl(AT->getElementType(), S, + getObjCEncodingForTypeImpl(AT->getElementType(), S, false, ExpandStructures, FD); } else { S += '['; - + if (const ConstantArrayType *CAT = dyn_cast(AT)) S += llvm::utostr(CAT->getSize().getZExtValue()); else { @@ -2792,14 +3079,20 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, assert(isa(AT) && "Unknown array type!"); S += '0'; } - - getObjCEncodingForTypeImpl(AT->getElementType(), S, + + getObjCEncodingForTypeImpl(AT->getElementType(), S, false, ExpandStructures, FD); S += ']'; } - } else if (T->getAsFunctionType()) { + return; + } + + if (T->getAs()) { S += '?'; - } else if (const RecordType *RTy = T->getAsRecordType()) { + return; + } + + if (const RecordType *RTy = T->getAs()) { RecordDecl *RDecl = RTy->getDecl(); S += RDecl->isUnion() ? '(' : '{'; // Anonymous structures print as '?' @@ -2818,30 +3111,39 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S += Field->getNameAsString(); S += '"'; } - + // Special case bit-fields. if (Field->isBitField()) { - getObjCEncodingForTypeImpl(Field->getType(), S, false, true, + getObjCEncodingForTypeImpl(Field->getType(), S, false, true, (*Field)); } else { QualType qt = Field->getType(); getLegacyIntegralTypeEncoding(qt); - getObjCEncodingForTypeImpl(qt, S, false, true, + getObjCEncodingForTypeImpl(qt, S, false, true, FD); } } } S += RDecl->isUnion() ? ')' : '}'; - } else if (T->isEnumeralType()) { + return; + } + + if (T->isEnumeralType()) { if (FD && FD->isBitField()) EncodeBitField(this, S, FD); else S += 'i'; - } else if (T->isBlockPointerType()) { + return; + } + + if (T->isBlockPointerType()) { S += "@?"; // Unlike a pointer-to-function, which is "^?". - } else if (T->isObjCInterfaceType()) { + return; + } + + if (const ObjCInterfaceType *OIT = T->getAs()) { // @encode(class_name) - ObjCInterfaceDecl *OI = T->getAsObjCInterfaceType()->getDecl(); + ObjCInterfaceDecl *OI = OIT->getDecl(); S += '{'; const IdentifierInfo *II = OI->getIdentifier(); S += II->getName(); @@ -2850,19 +3152,78 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, CollectObjCIvars(OI, RecFields); for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { if (RecFields[i]->isBitField()) - getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true, + getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true, RecFields[i]); else - getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true, + getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true, FD); } S += '}'; + return; } - else - assert(0 && "@encode for type not implemented!"); + + if (const ObjCObjectPointerType *OPT = T->getAs()) { + if (OPT->isObjCIdType()) { + S += '@'; + return; + } + + if (OPT->isObjCClassType()) { + S += '#'; + return; + } + + if (OPT->isObjCQualifiedIdType()) { + getObjCEncodingForTypeImpl(getObjCIdType(), S, + ExpandPointedToStructures, + ExpandStructures, FD); + if (FD || EncodingProperty) { + // Note that we do extended encoding of protocol qualifer list + // Only when doing ivar or property encoding. + S += '"'; + for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), + E = OPT->qual_end(); I != E; ++I) { + S += '<'; + S += (*I)->getNameAsString(); + S += '>'; + } + S += '"'; + } + return; + } + + QualType PointeeTy = OPT->getPointeeType(); + if (!EncodingProperty && + isa(PointeeTy.getTypePtr())) { + // Another historical/compatibility reason. + // We encode the underlying type which comes out as + // {...}; + S += '^'; + getObjCEncodingForTypeImpl(PointeeTy, S, + false, ExpandPointedToStructures, + NULL); + return; + } + + S += '@'; + if (FD || EncodingProperty) { + S += '"'; + S += OPT->getInterfaceDecl()->getNameAsCString(); + for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), + E = OPT->qual_end(); I != E; ++I) { + S += '<'; + S += (*I)->getNameAsString(); + S += '>'; + } + S += '"'; + } + return; + } + + assert(0 && "@encode for type not implemented!"); } -void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, +void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, std::string& S) const { if (QT & Decl::OBJC_TQ_In) S += 'n'; @@ -2878,46 +3239,26 @@ void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, S += 'V'; } -void ASTContext::setBuiltinVaListType(QualType T) -{ +void ASTContext::setBuiltinVaListType(QualType T) { assert(BuiltinVaListType.isNull() && "__builtin_va_list type already set!"); - + BuiltinVaListType = T; } -void ASTContext::setObjCIdType(QualType T) -{ - ObjCIdType = T; - - const TypedefType *TT = T->getAsTypedefType(); - if (!TT) - return; - - TypedefDecl *TD = TT->getDecl(); - - // typedef struct objc_object *id; - const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); - // User error - caller will issue diagnostics. - if (!ptr) - return; - const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); - // User error - caller will issue diagnostics. - if (!rec) - return; - IdStructType = rec; +void ASTContext::setObjCIdType(QualType T) { + ObjCIdTypedefType = T; } -void ASTContext::setObjCSelType(QualType T) -{ +void ASTContext::setObjCSelType(QualType T) { ObjCSelType = T; - const TypedefType *TT = T->getAsTypedefType(); + const TypedefType *TT = T->getAs(); if (!TT) return; TypedefDecl *TD = TT->getDecl(); // typedef struct objc_selector *SEL; - const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); + const PointerType *ptr = TD->getUnderlyingType()->getAs(); if (!ptr) return; const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); @@ -2926,38 +3267,24 @@ void ASTContext::setObjCSelType(QualType T) SelStructType = rec; } -void ASTContext::setObjCProtoType(QualType QT) -{ +void ASTContext::setObjCProtoType(QualType QT) { ObjCProtoType = QT; } -void ASTContext::setObjCClassType(QualType T) -{ - ObjCClassType = T; - - const TypedefType *TT = T->getAsTypedefType(); - if (!TT) - return; - TypedefDecl *TD = TT->getDecl(); - - // typedef struct objc_class *Class; - const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); - assert(ptr && "'Class' incorrectly typed"); - const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); - assert(rec && "'Class' incorrectly typed"); - ClassStructType = rec; +void ASTContext::setObjCClassType(QualType T) { + ObjCClassTypedefType = T; } void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { - assert(ObjCConstantStringType.isNull() && + assert(ObjCConstantStringType.isNull() && "'NSConstantString' type already set!"); - + ObjCConstantStringType = getObjCInterfaceType(Decl); } /// \brief Retrieve the template name that represents a qualified /// template name such as \c std::vector. -TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, +TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, TemplateDecl *Template) { llvm::FoldingSetNodeID ID; @@ -2974,11 +3301,31 @@ TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, return TemplateName(QTN); } +/// \brief Retrieve the template name that represents a qualified +/// template name such as \c std::vector. +TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, + bool TemplateKeyword, + OverloadedFunctionDecl *Template) { + llvm::FoldingSetNodeID ID; + QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template); + + void *InsertPos = 0; + QualifiedTemplateName *QTN = + QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + if (!QTN) { + QTN = new (*this,4) QualifiedTemplateName(NNS, TemplateKeyword, Template); + QualifiedTemplateNames.InsertNode(QTN, InsertPos); + } + + return TemplateName(QTN); +} + /// \brief Retrieve the template name that represents a dependent /// template name such as \c MetaFun::template apply. -TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, +TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, const IdentifierInfo *Name) { - assert(NNS->isDependent() && "Nested name specifier must be dependent"); + assert((!NNS || NNS->isDependent()) && + "Nested name specifier must be dependent"); llvm::FoldingSetNodeID ID; DependentTemplateName::Profile(ID, NNS, Name); @@ -3007,7 +3354,7 @@ TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, /// is actually a value of type @c TargetInfo::IntType. QualType ASTContext::getFromTargetType(unsigned Type) const { switch (Type) { - case TargetInfo::NoInt: return QualType(); + case TargetInfo::NoInt: return QualType(); case TargetInfo::SignedShort: return ShortTy; case TargetInfo::UnsignedShort: return UnsignedShortTy; case TargetInfo::SignedInt: return IntTy; @@ -3029,6 +3376,7 @@ QualType ASTContext::getFromTargetType(unsigned Type) const { /// isObjCNSObjectType - Return true if this is an NSObject object using /// NSObject attribute on a c-style pointer type. /// FIXME - Make it work directly on types. +/// FIXME: Move to Type. /// bool ASTContext::isObjCNSObjectType(QualType Ty) const { if (TypedefType *TDT = dyn_cast(Ty)) { @@ -3036,68 +3384,30 @@ bool ASTContext::isObjCNSObjectType(QualType Ty) const { if (TD->getAttr()) return true; } - return false; -} - -/// isObjCObjectPointerType - Returns true if type is an Objective-C pointer -/// to an object type. This includes "id" and "Class" (two 'special' pointers -/// to struct), Interface* (pointer to ObjCInterfaceType) and id

(qualified -/// ID type). -bool ASTContext::isObjCObjectPointerType(QualType Ty) const { - if (Ty->isObjCQualifiedIdType()) - return true; - - // Blocks are objects. - if (Ty->isBlockPointerType()) - return true; - - // All other object types are pointers. - const PointerType *PT = Ty->getAsPointerType(); - if (PT == 0) - return false; - - // If this a pointer to an interface (e.g. NSString*), it is ok. - if (PT->getPointeeType()->isObjCInterfaceType() || - // If is has NSObject attribute, OK as well. - isObjCNSObjectType(Ty)) - return true; - - // Check to see if this is 'id' or 'Class', both of which are typedefs for - // pointer types. This looks for the typedef specifically, not for the - // underlying type. Iteratively strip off typedefs so that we can handle - // typedefs of typedefs. - while (TypedefType *TDT = dyn_cast(Ty)) { - if (Ty.getUnqualifiedType() == getObjCIdType() || - Ty.getUnqualifiedType() == getObjCClassType()) - return true; - - Ty = TDT->getDecl()->getUnderlyingType(); - } - return false; } /// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's /// garbage collection attribute. /// -QualType::GCAttrTypes ASTContext::getObjCGCAttrKind(const QualType &Ty) const { - QualType::GCAttrTypes GCAttrs = QualType::GCNone; +Qualifiers::GC ASTContext::getObjCGCAttrKind(const QualType &Ty) const { + Qualifiers::GC GCAttrs = Qualifiers::GCNone; if (getLangOptions().ObjC1 && getLangOptions().getGCMode() != LangOptions::NonGC) { GCAttrs = Ty.getObjCGCAttr(); // Default behavious under objective-c's gc is for objective-c pointers - // (or pointers to them) be treated as though they were declared + // (or pointers to them) be treated as though they were declared // as __strong. - if (GCAttrs == QualType::GCNone) { - if (isObjCObjectPointerType(Ty)) - GCAttrs = QualType::Strong; + if (GCAttrs == Qualifiers::GCNone) { + if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType()) + GCAttrs = Qualifiers::Strong; else if (Ty->isPointerType()) - return getObjCGCAttrKind(Ty->getAsPointerType()->getPointeeType()); + return getObjCGCAttrKind(Ty->getAs()->getPointeeType()); } // Non-pointers have none gc'able attribute regardless of the attribute // set on them. - else if (!Ty->isPointerType() && !isObjCObjectPointerType(Ty)) - return QualType::GCNone; + else if (!Ty->isAnyPointerType() && !Ty->isBlockPointerType()) + return Qualifiers::GCNone; } return GCAttrs; } @@ -3106,7 +3416,7 @@ QualType::GCAttrTypes ASTContext::getObjCGCAttrKind(const QualType &Ty) const { // Type Compatibility Testing //===----------------------------------------------------------------------===// -/// areCompatVectorTypes - Return true if the two specified vector types are +/// areCompatVectorTypes - Return true if the two specified vector types are /// compatible. static bool areCompatVectorTypes(const VectorType *LHS, const VectorType *RHS) { @@ -3115,46 +3425,207 @@ static bool areCompatVectorTypes(const VectorType *LHS, LHS->getNumElements() == RHS->getNumElements(); } +//===----------------------------------------------------------------------===// +// ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's. +//===----------------------------------------------------------------------===// + +/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the +/// inheritance hierarchy of 'rProto'. +bool ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, + ObjCProtocolDecl *rProto) { + if (lProto == rProto) + return true; + for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(), + E = rProto->protocol_end(); PI != E; ++PI) + if (ProtocolCompatibleWithProtocol(lProto, *PI)) + return true; + return false; +} + +/// QualifiedIdConformsQualifiedId - compare id with id +/// return true if lhs's protocols conform to rhs's protocol; false +/// otherwise. +bool ASTContext::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) { + if (lhs->isObjCQualifiedIdType() && rhs->isObjCQualifiedIdType()) + return ObjCQualifiedIdTypesAreCompatible(lhs, rhs, false); + return false; +} + +/// ObjCQualifiedIdTypesAreCompatible - We know that one of lhs/rhs is an +/// ObjCQualifiedIDType. +bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, + bool compare) { + // Allow id and an 'id' or void* type in all cases. + if (lhs->isVoidPointerType() || + lhs->isObjCIdType() || lhs->isObjCClassType()) + return true; + else if (rhs->isVoidPointerType() || + rhs->isObjCIdType() || rhs->isObjCClassType()) + return true; + + if (const ObjCObjectPointerType *lhsQID = lhs->getAsObjCQualifiedIdType()) { + const ObjCObjectPointerType *rhsOPT = rhs->getAs(); + + if (!rhsOPT) return false; + + if (rhsOPT->qual_empty()) { + // If the RHS is a unqualified interface pointer "NSString*", + // make sure we check the class hierarchy. + if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) { + for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(), + E = lhsQID->qual_end(); I != E; ++I) { + // when comparing an id

on lhs with a static type on rhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + if (!rhsID->ClassImplementsProtocol(*I, true)) + return false; + } + } + // If there are no qualifiers and no interface, we have an 'id'. + return true; + } + // Both the right and left sides have qualifiers. + for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(), + E = lhsQID->qual_end(); I != E; ++I) { + ObjCProtocolDecl *lhsProto = *I; + bool match = false; + + // when comparing an id

on lhs with a static type on rhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + for (ObjCObjectPointerType::qual_iterator J = rhsOPT->qual_begin(), + E = rhsOPT->qual_end(); J != E; ++J) { + ObjCProtocolDecl *rhsProto = *J; + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || + (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) { + match = true; + break; + } + } + // If the RHS is a qualified interface pointer "NSString

*", + // make sure we check the class hierarchy. + if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) { + for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(), + E = lhsQID->qual_end(); I != E; ++I) { + // when comparing an id

on lhs with a static type on rhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + if (rhsID->ClassImplementsProtocol(*I, true)) { + match = true; + break; + } + } + } + if (!match) + return false; + } + + return true; + } + + const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType(); + assert(rhsQID && "One of the LHS/RHS should be id"); + + if (const ObjCObjectPointerType *lhsOPT = + lhs->getAsObjCInterfacePointerType()) { + if (lhsOPT->qual_empty()) { + bool match = false; + if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) { + for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(), + E = rhsQID->qual_end(); I != E; ++I) { + // when comparing an id

on lhs with a static type on rhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + if (lhsID->ClassImplementsProtocol(*I, true)) { + match = true; + break; + } + } + if (!match) + return false; + } + return true; + } + // Both the right and left sides have qualifiers. + for (ObjCObjectPointerType::qual_iterator I = lhsOPT->qual_begin(), + E = lhsOPT->qual_end(); I != E; ++I) { + ObjCProtocolDecl *lhsProto = *I; + bool match = false; + + // when comparing an id

on lhs with a static type on rhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + for (ObjCObjectPointerType::qual_iterator J = rhsQID->qual_begin(), + E = rhsQID->qual_end(); J != E; ++J) { + ObjCProtocolDecl *rhsProto = *J; + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || + (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) { + match = true; + break; + } + } + if (!match) + return false; + } + return true; + } + return false; +} + /// canAssignObjCInterfaces - Return true if the two interface types are /// compatible for assignment from RHS to LHS. This handles validation of any /// protocol qualifiers on the LHS or RHS. /// +bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT) { + // If either type represents the built-in 'id' or 'Class' types, return true. + if (LHSOPT->isObjCBuiltinType() || RHSOPT->isObjCBuiltinType()) + return true; + + if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType()) + return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), + QualType(RHSOPT,0), + false); + + const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType(); + const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType(); + if (LHS && RHS) // We have 2 user-defined types. + return canAssignObjCInterfaces(LHS, RHS); + + return false; +} + bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS, const ObjCInterfaceType *RHS) { // Verify that the base decls are compatible: the RHS must be a subclass of // the LHS. if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl())) return false; - + // RHS must have a superset of the protocols in the LHS. If the LHS is not // protocol qualified at all, then we are good. - if (!isa(LHS)) + if (LHS->getNumProtocols() == 0) return true; - + // Okay, we know the LHS has protocol qualifiers. If the RHS doesn't, then it // isn't a superset. - if (!isa(RHS)) + if (RHS->getNumProtocols() == 0) return true; // FIXME: should return false! - - // Finally, we must have two protocol-qualified interfaces. - const ObjCQualifiedInterfaceType *LHSP =cast(LHS); - const ObjCQualifiedInterfaceType *RHSP =cast(RHS); - - // All LHS protocols must have a presence on the RHS. - assert(LHSP->qual_begin() != LHSP->qual_end() && "Empty LHS protocol list?"); - - for (ObjCQualifiedInterfaceType::qual_iterator LHSPI = LHSP->qual_begin(), - LHSPE = LHSP->qual_end(); + + for (ObjCInterfaceType::qual_iterator LHSPI = LHS->qual_begin(), + LHSPE = LHS->qual_end(); LHSPI != LHSPE; LHSPI++) { bool RHSImplementsProtocol = false; // If the RHS doesn't implement the protocol on the left, the types // are incompatible. - for (ObjCQualifiedInterfaceType::qual_iterator RHSPI = RHSP->qual_begin(), - RHSPE = RHSP->qual_end(); - !RHSImplementsProtocol && (RHSPI != RHSPE); RHSPI++) { - if ((*RHSPI)->lookupProtocolNamed((*LHSPI)->getIdentifier())) + for (ObjCInterfaceType::qual_iterator RHSPI = RHS->qual_begin(), + RHSPE = RHS->qual_end(); + RHSPI != RHSPE; RHSPI++) { + if ((*RHSPI)->lookupProtocolNamed((*LHSPI)->getIdentifier())) { RHSImplementsProtocol = true; + break; + } } // FIXME: For better diagnostics, consider passing back the protocol name. if (!RHSImplementsProtocol) @@ -3166,38 +3637,27 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS, bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) { // get the "pointed to" types - const PointerType *LHSPT = LHS->getAsPointerType(); - const PointerType *RHSPT = RHS->getAsPointerType(); - - if (!LHSPT || !RHSPT) - return false; - - QualType lhptee = LHSPT->getPointeeType(); - QualType rhptee = RHSPT->getPointeeType(); - const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType(); - const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType(); - // ID acts sort of like void* for ObjC interfaces - if (LHSIface && isObjCIdStructType(rhptee)) - return true; - if (RHSIface && isObjCIdStructType(lhptee)) - return true; - if (!LHSIface || !RHSIface) + const ObjCObjectPointerType *LHSOPT = LHS->getAs(); + const ObjCObjectPointerType *RHSOPT = RHS->getAs(); + + if (!LHSOPT || !RHSOPT) return false; - return canAssignObjCInterfaces(LHSIface, RHSIface) || - canAssignObjCInterfaces(RHSIface, LHSIface); + + return canAssignObjCInterfaces(LHSOPT, RHSOPT) || + canAssignObjCInterfaces(RHSOPT, LHSOPT); } -/// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible, +/// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible, /// both shall have the identically qualified version of a compatible type. -/// C99 6.2.7p1: Two types have compatible types if their types are the +/// 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) { return !mergeTypes(LHS, RHS).isNull(); } QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { - const FunctionType *lbase = lhs->getAsFunctionType(); - const FunctionType *rbase = rhs->getAsFunctionType(); + const FunctionType *lbase = lhs->getAs(); + const FunctionType *rbase = rhs->getAs(); const FunctionProtoType *lproto = dyn_cast(lbase); const FunctionProtoType *rproto = dyn_cast(rbase); bool allLTypes = true; @@ -3210,6 +3670,12 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { allLTypes = false; if (getCanonicalType(retType) != getCanonicalType(rbase->getResultType())) allRTypes = false; + // FIXME: double check this + bool NoReturn = lbase->getNoReturnAttr() || rbase->getNoReturnAttr(); + if (NoReturn != lbase->getNoReturnAttr()) + allLTypes = false; + if (NoReturn != rbase->getNoReturnAttr()) + allRTypes = false; if (lproto && rproto) { // two C99 style function prototypes assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() && @@ -3244,7 +3710,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { if (allLTypes) return lhs; if (allRTypes) return rhs; return getFunctionType(retType, types.begin(), types.size(), - lproto->isVariadic(), lproto->getTypeQuals()); + lproto->isVariadic(), lproto->getTypeQuals(), + NoReturn); } if (lproto) allRTypes = false; @@ -3270,13 +3737,13 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { if (allLTypes) return lhs; if (allRTypes) return rhs; return getFunctionType(retType, proto->arg_type_begin(), - proto->getNumArgs(), lproto->isVariadic(), - lproto->getTypeQuals()); + proto->getNumArgs(), proto->isVariadic(), + proto->getTypeQuals(), NoReturn); } if (allLTypes) return lhs; if (allRTypes) return rhs; - return getFunctionNoProtoType(retType); + return getFunctionNoProtoType(retType, NoReturn); } QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { @@ -3289,9 +3756,9 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { // 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->getAsReferenceType()) + if (const ReferenceType *RT = LHS->getAs()) LHS = RT->getPointeeType(); - if (const ReferenceType *RT = RHS->getAsReferenceType()) + if (const ReferenceType *RT = RHS->getAs()) RHS = RT->getPointeeType(); QualType LHSCan = getCanonicalType(LHS), @@ -3301,11 +3768,38 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { if (LHSCan == RHSCan) return LHS; - // If the qualifiers are different, the types aren't compatible - // Note that we handle extended qualifiers later, in the - // case for ExtQualType. - if (LHSCan.getCVRQualifiers() != RHSCan.getCVRQualifiers()) + // If the qualifiers are different, the types aren't compatible... mostly. + Qualifiers LQuals = LHSCan.getQualifiers(); + Qualifiers RQuals = RHSCan.getQualifiers(); + if (LQuals != RQuals) { + // If any of these qualifiers are different, we have a type + // mismatch. + if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() || + LQuals.getAddressSpace() != RQuals.getAddressSpace()) + return QualType(); + + // Exactly one GC qualifier difference is allowed: __strong is + // okay if the other type has no GC qualifier but is an Objective + // C object pointer (i.e. implicitly strong by default). We fix + // this by pretending that the unqualified type was actually + // qualified __strong. + Qualifiers::GC GC_L = LQuals.getObjCGCAttr(); + Qualifiers::GC GC_R = RQuals.getObjCGCAttr(); + assert((GC_L != GC_R) && "unequal qualifier sets had only equal elements"); + + if (GC_L == Qualifiers::Weak || GC_R == Qualifiers::Weak) + return QualType(); + + if (GC_L == Qualifiers::Strong && RHSCan->isObjCObjectPointerType()) { + return mergeTypes(LHS, getObjCGCQualType(RHS, Qualifiers::Strong)); + } + if (GC_R == Qualifiers::Strong && LHSCan->isObjCObjectPointerType()) { + return mergeTypes(getObjCGCQualType(LHS, Qualifiers::Strong), RHS); + } return QualType(); + } + + // Okay, qualifiers are equal. Type::TypeClass LHSClass = LHSCan->getTypeClass(); Type::TypeClass RHSClass = RHSCan->getTypeClass(); @@ -3315,120 +3809,25 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { if (LHSClass == Type::FunctionProto) LHSClass = Type::FunctionNoProto; if (RHSClass == Type::FunctionProto) RHSClass = Type::FunctionNoProto; - // Strip off objc_gc attributes off the top level so they can be merged. - // This is a complete mess, but the attribute itself doesn't make much sense. - if (RHSClass == Type::ExtQual) { - QualType::GCAttrTypes GCAttr = RHSCan.getObjCGCAttr(); - if (GCAttr != QualType::GCNone) { - QualType::GCAttrTypes GCLHSAttr = LHSCan.getObjCGCAttr(); - // __weak attribute must appear on both declarations. - // __strong attribue is redundant if other decl is an objective-c - // object pointer (or decorated with __strong attribute); otherwise - // issue error. - if ((GCAttr == QualType::Weak && GCLHSAttr != GCAttr) || - (GCAttr == QualType::Strong && GCLHSAttr != GCAttr && - LHSCan->isPointerType() && !isObjCObjectPointerType(LHSCan) && - !isObjCIdStructType(LHSCan->getAsPointerType()->getPointeeType()))) - return QualType(); - - RHS = QualType(cast(RHS.getDesugaredType())->getBaseType(), - RHS.getCVRQualifiers()); - QualType Result = mergeTypes(LHS, RHS); - if (!Result.isNull()) { - if (Result.getObjCGCAttr() == QualType::GCNone) - Result = getObjCGCQualType(Result, GCAttr); - else if (Result.getObjCGCAttr() != GCAttr) - Result = QualType(); - } - return Result; - } - } - if (LHSClass == Type::ExtQual) { - QualType::GCAttrTypes GCAttr = LHSCan.getObjCGCAttr(); - if (GCAttr != QualType::GCNone) { - QualType::GCAttrTypes GCRHSAttr = RHSCan.getObjCGCAttr(); - // __weak attribute must appear on both declarations. __strong - // __strong attribue is redundant if other decl is an objective-c - // object pointer (or decorated with __strong attribute); otherwise - // issue error. - if ((GCAttr == QualType::Weak && GCRHSAttr != GCAttr) || - (GCAttr == QualType::Strong && GCRHSAttr != GCAttr && - RHSCan->isPointerType() && !isObjCObjectPointerType(RHSCan) && - !isObjCIdStructType(RHSCan->getAsPointerType()->getPointeeType()))) - return QualType(); - - LHS = QualType(cast(LHS.getDesugaredType())->getBaseType(), - LHS.getCVRQualifiers()); - QualType Result = mergeTypes(LHS, RHS); - if (!Result.isNull()) { - if (Result.getObjCGCAttr() == QualType::GCNone) - Result = getObjCGCQualType(Result, GCAttr); - else if (Result.getObjCGCAttr() != GCAttr) - Result = QualType(); - } - return Result; - } - } - // Same as above for arrays if (LHSClass == Type::VariableArray || LHSClass == Type::IncompleteArray) LHSClass = Type::ConstantArray; if (RHSClass == Type::VariableArray || RHSClass == Type::IncompleteArray) RHSClass = Type::ConstantArray; - + // Canonicalize ExtVector -> Vector. if (LHSClass == Type::ExtVector) LHSClass = Type::Vector; if (RHSClass == Type::ExtVector) RHSClass = Type::Vector; - - // Consider qualified interfaces and interfaces the same. - if (LHSClass == Type::ObjCQualifiedInterface) LHSClass = Type::ObjCInterface; - if (RHSClass == Type::ObjCQualifiedInterface) RHSClass = Type::ObjCInterface; // If the canonical type classes don't match. if (LHSClass != RHSClass) { - const ObjCInterfaceType* LHSIface = LHS->getAsObjCInterfaceType(); - const ObjCInterfaceType* RHSIface = RHS->getAsObjCInterfaceType(); - - // 'id' and 'Class' act sort of like void* for ObjC interfaces - if (LHSIface && (isObjCIdStructType(RHS) || isObjCClassStructType(RHS))) - return LHS; - if (RHSIface && (isObjCIdStructType(LHS) || isObjCClassStructType(LHS))) - return RHS; - - // ID is compatible with all qualified id types. - if (LHS->isObjCQualifiedIdType()) { - if (const PointerType *PT = RHS->getAsPointerType()) { - QualType pType = PT->getPointeeType(); - if (isObjCIdStructType(pType) || isObjCClassStructType(pType)) - return LHS; - // FIXME: need to use ObjCQualifiedIdTypesAreCompatible(LHS, RHS, true). - // Unfortunately, this API is part of Sema (which we don't have access - // to. Need to refactor. The following check is insufficient, since we - // need to make sure the class implements the protocol. - if (pType->isObjCInterfaceType()) - return LHS; - } - } - if (RHS->isObjCQualifiedIdType()) { - if (const PointerType *PT = LHS->getAsPointerType()) { - QualType pType = PT->getPointeeType(); - if (isObjCIdStructType(pType) || isObjCClassStructType(pType)) - return RHS; - // FIXME: need to use ObjCQualifiedIdTypesAreCompatible(LHS, RHS, true). - // Unfortunately, this API is part of Sema (which we don't have access - // to. Need to refactor. The following check is insufficient, since we - // need to make sure the class implements the protocol. - if (pType->isObjCInterfaceType()) - return RHS; - } - } // C99 6.7.2.2p4: Each enumerated type shall be compatible with char, - // a signed integer type, or an unsigned integer type. - if (const EnumType* ETy = LHS->getAsEnumType()) { + // a signed integer type, or an unsigned integer type. + if (const EnumType* ETy = LHS->getAs()) { if (ETy->getDecl()->getIntegerType() == RHSCan.getUnqualifiedType()) return RHS; } - if (const EnumType* ETy = RHS->getAsEnumType()) { + if (const EnumType* ETy = RHS->getAs()) { if (ETy->getDecl()->getIntegerType() == LHSCan.getUnqualifiedType()) return LHS; } @@ -3456,15 +3855,14 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { case Type::VariableArray: case Type::FunctionProto: case Type::ExtVector: - case Type::ObjCQualifiedInterface: assert(false && "Types are eliminated above"); return QualType(); case Type::Pointer: { // Merge two pointer types, while trying to preserve typedef info - QualType LHSPointee = LHS->getAsPointerType()->getPointeeType(); - QualType RHSPointee = RHS->getAsPointerType()->getPointeeType(); + QualType LHSPointee = LHS->getAs()->getPointeeType(); + QualType RHSPointee = RHS->getAs()->getPointeeType(); QualType ResultType = mergeTypes(LHSPointee, RHSPointee); if (ResultType.isNull()) return QualType(); if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType)) @@ -3476,8 +3874,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { case Type::BlockPointer: { // Merge two block pointer types, while trying to preserve typedef info - QualType LHSPointee = LHS->getAsBlockPointerType()->getPointeeType(); - QualType RHSPointee = RHS->getAsBlockPointerType()->getPointeeType(); + QualType LHSPointee = LHS->getAs()->getPointeeType(); + QualType RHSPointee = RHS->getAs()->getPointeeType(); QualType ResultType = mergeTypes(LHSPointee, RHSPointee); if (ResultType.isNull()) return QualType(); if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType)) @@ -3525,15 +3923,13 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { } if (getCanonicalType(LHSElem) == getCanonicalType(ResultType)) return LHS; if (getCanonicalType(RHSElem) == getCanonicalType(ResultType)) return RHS; - return getIncompleteArrayType(ResultType, ArrayType::ArraySizeModifier(),0); + return getIncompleteArrayType(ResultType, + ArrayType::ArraySizeModifier(), 0); } case Type::FunctionNoProto: return mergeFunctionTypes(LHS, RHS); case Type::Record: case Type::Enum: - // FIXME: Why are these compatible? - if (isObjCIdStructType(LHS) && isObjCClassStructType(RHS)) return LHS; - if (isObjCClassStructType(LHS) && isObjCIdStructType(RHS)) return LHS; return QualType(); case Type::Builtin: // Only exactly equal builtin types are compatible, which is tested above. @@ -3543,56 +3939,31 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { return QualType(); case Type::Vector: // FIXME: The merged type should be an ExtVector! - if (areCompatVectorTypes(LHS->getAsVectorType(), RHS->getAsVectorType())) + if (areCompatVectorTypes(LHS->getAs(), RHS->getAs())) return LHS; return QualType(); case Type::ObjCInterface: { // Check if the interfaces are assignment compatible. // FIXME: This should be type compatibility, e.g. whether // "LHS x; RHS x;" at global scope is legal. - const ObjCInterfaceType* LHSIface = LHS->getAsObjCInterfaceType(); - const ObjCInterfaceType* RHSIface = RHS->getAsObjCInterfaceType(); + const ObjCInterfaceType* LHSIface = LHS->getAs(); + const ObjCInterfaceType* RHSIface = RHS->getAs(); if (LHSIface && RHSIface && canAssignObjCInterfaces(LHSIface, RHSIface)) return LHS; return QualType(); } - case Type::ObjCObjectPointer: - // FIXME: finish - // Distinct qualified id's are not compatible. + case Type::ObjCObjectPointer: { + if (canAssignObjCInterfaces(LHS->getAs(), + RHS->getAs())) + return LHS; + return QualType(); + } case Type::FixedWidthInt: // Distinct fixed-width integers are not compatible. return QualType(); - case Type::ExtQual: - // FIXME: ExtQual types can be compatible even if they're not - // identical! - return QualType(); - // First attempt at an implementation, but I'm not really sure it's - // right... -#if 0 - ExtQualType* LQual = cast(LHSCan); - ExtQualType* RQual = cast(RHSCan); - if (LQual->getAddressSpace() != RQual->getAddressSpace() || - LQual->getObjCGCAttr() != RQual->getObjCGCAttr()) - return QualType(); - QualType LHSBase, RHSBase, ResultType, ResCanUnqual; - LHSBase = QualType(LQual->getBaseType(), 0); - RHSBase = QualType(RQual->getBaseType(), 0); - ResultType = mergeTypes(LHSBase, RHSBase); - if (ResultType.isNull()) return QualType(); - ResCanUnqual = getCanonicalType(ResultType).getUnqualifiedType(); - if (LHSCan.getUnqualifiedType() == ResCanUnqual) - return LHS; - if (RHSCan.getUnqualifiedType() == ResCanUnqual) - return RHS; - ResultType = getAddrSpaceQualType(ResultType, LQual->getAddressSpace()); - ResultType = getObjCGCQualType(ResultType, LQual->getObjCGCAttr()); - ResultType.setCVRQualifiers(LHSCan.getCVRQualifiers()); - return ResultType; -#endif - case Type::TemplateSpecialization: assert(false && "Dependent types have no size"); break; @@ -3617,9 +3988,9 @@ unsigned ASTContext::getIntWidth(QualType T) { QualType ASTContext::getCorrespondingUnsignedType(QualType T) { assert(T->isSignedIntegerType() && "Unexpected type"); - if (const EnumType* ETy = T->getAsEnumType()) + if (const EnumType* ETy = T->getAs()) T = ETy->getDecl()->getIntegerType(); - const BuiltinType* BTy = T->getAsBuiltinType(); + const BuiltinType* BTy = T->getAs(); assert (BTy && "Unexpected signed integer type"); switch (BTy->getKind()) { case BuiltinType::Char_S: @@ -3652,18 +4023,18 @@ void ExternalASTSource::PrintStats() { } /// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the /// pointer over the consumed characters. This returns the resultant type. -static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, +static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, ASTContext::GetBuiltinTypeError &Error, bool AllowTypeModifiers = true) { // Modifiers. int HowLong = 0; bool Signed = false, Unsigned = false; - + // Read the modifiers first. bool Done = false; while (!Done) { switch (*Str++) { - default: Done = true; --Str; break; + default: Done = true; --Str; break; case 'S': assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!"); assert(!Signed && "Can't use 'S' modifier multiple times!"); @@ -3682,7 +4053,7 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, } QualType Type; - + // Read the base type. switch (*Str++) { default: assert(0 && "Unknown builtin type letter!"); @@ -3764,34 +4135,43 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, break; case 'V': { char *End; - unsigned NumElements = strtoul(Str, &End, 10); assert(End != Str && "Missing vector size"); - + Str = End; - + QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false); Type = Context.getVectorType(ElementType, NumElements); break; } - case 'P': { - IdentifierInfo *II = &Context.Idents.get("FILE"); - DeclContext::lookup_result Lookup - = Context.getTranslationUnitDecl()->lookup(II); - if (Lookup.first != Lookup.second && isa(*Lookup.first)) { - Type = Context.getTypeDeclType(cast(*Lookup.first)); - break; + case 'X': { + QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false); + Type = Context.getComplexType(ElementType); + break; + } + case 'P': + Type = Context.getFILEType(); + if (Type.isNull()) { + Error = ASTContext::GE_Missing_stdio; + return QualType(); } - else { - Error = ASTContext::GE_Missing_FILE; + break; + case 'J': + if (Signed) + Type = Context.getsigjmp_bufType(); + else + Type = Context.getjmp_bufType(); + + if (Type.isNull()) { + Error = ASTContext::GE_Missing_setjmp; return QualType(); } + break; } - } - + if (!AllowTypeModifiers) return Type; - + Done = false; while (!Done) { switch (*Str++) { @@ -3804,11 +4184,11 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, break; // FIXME: There's no way to have a built-in with an rvalue ref arg. case 'C': - Type = Type.getQualifiedType(QualType::Const); + Type = Type.withConst(); break; } } - + return Type; } @@ -3816,9 +4196,9 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, QualType ASTContext::GetBuiltinType(unsigned id, GetBuiltinTypeError &Error) { const char *TypeStr = BuiltinInfo.GetTypeString(id); - + llvm::SmallVector ArgTypes; - + Error = GE_None; QualType ResType = DecodeTypeFromStr(TypeStr, *this, Error); if (Error != GE_None) @@ -3831,7 +4211,7 @@ QualType ASTContext::GetBuiltinType(unsigned id, // Do array -> pointer decay. The builtin should use the decayed type. if (Ty->isArrayType()) Ty = getArrayDecayedType(Ty); - + ArgTypes.push_back(Ty); } @@ -3844,3 +4224,143 @@ QualType ASTContext::GetBuiltinType(unsigned id, return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(), TypeStr[0] == '.', 0); } + +QualType +ASTContext::UsualArithmeticConversionsType(QualType lhs, QualType rhs) { + // Perform the usual unary conversions. We do this early so that + // integral promotions to "int" can allow us to exit early, in the + // lhs == rhs check. Also, for conversion purposes, we ignore any + // qualifiers. For example, "const float" and "float" are + // equivalent. + if (lhs->isPromotableIntegerType()) + lhs = getPromotedIntegerType(lhs); + else + lhs = lhs.getUnqualifiedType(); + if (rhs->isPromotableIntegerType()) + rhs = getPromotedIntegerType(rhs); + else + rhs = rhs.getUnqualifiedType(); + + // If both types are identical, no conversion is needed. + if (lhs == rhs) + return lhs; + + // If either side is a non-arithmetic type (e.g. a pointer), we are done. + // The caller can deal with this (e.g. pointer + int). + if (!lhs->isArithmeticType() || !rhs->isArithmeticType()) + return lhs; + + // At this point, we have two different arithmetic types. + + // Handle complex types first (C99 6.3.1.8p1). + if (lhs->isComplexType() || rhs->isComplexType()) { + // if we have an integer operand, the result is the complex type. + if (rhs->isIntegerType() || rhs->isComplexIntegerType()) { + // convert the rhs to the lhs complex type. + return lhs; + } + if (lhs->isIntegerType() || lhs->isComplexIntegerType()) { + // convert the lhs to the rhs complex type. + return rhs; + } + // This handles complex/complex, complex/float, or float/complex. + // When both operands are complex, the shorter operand is converted to the + // type of the longer, and that is the type of the result. This corresponds + // to what is done when combining two real floating-point operands. + // The fun begins when size promotion occur across type domains. + // From H&S 6.3.4: When one operand is complex and the other is a real + // floating-point type, the less precise type is converted, within it's + // real or complex domain, to the precision of the other type. For example, + // when combining a "long double" with a "double _Complex", the + // "double _Complex" is promoted to "long double _Complex". + int result = getFloatingTypeOrder(lhs, rhs); + + if (result > 0) { // The left side is bigger, convert rhs. + rhs = getFloatingTypeOfSizeWithinDomain(lhs, rhs); + } else if (result < 0) { // The right side is bigger, convert lhs. + lhs = getFloatingTypeOfSizeWithinDomain(rhs, lhs); + } + // At this point, lhs and rhs have the same rank/size. Now, make sure the + // domains match. This is a requirement for our implementation, C99 + // does not require this promotion. + if (lhs != rhs) { // Domains don't match, we have complex/float mix. + if (lhs->isRealFloatingType()) { // handle "double, _Complex double". + return rhs; + } else { // handle "_Complex double, double". + return lhs; + } + } + return lhs; // The domain/size match exactly. + } + // Now handle "real" floating types (i.e. float, double, long double). + if (lhs->isRealFloatingType() || rhs->isRealFloatingType()) { + // if we have an integer operand, the result is the real floating type. + if (rhs->isIntegerType()) { + // convert rhs to the lhs floating point type. + return lhs; + } + if (rhs->isComplexIntegerType()) { + // convert rhs to the complex floating point type. + return getComplexType(lhs); + } + if (lhs->isIntegerType()) { + // convert lhs to the rhs floating point type. + return rhs; + } + if (lhs->isComplexIntegerType()) { + // convert lhs to the complex floating point type. + return getComplexType(rhs); + } + // We have two real floating types, float/complex combos were handled above. + // Convert the smaller operand to the bigger result. + int result = getFloatingTypeOrder(lhs, rhs); + if (result > 0) // convert the rhs + return lhs; + assert(result < 0 && "illegal float comparison"); + return rhs; // convert the lhs + } + if (lhs->isComplexIntegerType() || rhs->isComplexIntegerType()) { + // Handle GCC complex int extension. + const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType(); + const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType(); + + if (lhsComplexInt && rhsComplexInt) { + if (getIntegerTypeOrder(lhsComplexInt->getElementType(), + rhsComplexInt->getElementType()) >= 0) + return lhs; // convert the rhs + return rhs; + } else if (lhsComplexInt && rhs->isIntegerType()) { + // convert the rhs to the lhs complex type. + return lhs; + } else if (rhsComplexInt && lhs->isIntegerType()) { + // convert the lhs to the rhs complex type. + return rhs; + } + } + // Finally, we have two differing integer types. + // The rules for this case are in C99 6.3.1.8 + int compare = getIntegerTypeOrder(lhs, rhs); + bool lhsSigned = lhs->isSignedIntegerType(), + rhsSigned = rhs->isSignedIntegerType(); + QualType destType; + if (lhsSigned == rhsSigned) { + // Same signedness; use the higher-ranked type + destType = compare >= 0 ? lhs : rhs; + } else if (compare != (lhsSigned ? 1 : -1)) { + // The unsigned type has greater than or equal rank to the + // signed type, so use the unsigned type + destType = lhsSigned ? rhs : lhs; + } else if (getIntWidth(lhs) != getIntWidth(rhs)) { + // The two types are different widths; if we are here, that + // means the signed type is larger than the unsigned type, so + // use the signed type. + destType = lhsSigned ? lhs : rhs; + } else { + // The signed type is higher-ranked than the unsigned type, + // but isn't actually any bigger (like unsigned int and long + // on most 32-bit systems). Use the unsigned type corresponding + // to the signed type. + destType = getCorrespondingUnsignedType(lhsSigned ? lhs : rhs); + } + return destType; +} diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index ac4cbb2d296e..20e1150b22c2 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -4,28 +4,31 @@ add_clang_library(clangAST APValue.cpp ASTConsumer.cpp ASTContext.cpp - CFG.cpp - DeclarationName.cpp - DeclBase.cpp + CXXInheritance.cpp Decl.cpp + DeclBase.cpp DeclCXX.cpp DeclGroup.cpp DeclObjC.cpp DeclPrinter.cpp DeclTemplate.cpp - ExprConstant.cpp + DeclarationName.cpp Expr.cpp ExprCXX.cpp + ExprConstant.cpp InheritViz.cpp NestedNameSpecifier.cpp ParentMap.cpp + RecordLayoutBuilder.cpp Stmt.cpp StmtDumper.cpp StmtIterator.cpp StmtPrinter.cpp + StmtProfile.cpp StmtViz.cpp TemplateName.cpp Type.cpp + TypeLoc.cpp ) add_dependencies(clangAST ClangDiagnosticAST) diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp new file mode 100644 index 000000000000..4a46eab2e603 --- /dev/null +++ b/lib/AST/CXXInheritance.cpp @@ -0,0 +1,244 @@ +//===------ CXXInheritance.cpp - C++ Inheritance ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides routines that help analyzing C++ inheritance hierarchies. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/DeclCXX.h" +#include +#include + +using namespace clang; + +/// \brief Computes the set of declarations referenced by these base +/// paths. +void CXXBasePaths::ComputeDeclsFound() { + assert(NumDeclsFound == 0 && !DeclsFound && + "Already computed the set of declarations"); + + std::set Decls; + for (CXXBasePaths::paths_iterator Path = begin(), PathEnd = end(); + Path != PathEnd; ++Path) + Decls.insert(*Path->Decls.first); + + NumDeclsFound = Decls.size(); + DeclsFound = new NamedDecl * [NumDeclsFound]; + std::copy(Decls.begin(), Decls.end(), DeclsFound); +} + +CXXBasePaths::decl_iterator CXXBasePaths::found_decls_begin() { + if (NumDeclsFound == 0) + ComputeDeclsFound(); + return DeclsFound; +} + +CXXBasePaths::decl_iterator CXXBasePaths::found_decls_end() { + if (NumDeclsFound == 0) + ComputeDeclsFound(); + return DeclsFound + NumDeclsFound; +} + +/// isAmbiguous - Determines whether the set of paths provided is +/// ambiguous, i.e., there are two or more paths that refer to +/// different base class subobjects of the same type. BaseType must be +/// an unqualified, canonical class type. +bool CXXBasePaths::isAmbiguous(QualType BaseType) { + assert(BaseType->isCanonical() && "Base type must be the canonical type"); + assert(BaseType.hasQualifiers() == 0 && "Base type must be unqualified"); + std::pair& Subobjects = ClassSubobjects[BaseType]; + return Subobjects.second + (Subobjects.first? 1 : 0) > 1; +} + +/// clear - Clear out all prior path information. +void CXXBasePaths::clear() { + Paths.clear(); + ClassSubobjects.clear(); + ScratchPath.clear(); + DetectedVirtual = 0; +} + +/// @brief Swaps the contents of this CXXBasePaths structure with the +/// contents of Other. +void CXXBasePaths::swap(CXXBasePaths &Other) { + std::swap(Origin, Other.Origin); + Paths.swap(Other.Paths); + ClassSubobjects.swap(Other.ClassSubobjects); + std::swap(FindAmbiguities, Other.FindAmbiguities); + std::swap(RecordPaths, Other.RecordPaths); + std::swap(DetectVirtual, Other.DetectVirtual); + std::swap(DetectedVirtual, Other.DetectedVirtual); +} + +bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base) { + CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false, + /*DetectVirtual=*/false); + return isDerivedFrom(Base, Paths); +} + +bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) { + if (getCanonicalDecl() == Base->getCanonicalDecl()) + return false; + + Paths.setOrigin(this); + return lookupInBases(&FindBaseClass, Base->getCanonicalDecl(), Paths); +} + +bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, + void *UserData, + CXXBasePaths &Paths) { + bool FoundPath = false; + + ASTContext &Context = getASTContext(); + for (base_class_iterator BaseSpec = bases_begin(), BaseSpecEnd = bases_end(); + BaseSpec != BaseSpecEnd; ++BaseSpec) { + // Find the record of the base class subobjects for this type. + QualType BaseType = Context.getCanonicalType(BaseSpec->getType()); + BaseType = BaseType.getUnqualifiedType(); + + // C++ [temp.dep]p3: + // In the definition of a class template or a member of a class template, + // if a base class of the class template depends on a template-parameter, + // the base class scope is not examined during unqualified name lookup + // either at the point of definition of the class template or member or + // during an instantiation of the class tem- plate or member. + if (BaseType->isDependentType()) + continue; + + // Determine whether we need to visit this base class at all, + // updating the count of subobjects appropriately. + std::pair& Subobjects = Paths.ClassSubobjects[BaseType]; + bool VisitBase = true; + bool SetVirtual = false; + if (BaseSpec->isVirtual()) { + VisitBase = !Subobjects.first; + Subobjects.first = true; + if (Paths.isDetectingVirtual() && Paths.DetectedVirtual == 0) { + // If this is the first virtual we find, remember it. If it turns out + // there is no base path here, we'll reset it later. + Paths.DetectedVirtual = BaseType->getAs(); + SetVirtual = true; + } + } else + ++Subobjects.second; + + if (Paths.isRecordingPaths()) { + // Add this base specifier to the current path. + CXXBasePathElement Element; + Element.Base = &*BaseSpec; + Element.Class = this; + if (BaseSpec->isVirtual()) + Element.SubobjectNumber = 0; + else + Element.SubobjectNumber = Subobjects.second; + Paths.ScratchPath.push_back(Element); + } + + if (BaseMatches(BaseSpec, Paths.ScratchPath, UserData)) { + // We've found a path that terminates that this base. + FoundPath = true; + if (Paths.isRecordingPaths()) { + // We have a path. Make a copy of it before moving on. + Paths.Paths.push_back(Paths.ScratchPath); + } else if (!Paths.isFindingAmbiguities()) { + // We found a path and we don't care about ambiguities; + // return immediately. + return FoundPath; + } + } else if (VisitBase) { + CXXRecordDecl *BaseRecord + = cast(BaseSpec->getType()->getAs() + ->getDecl()); + if (BaseRecord->lookupInBases(BaseMatches, UserData, Paths)) { + // C++ [class.member.lookup]p2: + // A member name f in one sub-object B hides a member name f in + // a sub-object A if A is a base class sub-object of B. Any + // declarations that are so hidden are eliminated from + // consideration. + + // 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; + if (!Paths.isFindingAmbiguities()) + return FoundPath; + } + } + + // Pop this base specifier off the current path (if we're + // collecting paths). + if (Paths.isRecordingPaths()) + Paths.ScratchPath.pop_back(); + // If we set a virtual earlier, and this isn't a path, forget it again. + if (SetVirtual && !FoundPath) { + Paths.DetectedVirtual = 0; + } + } + + return FoundPath; +} + +bool CXXRecordDecl::FindBaseClass(CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *BaseRecord) { + assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord && + "User data for FindBaseClass is not canonical!"); + return Specifier->getType()->getAs()->getDecl() + ->getCanonicalDecl() == BaseRecord; +} + +bool CXXRecordDecl::FindTagMember(CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *Name) { + RecordDecl *BaseRecord = Specifier->getType()->getAs()->getDecl(); + + DeclarationName N = DeclarationName::getFromOpaquePtr(Name); + for (Path.Decls = BaseRecord->lookup(N); + Path.Decls.first != Path.Decls.second; + ++Path.Decls.first) { + if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag)) + return true; + } + + return false; +} + +bool CXXRecordDecl::FindOrdinaryMember(CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *Name) { + RecordDecl *BaseRecord = Specifier->getType()->getAs()->getDecl(); + + const unsigned IDNS = IDNS_Ordinary | IDNS_Tag | IDNS_Member; + DeclarationName N = DeclarationName::getFromOpaquePtr(Name); + for (Path.Decls = BaseRecord->lookup(N); + Path.Decls.first != Path.Decls.second; + ++Path.Decls.first) { + if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS)) + return true; + } + + return false; +} + +bool CXXRecordDecl::FindNestedNameSpecifierMember(CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *Name) { + RecordDecl *BaseRecord = Specifier->getType()->getAs()->getDecl(); + + DeclarationName N = DeclarationName::getFromOpaquePtr(Name); + for (Path.Decls = BaseRecord->lookup(N); + Path.Decls.first != Path.Decls.second; + ++Path.Decls.first) { + // FIXME: Refactor the "is it a nested-name-specifier?" check + if (isa(*Path.Decls.first) || + (*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag)) + return true; + } + + return false; +} diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 3d02150b65bf..429729ea3b0e 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -16,11 +16,14 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/TypeLoc.h" #include "clang/AST/Stmt.h" #include "clang/AST/Expr.h" #include "clang/AST/PrettyPrinter.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Parse/DeclSpec.h" +#include "llvm/Support/ErrorHandling.h" #include using namespace clang; @@ -34,11 +37,15 @@ void Attr::Destroy(ASTContext &C) { C.Deallocate((void*)this); } +/// \brief Return the TypeLoc wrapper for the type source info. +TypeLoc DeclaratorInfo::getTypeLoc() const { + return TypeLoc(Ty, (void*)(this + 1)); +} //===----------------------------------------------------------------------===// // Decl Allocation/Deallocation Method Implementations //===----------------------------------------------------------------------===// - + TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) { return new (C) TranslationUnitDecl(C); @@ -52,7 +59,7 @@ NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC, 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); } @@ -68,9 +75,9 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass 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::PrivateExtern: return "__private_extern__"; break; case VarDecl::Register: return "register"; break; - case VarDecl::Static: return "static"; break; + case VarDecl::Static: return "static"; break; } assert(0 && "Invalid storage class"); @@ -79,34 +86,45 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, StorageClass S, - Expr *DefArg) { - return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, S, DefArg); + QualType T, DeclaratorInfo *DInfo, + StorageClass S, Expr *DefArg) { + return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, DInfo, S, DefArg); } QualType ParmVarDecl::getOriginalType() const { - if (const OriginalParmVarDecl *PVD = + if (const OriginalParmVarDecl *PVD = dyn_cast(this)) return PVD->OriginalType; return getType(); } -void VarDecl::setInit(ASTContext &C, Expr *I) { - if (EvaluatedStmt *Eval = Init.dyn_cast()) { - Eval->~EvaluatedStmt(); - C.Deallocate(Eval); - } +SourceRange ParmVarDecl::getDefaultArgRange() const { + if (const Expr *E = getInit()) + return E->getSourceRange(); + + if (const Expr *E = getUninstantiatedDefaultArg()) + return E->getSourceRange(); + + return SourceRange(); +} - Init = I; +void VarDecl::setInit(ASTContext &C, Expr *I) { + if (EvaluatedStmt *Eval = Init.dyn_cast()) { + Eval->~EvaluatedStmt(); + C.Deallocate(Eval); } -bool VarDecl::isExternC(ASTContext &Context) const { + Init = I; +} + +bool VarDecl::isExternC() const { + ASTContext &Context = getASTContext(); if (!Context.getLangOptions().CPlusPlus) - return (getDeclContext()->isTranslationUnit() && + return (getDeclContext()->isTranslationUnit() && getStorageClass() != Static) || (getDeclContext()->isFunctionOrMethod() && hasExternalStorage()); - for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); + for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); DC = DC->getParent()) { if (const LinkageSpecDecl *Linkage = dyn_cast(DC)) { if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) @@ -125,20 +143,19 @@ bool VarDecl::isExternC(ASTContext &Context) const { OriginalParmVarDecl *OriginalParmVarDecl::Create( ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, QualType OT, StorageClass S, - Expr *DefArg) { - return new (C) OriginalParmVarDecl(DC, L, Id, T, OT, S, DefArg); + QualType T, DeclaratorInfo *DInfo, + QualType OT, StorageClass S, Expr *DefArg) { + return new (C) OriginalParmVarDecl(DC, L, Id, T, DInfo, OT, S, DefArg); } FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - DeclarationName N, QualType T, - StorageClass S, bool isInline, - bool hasWrittenPrototype, - SourceLocation TypeSpecStartLoc) { - FunctionDecl *New - = new (C) FunctionDecl(Function, DC, L, N, T, S, isInline, - TypeSpecStartLoc); + SourceLocation L, + DeclarationName N, QualType T, + DeclaratorInfo *DInfo, + StorageClass S, bool isInline, + bool hasWrittenPrototype) { + FunctionDecl *New + = new (C) FunctionDecl(Function, DC, L, N, T, DInfo, S, isInline); New->HasWrittenPrototype = hasWrittenPrototype; return New; } @@ -148,16 +165,16 @@ BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { } FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, Expr *BW, - bool Mutable) { - return new (C) FieldDecl(Decl::Field, DC, L, Id, T, BW, Mutable); + IdentifierInfo *Id, QualType T, + DeclaratorInfo *DInfo, Expr *BW, bool Mutable) { + return new (C) FieldDecl(Decl::Field, DC, L, Id, T, DInfo, BW, Mutable); } bool FieldDecl::isAnonymousStructOrUnion() const { if (!isImplicit() || getDeclName()) return false; - - if (const RecordType *Record = getType()->getAsRecordType()) + + if (const RecordType *Record = getType()->getAs()) return Record->getDecl()->isAnonymousStructOrUnion(); return false; @@ -182,9 +199,9 @@ TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, } EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, + IdentifierInfo *Id, SourceLocation TKL, EnumDecl *PrevDecl) { - EnumDecl *Enum = new (C) EnumDecl(DC, L, Id); + EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL); C.getTypeDeclType(Enum, PrevDecl); return Enum; } @@ -210,6 +227,10 @@ FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, //===----------------------------------------------------------------------===// std::string NamedDecl::getQualifiedNameAsString() const { + return getQualifiedNameAsString(getASTContext().getLangOptions()); +} + +std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { std::vector Names; std::string QualName; const DeclContext *Ctx = getDeclContext(); @@ -223,15 +244,14 @@ std::string NamedDecl::getQualifiedNameAsString() const { // scope class/struct/union. How do we handle this case? break; - if (const ClassTemplateSpecializationDecl *Spec + if (const ClassTemplateSpecializationDecl *Spec = dyn_cast(Ctx)) { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); - PrintingPolicy Policy(getASTContext().getLangOptions()); std::string TemplateArgsStr = TemplateSpecializationType::PrintTemplateArgumentList( TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size(), - Policy); + P); Names.push_back(Spec->getIdentifier()->getName() + TemplateArgsStr); } else if (const NamedDecl *ND = dyn_cast(Ctx)) Names.push_back(ND->getNameAsString()); @@ -253,7 +273,6 @@ std::string NamedDecl::getQualifiedNameAsString() const { return QualName; } - bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch"); @@ -263,7 +282,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { return cast(this)->getNominatedNamespace() == cast(OldD)->getNominatedNamespace(); } - + if (const FunctionDecl *FD = dyn_cast(this)) // For function declarations, we keep track of redeclarations. return FD->getPreviousDeclaration() == OldD; @@ -275,11 +294,14 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { = dyn_cast(OldD)) return FunctionTemplate->getTemplatedDecl() ->declarationReplaces(OldFunctionTemplate->getTemplatedDecl()); - + // For method declarations, we keep track of redeclarations. if (isa(this)) return false; - + + if (isa(this) && isa(OldD)) + return true; + // For non-function declarations, if the declarations are of the // same kind then this must be a redeclaration, or semantic analysis // would not have given us the new declaration. @@ -309,14 +331,24 @@ NamedDecl *NamedDecl::getUnderlyingDecl() { } } +//===----------------------------------------------------------------------===// +// DeclaratorDecl Implementation +//===----------------------------------------------------------------------===// + +SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const { + if (DeclInfo) + return DeclInfo->getTypeLoc().getTypeSpecRange().getBegin(); + return SourceLocation(); +} + //===----------------------------------------------------------------------===// // VarDecl Implementation //===----------------------------------------------------------------------===// VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, StorageClass S, - SourceLocation TypeSpecStartLoc) { - return new (C) VarDecl(Var, DC, L, Id, T, S, TypeSpecStartLoc); + IdentifierInfo *Id, QualType T, DeclaratorInfo *DInfo, + StorageClass S) { + return new (C) VarDecl(Var, DC, L, Id, T, DInfo, S); } void VarDecl::Destroy(ASTContext& C) { @@ -341,6 +373,31 @@ SourceRange VarDecl::getSourceRange() const { return SourceRange(getLocation(), getLocation()); } +VarDecl *VarDecl::getInstantiatedFromStaticDataMember() { + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) + return cast(MSI->getInstantiatedFrom()); + + return 0; +} + +TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() { + if (MemberSpecializationInfo *MSI + = getASTContext().getInstantiatedFromStaticDataMember(this)) + return MSI->getTemplateSpecializationKind(); + + return TSK_Undeclared; +} + +MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() { + return getASTContext().getInstantiatedFromStaticDataMember(this); +} + +void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + MemberSpecializationInfo *MSI = getMemberSpecializationInfo(); + assert(MSI && "Not an instantiated static data member?"); + MSI->setTemplateSpecializationKind(TSK); +} + bool VarDecl::isTentativeDefinition(ASTContext &Context) const { if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus) return false; @@ -351,11 +408,19 @@ bool VarDecl::isTentativeDefinition(ASTContext &Context) const { } const Expr *VarDecl::getDefinition(const VarDecl *&Def) const { - Def = this; - while (Def && !Def->getInit()) - Def = Def->getPreviousDeclaration(); + redecl_iterator I = redecls_begin(), E = redecls_end(); + while (I != E && !I->getInit()) + ++I; - return Def? Def->getInit() : 0; + if (I != E) { + Def = *I; + return I->getInit(); + } + return 0; +} + +VarDecl *VarDecl::getCanonicalDecl() { + return getFirstDeclaration(); } //===----------------------------------------------------------------------===// @@ -369,27 +434,39 @@ void FunctionDecl::Destroy(ASTContext& C) { for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I) (*I)->Destroy(C); + FunctionTemplateSpecializationInfo *FTSInfo + = TemplateOrSpecialization.dyn_cast(); + if (FTSInfo) + C.Deallocate(FTSInfo); + + MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast(); + if (MSInfo) + C.Deallocate(MSInfo); + C.Deallocate(ParamInfo); Decl::Destroy(C); } - -Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { - for (const FunctionDecl *FD = this; FD != 0; FD = FD->PreviousDeclaration) { - if (FD->Body) { - Definition = FD; - return FD->Body.get(getASTContext().getExternalSource()); - } - } - - return 0; +void FunctionDecl::getNameForDiagnostic(std::string &S, + const PrintingPolicy &Policy, + bool Qualified) const { + NamedDecl::getNameForDiagnostic(S, Policy, Qualified); + const TemplateArgumentList *TemplateArgs = getTemplateSpecializationArgs(); + if (TemplateArgs) + S += TemplateSpecializationType::PrintTemplateArgumentList( + TemplateArgs->getFlatArgumentList(), + TemplateArgs->flat_size(), + Policy); + } -Stmt *FunctionDecl::getBodyIfAvailable() const { - for (const FunctionDecl *FD = this; FD != 0; FD = FD->PreviousDeclaration) { - if (FD->Body && !FD->Body.isOffset()) { - return FD->Body.get(0); +Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { + if (I->Body) { + Definition = *I; + return I->Body.get(getASTContext().getExternalSource()); } } @@ -403,21 +480,24 @@ void FunctionDecl::setBody(Stmt *B) { } bool FunctionDecl::isMain() const { - return getDeclContext()->getLookupContext()->isTranslationUnit() && + ASTContext &Context = getASTContext(); + return !Context.getLangOptions().Freestanding && + getDeclContext()->getLookupContext()->isTranslationUnit() && getIdentifier() && getIdentifier()->isStr("main"); } -bool FunctionDecl::isExternC(ASTContext &Context) const { +bool FunctionDecl::isExternC() const { + ASTContext &Context = getASTContext(); // In C, any non-static, non-overloadable function has external // linkage. if (!Context.getLangOptions().CPlusPlus) return getStorageClass() != Static && !getAttr(); - for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); + for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); DC = DC->getParent()) { if (const LinkageSpecDecl *Linkage = dyn_cast(DC)) { if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) - return getStorageClass() != Static && + return getStorageClass() != Static && !getAttr(); break; @@ -434,7 +514,7 @@ bool FunctionDecl::isGlobal() const { if (getStorageClass() == Static) return false; - for (const DeclContext *DC = getDeclContext(); + for (const DeclContext *DC = getDeclContext(); DC->isNamespace(); DC = DC->getParent()) { if (const NamespaceDecl *Namespace = cast(DC)) { @@ -454,9 +534,10 @@ bool FunctionDecl::isGlobal() const { /// declared at translation scope or within an extern "C" block and /// its name matches with the name of a builtin. The returned value /// will be 0 for functions that do not correspond to a builtin, a -/// value of type \c Builtin::ID if in the target-independent range +/// value of type \c Builtin::ID if in the target-independent range /// \c [1,Builtin::First), or a target-specific builtin value. -unsigned FunctionDecl::getBuiltinID(ASTContext &Context) const { +unsigned FunctionDecl::getBuiltinID() const { + ASTContext &Context = getASTContext(); if (!getIdentifier() || !getIdentifier()->getBuiltinID()) return 0; @@ -481,7 +562,7 @@ unsigned FunctionDecl::getBuiltinID(ASTContext &Context) const { // If the function is in an extern "C" linkage specification and is // not marked "overloadable", it's the real function. if (isa(getDeclContext()) && - cast(getDeclContext())->getLanguage() + cast(getDeclContext())->getLanguage() == LinkageSpecDecl::lang_c && !getAttr()) return BuiltinID; @@ -495,18 +576,18 @@ unsigned FunctionDecl::getBuiltinID(ASTContext &Context) const { /// based on its FunctionType. This is the length of the PararmInfo array /// after it has been created. unsigned FunctionDecl::getNumParams() const { - const FunctionType *FT = getType()->getAsFunctionType(); + const FunctionType *FT = getType()->getAs(); if (isa(FT)) return 0; return cast(FT)->getNumArgs(); - + } void FunctionDecl::setParams(ASTContext& C, 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); @@ -533,42 +614,87 @@ unsigned FunctionDecl::getMinRequiredArguments() const { return NumRequiredArgs; } -bool FunctionDecl::hasActiveGNUInlineAttribute(ASTContext &Context) const { - if (!isInline() || !hasAttr()) +/// \brief For an inline function definition in C, determine whether the +/// definition will be externally visible. +/// +/// Inline function definitions are always available for inlining optimizations. +/// However, depending on the language dialect, declaration specifiers, and +/// attributes, the definition of an inline function may or may not be +/// "externally" visible to other translation units in the program. +/// +/// In C99, inline definitions are not externally visible by default. However, +/// if even one of the globa-scope declarations is marked "extern inline", the +/// inline definition becomes externally visible (C99 6.7.4p6). +/// +/// In GNU89 mode, or if the gnu_inline attribute is attached to the function +/// definition, we use the GNU semantics for inline, which are nearly the +/// opposite of C99 semantics. In particular, "inline" by itself will create +/// an externally visible symbol, but "extern inline" will not create an +/// externally visible symbol. +bool FunctionDecl::isInlineDefinitionExternallyVisible() const { + assert(isThisDeclarationADefinition() && "Must have the function definition"); + assert(isInline() && "Function must be inline"); + + if (!getASTContext().getLangOptions().C99 || hasAttr()) { + // GNU inline semantics. Based on a number of examples, we came up with the + // following heuristic: if the "inline" keyword is present on a + // declaration of the function but "extern" is not present on that + // declaration, then the symbol is externally visible. Otherwise, the GNU + // "extern inline" semantics applies and the symbol is not externally + // visible. + for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end(); + Redecl != RedeclEnd; + ++Redecl) { + if (Redecl->isInline() && Redecl->getStorageClass() != Extern) + return true; + } + + // GNU "extern inline" semantics; no externally visible symbol. return false; - - for (const FunctionDecl *FD = getPreviousDeclaration(); FD; - FD = FD->getPreviousDeclaration()) { - if (FD->isInline() && !FD->hasAttr()) - return false; } - - return true; -} - -bool FunctionDecl::isExternGNUInline(ASTContext &Context) const { - if (!hasActiveGNUInlineAttribute(Context)) - return false; - - for (const FunctionDecl *FD = this; FD; FD = FD->getPreviousDeclaration()) - if (FD->getStorageClass() == Extern && FD->hasAttr()) - return true; - + + // C99 6.7.4p6: + // [...] If all of the file scope declarations for a function in a + // translation unit include the inline function specifier without extern, + // then the definition in that translation unit is an inline definition. + for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end(); + Redecl != RedeclEnd; + ++Redecl) { + // Only consider file-scope declarations in this test. + if (!Redecl->getLexicalDeclContext()->isTranslationUnit()) + continue; + + if (!Redecl->isInline() || Redecl->getStorageClass() == Extern) + return true; // Not an inline definition + } + + // C99 6.7.4p6: + // An inline definition does not provide an external definition for the + // function, and does not forbid an external definition in another + // translation unit. return false; } -void +void FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { - PreviousDeclaration = PrevDecl; - + redeclarable_base::setPreviousDeclaration(PrevDecl); + if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) { - FunctionTemplateDecl *PrevFunTmpl + 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 { @@ -578,8 +704,29 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { return OO_None; } +FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const { + if (MemberSpecializationInfo *Info = getMemberSpecializationInfo()) + return cast(Info->getInstantiatedFrom()); + + return 0; +} + +MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const { + return TemplateOrSpecialization.dyn_cast(); +} + +void +FunctionDecl::setInstantiationOfMemberFunction(FunctionDecl *FD, + TemplateSpecializationKind TSK) { + assert(TemplateOrSpecialization.isNull() && + "Member function is already a specialization"); + MemberSpecializationInfo *Info + = new (getASTContext()) MemberSpecializationInfo(FD, TSK); + TemplateOrSpecialization = Info; +} + FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const { - if (FunctionTemplateSpecializationInfo *Info + if (FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization .dyn_cast()) { return Info->Template.getPointer(); @@ -589,79 +736,151 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const { const TemplateArgumentList * FunctionDecl::getTemplateSpecializationArgs() const { - if (FunctionTemplateSpecializationInfo *Info - = TemplateOrSpecialization - .dyn_cast()) { + if (FunctionTemplateSpecializationInfo *Info + = TemplateOrSpecialization + .dyn_cast()) { return Info->TemplateArguments; } return 0; } -void +void FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context, FunctionTemplateDecl *Template, const TemplateArgumentList *TemplateArgs, - void *InsertPos) { - FunctionTemplateSpecializationInfo *Info + void *InsertPos, + TemplateSpecializationKind TSK) { + assert(TSK != TSK_Undeclared && + "Must specify the type of function template specialization"); + FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization.dyn_cast(); if (!Info) Info = new (Context) FunctionTemplateSpecializationInfo; - + Info->Function = this; Info->Template.setPointer(Template); - Info->Template.setInt(0); // Implicit instantiation, unless told otherwise + Info->Template.setInt(TSK - 1); Info->TemplateArguments = TemplateArgs; TemplateOrSpecialization = Info; - + // Insert this function template specialization into the set of known - // function template specialiations. - Template->getSpecializations().InsertNode(Info, InsertPos); + // function template specializations. + if (InsertPos) + Template->getSpecializations().InsertNode(Info, InsertPos); + else { + // Try to insert the new node. If there is an existing node, remove it + // first. + FunctionTemplateSpecializationInfo *Existing + = Template->getSpecializations().GetOrInsertNode(Info); + if (Existing) { + Template->getSpecializations().RemoveNode(Existing); + Template->getSpecializations().GetOrInsertNode(Info); + } + } } -bool FunctionDecl::isExplicitSpecialization() const { - // FIXME: check this property for explicit specializations of member - // functions of class templates. - FunctionTemplateSpecializationInfo *Info +TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { + // For a function template specialization, query the specialization + // information object. + FunctionTemplateSpecializationInfo *FTSInfo = TemplateOrSpecialization.dyn_cast(); - if (!Info) - return false; + if (FTSInfo) + return FTSInfo->getTemplateSpecializationKind(); + + MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast(); + if (MSInfo) + return MSInfo->getTemplateSpecializationKind(); - return Info->isExplicitSpecialization(); + return TSK_Undeclared; +} + +void +FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + if (FunctionTemplateSpecializationInfo *FTSInfo + = TemplateOrSpecialization.dyn_cast< + FunctionTemplateSpecializationInfo*>()) + FTSInfo->setTemplateSpecializationKind(TSK); + else if (MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast()) + MSInfo->setTemplateSpecializationKind(TSK); + else + assert(false && "Function cannot have a template specialization kind"); } -void FunctionDecl::setExplicitSpecialization(bool ES) { - // FIXME: set this property for explicit specializations of member functions - // of class templates. - FunctionTemplateSpecializationInfo *Info - = TemplateOrSpecialization.dyn_cast(); - if (Info) - Info->setExplicitSpecialization(ES); +bool FunctionDecl::isOutOfLine() const { + // FIXME: Should we restrict this to member functions? + if (Decl::isOutOfLine()) + return true; + + // If this function was instantiated from a member function of a + // class template, check whether that member function was defined out-of-line. + if (FunctionDecl *FD = getInstantiatedFromMemberFunction()) { + const FunctionDecl *Definition; + if (FD->getBody(Definition)) + return Definition->isOutOfLine(); + } + + // If this function was instantiated from a function template, + // check whether that function template was defined out-of-line. + if (FunctionTemplateDecl *FunTmpl = getPrimaryTemplate()) { + const FunctionDecl *Definition; + if (FunTmpl->getTemplatedDecl()->getBody(Definition)) + return Definition->isOutOfLine(); + } + + return false; } //===----------------------------------------------------------------------===// // TagDecl Implementation //===----------------------------------------------------------------------===// +SourceRange TagDecl::getSourceRange() const { + SourceLocation E = RBraceLoc.isValid() ? RBraceLoc : getLocation(); + return SourceRange(TagKeywordLoc, E); +} + +TagDecl* TagDecl::getCanonicalDecl() { + return getFirstDeclaration(); +} + void TagDecl::startDefinition() { - TagType *TagT = const_cast(TypeForDecl->getAsTagType()); - TagT->decl.setPointer(this); - TagT->getAsTagType()->decl.setInt(1); + if (TagType *TagT = const_cast(TypeForDecl->getAs())) { + TagT->decl.setPointer(this); + TagT->decl.setInt(1); + } } void TagDecl::completeDefinition() { - assert((!TypeForDecl || - TypeForDecl->getAsTagType()->decl.getPointer() == this) && - "Attempt to redefine a tag definition?"); IsDefinition = true; - TagType *TagT = const_cast(TypeForDecl->getAsTagType()); - TagT->decl.setPointer(this); - TagT->decl.setInt(0); + if (TagType *TagT = const_cast(TypeForDecl->getAs())) { + assert(TagT->decl.getPointer() == this && + "Attempt to redefine a tag definition?"); + TagT->decl.setInt(0); + } } TagDecl* TagDecl::getDefinition(ASTContext& C) const { - QualType T = C.getTypeDeclType(const_cast(this)); - TagDecl* D = cast(T->getAsTagType()->getDecl()); - return D->isDefinition() ? D : 0; + if (isDefinition()) + return const_cast(this); + + for (redecl_iterator R = redecls_begin(), REnd = redecls_end(); + R != REnd; ++R) + if (R->isDefinition()) + return *R; + + return 0; +} + +TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) { + switch (TypeSpec) { + default: llvm::llvm_unreachable("unexpected type specifier"); + case DeclSpec::TST_struct: return TK_struct; + case DeclSpec::TST_class: return TK_class; + case DeclSpec::TST_union: return TK_union; + case DeclSpec::TST_enum: return TK_enum; + } } //===----------------------------------------------------------------------===// @@ -669,18 +888,20 @@ TagDecl* TagDecl::getDefinition(ASTContext& C) const { //===----------------------------------------------------------------------===// RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id) - : TagDecl(DK, TK, DC, L, Id) { + IdentifierInfo *Id, RecordDecl *PrevDecl, + SourceLocation TKL) + : TagDecl(DK, TK, DC, L, Id, PrevDecl, TKL) { HasFlexibleArrayMember = false; AnonymousStructOrUnion = false; + HasObjectMember = false; assert(classof(static_cast(this)) && "Invalid Kind!"); } RecordDecl *RecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - RecordDecl* PrevDecl) { - - RecordDecl* R = new (C) RecordDecl(Record, TK, DC, L, Id); + SourceLocation TKL, RecordDecl* PrevDecl) { + + RecordDecl* R = new (C) RecordDecl(Record, TK, DC, L, Id, PrevDecl, TKL); C.getTypeDeclType(R, PrevDecl); return R; } @@ -693,7 +914,7 @@ void RecordDecl::Destroy(ASTContext& C) { } bool RecordDecl::isInjectedClassName() const { - return isImplicit() && getDeclName() && getDeclContext()->isRecord() && + return isImplicit() && getDeclName() && getDeclContext()->isRecord() && cast(getDeclContext())->getDeclName() == getDeclName(); } @@ -717,15 +938,15 @@ void BlockDecl::Destroy(ASTContext& C) { for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I) (*I)->Destroy(C); - - C.Deallocate(ParamInfo); + + C.Deallocate(ParamInfo); Decl::Destroy(C); } void BlockDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo, unsigned NParms) { assert(ParamInfo == 0 && "Already has param info!"); - + // Zero params -> null pointer. if (NParms) { NumParams = NParms; diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 96ba19b9a6b9..224bf877ad24 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -62,12 +62,12 @@ bool Decl::CollectingStats(bool Enable) { void Decl::PrintStats() { fprintf(stderr, "*** Decl Stats:\n"); - + int totalDecls = 0; #define DECL(Derived, Base) totalDecls += n##Derived##s; #include "clang/AST/DeclNodes.def" fprintf(stderr, " %d decls total.\n", totalDecls); - + int totalBytes = 0; #define DECL(Derived, Base) \ if (n##Derived##s > 0) { \ @@ -77,7 +77,7 @@ void Decl::PrintStats() { (int)(n##Derived##s * sizeof(Derived##Decl))); \ } #include "clang/AST/DeclNodes.def" - + fprintf(stderr, "Total bytes = %d\n", totalBytes); } @@ -92,26 +92,26 @@ void Decl::addDeclKind(Kind k) { bool Decl::isTemplateParameterPack() const { if (const TemplateTypeParmDecl *TTP = dyn_cast(this)) return TTP->isParameterPack(); - + return false; } bool Decl::isFunctionOrFunctionTemplate() const { if (const UsingDecl *UD = dyn_cast(this)) return UD->getTargetDecl()->isFunctionOrFunctionTemplate(); - + return isa(this) || isa(this); } //===----------------------------------------------------------------------===// // PrettyStackTraceDecl Implementation //===----------------------------------------------------------------------===// - + void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const { SourceLocation TheLoc = Loc; if (TheLoc.isInvalid() && TheDecl) TheLoc = TheDecl->getLocation(); - + if (TheLoc.isValid()) { TheLoc.print(OS, SM); OS << ": "; @@ -123,7 +123,7 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const { OS << " '" << DN->getQualifiedNameAsString() << '\''; OS << '\n'; } - + //===----------------------------------------------------------------------===// // Decl Implementation //===----------------------------------------------------------------------===// @@ -132,14 +132,14 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const { Decl::~Decl() { if (isOutOfSemaDC()) delete getMultipleDC(); - + assert(!HasAttrs && "attributes should have been freed by Destroy"); } void Decl::setDeclContext(DeclContext *DC) { if (isOutOfSemaDC()) delete getMultipleDC(); - + DeclCtx = DC; } @@ -157,28 +157,39 @@ void Decl::setLexicalDeclContext(DeclContext *DC) { } } +bool Decl::isInAnonymousNamespace() const { + const DeclContext *DC = getDeclContext(); + do { + if (const NamespaceDecl *ND = dyn_cast(DC)) + if (ND->isAnonymousNamespace()) + return true; + } while ((DC = DC->getParent())); + + return false; +} + TranslationUnitDecl *Decl::getTranslationUnitDecl() { if (TranslationUnitDecl *TUD = dyn_cast(this)) return TUD; DeclContext *DC = getDeclContext(); assert(DC && "This decl is not contained in a translation unit!"); - + while (!DC->isTranslationUnit()) { DC = DC->getParent(); assert(DC && "This decl is not contained in a translation unit!"); } - + return cast(DC); } ASTContext &Decl::getASTContext() const { - return getTranslationUnitDecl()->getASTContext(); + return getTranslationUnitDecl()->getASTContext(); } unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { switch (DeclKind) { - default: + default: if (DeclKind >= FunctionFirst && DeclKind <= FunctionLast) return IDNS_Ordinary; assert(0 && "Unknown decl kind!"); @@ -191,6 +202,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case OriginalParmVar: case NonTypeTemplateParm: case Using: + case UnresolvedUsing: case ObjCMethod: case ObjCContainer: case ObjCCategory: @@ -198,10 +210,10 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCProperty: case ObjCCompatibleAlias: return IDNS_Ordinary; - + case ObjCProtocol: return IDNS_ObjCProtocol; - + case ObjCImplementation: return IDNS_ObjCImplementation; @@ -212,13 +224,13 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCAtDefsField: case ObjCIvar: return IDNS_Member; - + case Record: case CXXRecord: case Enum: case TemplateTypeParm: return IDNS_Tag; - + case Namespace: case Template: case FunctionTemplate: @@ -226,8 +238,10 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case TemplateTemplateParm: case NamespaceAlias: return IDNS_Tag | IDNS_Ordinary; - + // Never have names. + case Friend: + case FriendTemplate: case LinkageSpec: case FileScopeAsm: case StaticAssert: @@ -250,41 +264,41 @@ void Decl::addAttr(Attr *NewAttr) { NewAttr->setNext(ExistingAttr); ExistingAttr = NewAttr; - + HasAttrs = true; } void Decl::invalidateAttrs() { if (!HasAttrs) return; - + HasAttrs = false; getASTContext().eraseDeclAttrs(this); } const Attr *Decl::getAttrsImpl() const { - assert(HasAttrs && "getAttrs() should verify this!"); + assert(HasAttrs && "getAttrs() should verify this!"); return getASTContext().getDeclAttrs(this); } void Decl::swapAttrs(Decl *RHS) { bool HasLHSAttr = this->HasAttrs; bool HasRHSAttr = RHS->HasAttrs; - + // Usually, neither decl has attrs, nothing to do. if (!HasLHSAttr && !HasRHSAttr) return; - + // If 'this' has no attrs, swap the other way. if (!HasLHSAttr) return RHS->swapAttrs(this); - + ASTContext &Context = getASTContext(); - + // Handle the case when both decls have attrs. if (HasRHSAttr) { std::swap(Context.getDeclAttrs(this), Context.getDeclAttrs(RHS)); return; } - + // Otherwise, LHS has an attr and RHS doesn't. Context.getDeclAttrs(RHS) = Context.getDeclAttrs(this); Context.eraseDeclAttrs(this); @@ -300,7 +314,7 @@ void Decl::Destroy(ASTContext &C) { invalidateAttrs(); HasAttrs = false; } - + #if 0 // FIXME: Once ownership is fully understood, we can enable this code if (DeclContext *DC = dyn_cast(this)) @@ -309,15 +323,15 @@ void Decl::Destroy(ASTContext &C) { // Observe the unrolled recursion. By setting N->NextDeclInContext = 0x0 // within the loop, only the Destroy method for the first Decl // will deallocate all of the Decls in a chain. - + Decl* N = getNextDeclInContext(); - + while (N) { Decl* Tmp = N->getNextDeclInContext(); N->NextDeclInContext = 0; N->Destroy(C); N = Tmp; - } + } this->~Decl(); C.Deallocate((void *)this); @@ -377,8 +391,13 @@ SourceLocation Decl::getBodyRBrace() const { #ifndef NDEBUG void Decl::CheckAccessDeclContext() const { - assert((Access != AS_none || isa(this) || - !isa(getDeclContext())) && + // If the decl is the toplevel translation unit or if we're not in a + // record decl context, we don't need to check anything. + if (isa(this) || + !isa(getDeclContext())) + return; + + assert(Access != AS_none && "Access specifier is AS_none inside a record decl"); } @@ -413,6 +432,22 @@ void DeclContext::DestroyDecls(ASTContext &C) { (*D++)->Destroy(C); } +/// \brief Find the parent context of this context that will be +/// used for unqualified name lookup. +/// +/// Generally, the parent lookup context is the semantic context. However, for +/// a friend function the parent lookup context is the lexical context, which +/// is the class in which the friend is declared. +DeclContext *DeclContext::getLookupParent() { + // FIXME: Find a better way to identify friends + if (isa(this)) + if (getParent()->getLookupContext()->isFileContext() && + getLexicalParent()->getLookupContext()->isRecord()) + return getLexicalParent(); + + return getParent(); +} + bool DeclContext::isDependentContext() const { if (isFileContext()) return false; @@ -427,7 +462,7 @@ bool DeclContext::isDependentContext() const { if (const FunctionDecl *Function = dyn_cast(this)) if (Function->getDescribedFunctionTemplate()) return true; - + return getParent() && getParent()->isDependentContext(); } @@ -444,11 +479,21 @@ bool DeclContext::isTransparentContext() const { return false; } +bool DeclContext::Encloses(DeclContext *DC) { + if (getPrimaryContext() != this) + return getPrimaryContext()->Encloses(DC); + + for (; DC; DC = DC->getParent()) + if (DC->getPrimaryContext() == this) + return true; + return false; +} + DeclContext *DeclContext::getPrimaryContext() { switch (DeclKind) { case Decl::TranslationUnit: case Decl::LinkageSpec: - case Decl::Block: + case Decl::Block: // There is only one DeclContext for these entities. return this; @@ -473,8 +518,8 @@ DeclContext *DeclContext::getPrimaryContext() { if (DeclKind >= Decl::TagFirst && DeclKind <= Decl::TagLast) { // If this is a tag type that has a definition or is currently // being defined, that definition is our primary context. - if (const TagType *TagT =cast(this)->TypeForDecl->getAsTagType()) - if (TagT->isBeingDefined() || + if (const TagType *TagT =cast(this)->TypeForDecl->getAs()) + if (TagT->isBeingDefined() || (TagT->getDecl() && TagT->getDecl()->isDefinition())) return TagT->getDecl(); return this; @@ -499,13 +544,13 @@ DeclContext *DeclContext::getNextContext() { /// \brief Load the declarations within this lexical storage from an /// external source. -void +void DeclContext::LoadLexicalDeclsFromExternalStorage() const { ExternalASTSource *Source = getParentASTContext().getExternalSource(); assert(hasExternalLexicalStorage() && Source && "No external storage?"); llvm::SmallVector Decls; - if (Source->ReadDeclsLexicallyInContext(const_cast(this), + if (Source->ReadDeclsLexicallyInContext(const_cast(this), Decls)) return; @@ -537,7 +582,7 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const { LastDecl = PrevDecl; } -void +void DeclContext::LoadVisibleDeclsFromExternalStorage() const { DeclContext *This = const_cast(this); ExternalASTSource *Source = getParentASTContext().getExternalSource(); @@ -566,14 +611,14 @@ DeclContext::decl_iterator DeclContext::decls_begin() const { // FIXME: Check whether we need to load some declarations from // external storage. - return decl_iterator(FirstDecl); + return decl_iterator(FirstDecl); } DeclContext::decl_iterator DeclContext::decls_end() const { if (hasExternalLexicalStorage()) LoadLexicalDeclsFromExternalStorage(); - return decl_iterator(); + return decl_iterator(); } bool DeclContext::decls_empty() const { @@ -583,10 +628,10 @@ bool DeclContext::decls_empty() const { return !FirstDecl; } -void DeclContext::addDecl(Decl *D) { +void DeclContext::addHiddenDecl(Decl *D) { assert(D->getLexicalDeclContext() == this && "Decl inserted into wrong lexical context"); - assert(!D->getNextDeclInContext() && D != LastDecl && + assert(!D->getNextDeclInContext() && D != LastDecl && "Decl already inserted into a DeclContext"); if (FirstDecl) { @@ -595,6 +640,10 @@ void DeclContext::addDecl(Decl *D) { } else { FirstDecl = LastDecl = D; } +} + +void DeclContext::addDecl(Decl *D) { + addHiddenDecl(D); if (NamedDecl *ND = dyn_cast(D)) ND->getDeclContext()->makeDeclVisibleInContext(ND); @@ -605,12 +654,15 @@ void DeclContext::addDecl(Decl *D) { /// transparent contexts nested within it). void DeclContext::buildLookup(DeclContext *DCtx) { for (; DCtx; DCtx = DCtx->getNextContext()) { - for (decl_iterator D = DCtx->decls_begin(), - DEnd = DCtx->decls_end(); + for (decl_iterator D = DCtx->decls_begin(), + DEnd = DCtx->decls_end(); D != DEnd; ++D) { - // Insert this declaration into the lookup structure + // Insert this declaration into the lookup structure, but only + // if it's semantically in its decl context. During non-lazy + // lookup building, this is implicitly enforced by addDecl. if (NamedDecl *ND = dyn_cast(*D)) - makeDeclVisibleInContextImpl(ND); + if (D->getDeclContext() == DCtx) + makeDeclVisibleInContextImpl(ND); // If this declaration is itself a transparent declaration context, // add its members (recursively). @@ -621,7 +673,7 @@ void DeclContext::buildLookup(DeclContext *DCtx) { } } -DeclContext::lookup_result +DeclContext::lookup_result DeclContext::lookup(DeclarationName Name) { DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) @@ -647,7 +699,7 @@ DeclContext::lookup(DeclarationName Name) { return Pos->second.getLookupResult(getParentASTContext()); } -DeclContext::lookup_const_result +DeclContext::lookup_const_result DeclContext::lookup(DeclarationName Name) const { return const_cast(this)->lookup(Name); } @@ -668,7 +720,7 @@ DeclContext *DeclContext::getEnclosingNamespaceContext() { return Ctx->getPrimaryContext(); } -void DeclContext::makeDeclVisibleInContext(NamedDecl *D) { +void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) { // FIXME: This feels like a hack. Should DeclarationName support // template-ids, or is there a better way to keep specializations // from being visible? @@ -677,20 +729,20 @@ void DeclContext::makeDeclVisibleInContext(NamedDecl *D) { DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) { - PrimaryContext->makeDeclVisibleInContext(D); + PrimaryContext->makeDeclVisibleInContext(D, Recoverable); return; } // If we already have a lookup data structure, perform the insertion // into it. Otherwise, be lazy and don't build that structure until // someone asks for it. - if (LookupPtr) + if (LookupPtr || !Recoverable) makeDeclVisibleInContextImpl(D); // If we are a transparent context, insert into our parent context, // too. This operation is recursive. if (isTransparentContext()) - getParent()->makeDeclVisibleInContext(D); + getParent()->makeDeclVisibleInContext(D, Recoverable); } void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { @@ -720,14 +772,14 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { // one, just replace it and return. if (DeclNameEntries.HandleRedeclaration(getParentASTContext(), D)) return; - + // Put this declaration into the appropriate slot. DeclNameEntries.AddSubsequentDecl(D); } /// Returns iterator range [First, Last) of UsingDirectiveDecls stored within /// this context. -DeclContext::udir_iterator_range +DeclContext::udir_iterator_range DeclContext::getUsingDirectives() const { lookup_const_result Result = lookup(UsingDirectiveDecl::getName()); return udir_iterator_range(reinterpret_cast(Result.first), diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index b8b29528066d..457f4c85a047 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -17,6 +17,7 @@ #include "clang/AST/Expr.h" #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -24,22 +25,32 @@ using namespace clang; //===----------------------------------------------------------------------===// CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id) - : RecordDecl(K, TK, DC, L, Id), + SourceLocation L, IdentifierInfo *Id, + CXXRecordDecl *PrevDecl, + SourceLocation TKL) + : RecordDecl(K, TK, DC, L, Id, PrevDecl, TKL), UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false), - Aggregate(true), PlainOldData(true), Polymorphic(false), Abstract(false), - HasTrivialConstructor(true), HasTrivialDestructor(true), - Bases(0), NumBases(0), Conversions(DC, DeclarationName()), + 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), + Conversions(DC, DeclarationName()), + VisibleConversions(DC, DeclarationName()), TemplateOrInstantiation() { } CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + SourceLocation TKL, CXXRecordDecl* PrevDecl, bool DelayTypeCreation) { - CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id); + CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id, + PrevDecl, TKL); + + // FIXME: DelayTypeCreation seems like such a hack if (!DelayTypeCreation) - C.getTypeDeclType(R, PrevDecl); + C.getTypeDeclType(R, PrevDecl); return R; } @@ -48,14 +59,15 @@ CXXRecordDecl::~CXXRecordDecl() { void CXXRecordDecl::Destroy(ASTContext &C) { C.Deallocate(Bases); + C.Deallocate(VBases); this->RecordDecl::Destroy(C); } -void +void CXXRecordDecl::setBases(ASTContext &C, - CXXBaseSpecifier const * const *Bases, + CXXBaseSpecifier const * const *Bases, unsigned NumBases) { - // C++ [dcl.init.aggr]p1: + // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with [...] // no base classes [...]. Aggregate = false; @@ -63,39 +75,109 @@ CXXRecordDecl::setBases(ASTContext &C, if (this->Bases) C.Deallocate(this->Bases); + int vbaseCount = 0; + llvm::SmallVector UniqueVbases; + bool hasDirectVirtualBase = false; + this->Bases = new(C) CXXBaseSpecifier [NumBases]; this->NumBases = NumBases; - for (unsigned i = 0; i < NumBases; ++i) + for (unsigned i = 0; i < NumBases; ++i) { this->Bases[i] = *Bases[i]; + // Keep track of inherited vbases for this base class. + const CXXBaseSpecifier *Base = Bases[i]; + QualType BaseType = Base->getType(); + // Skip template types. + // FIXME. This means that this list must be rebuilt during template + // instantiation. + if (BaseType->isDependentType()) + continue; + CXXRecordDecl *BaseClassDecl + = cast(BaseType->getAs()->getDecl()); + if (Base->isVirtual()) + hasDirectVirtualBase = true; + for (CXXRecordDecl::base_class_iterator VBase = + BaseClassDecl->vbases_begin(), + E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) { + // Add this vbase to the array of vbases for current class if it is + // not already in the list. + // FIXME. Note that we do a linear search as number of such classes are + // very few. + int i; + for (i = 0; i < vbaseCount; ++i) + if (UniqueVbases[i]->getType() == VBase->getType()) + break; + if (i == vbaseCount) { + UniqueVbases.push_back(VBase); + ++vbaseCount; + } + } + } + if (hasDirectVirtualBase) { + // Iterate one more time through the direct bases and add the virtual + // base to the list of vritual bases for current class. + for (unsigned i = 0; i < NumBases; ++i) { + const CXXBaseSpecifier *VBase = Bases[i]; + if (!VBase->isVirtual()) + continue; + int j; + for (j = 0; j < vbaseCount; ++j) + if (UniqueVbases[j]->getType() == VBase->getType()) + break; + if (j == vbaseCount) { + UniqueVbases.push_back(VBase); + ++vbaseCount; + } + } + } + if (vbaseCount > 0) { + // build AST for inhireted, direct or indirect, virtual bases. + this->VBases = new (C) CXXBaseSpecifier [vbaseCount]; + this->NumVBases = vbaseCount; + for (int i = 0; i < vbaseCount; i++) { + QualType QT = UniqueVbases[i]->getType(); + CXXRecordDecl *VBaseClassDecl + = cast(QT->getAs()->getDecl()); + this->VBases[i] = + CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true, + VBaseClassDecl->getTagKind() == RecordDecl::TK_class, + UniqueVbases[i]->getAccessSpecifier(), QT); + } + } } bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const { - return getCopyConstructor(Context, QualType::Const) != 0; + return getCopyConstructor(Context, Qualifiers::Const) != 0; } -CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context, +CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context, unsigned TypeQuals) const{ QualType ClassType = Context.getTypeDeclType(const_cast(this)); - DeclarationName ConstructorName + DeclarationName ConstructorName = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ClassType)); unsigned FoundTQs; DeclContext::lookup_const_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = this->lookup(ConstructorName); Con != ConEnd; ++Con) { - if (cast(*Con)->isCopyConstructor(Context, + // C++ [class.copy]p2: + // A non-template constructor for class X is a copy constructor if [...] + if (isa(*Con)) + continue; + + if (cast(*Con)->isCopyConstructor(Context, FoundTQs)) { - if (((TypeQuals & QualType::Const) == (FoundTQs & QualType::Const)) || - (!(TypeQuals & QualType::Const) && (FoundTQs & QualType::Const))) + if (((TypeQuals & Qualifiers::Const) == (FoundTQs & Qualifiers::Const)) || + (!(TypeQuals & Qualifiers::Const) && (FoundTQs & Qualifiers::Const))) return cast(*Con); - + } } return 0; } -bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const { +bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context, + const CXXMethodDecl *& MD) const { QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( const_cast(this))); DeclarationName OpName =Context.DeclarationNames.getCXXOperatorName(OO_Equal); @@ -110,16 +192,17 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const { const CXXMethodDecl* Method = cast(*Op); if (Method->isStatic()) continue; - // TODO: Skip templates? Or is this implicitly done due to parameter types? + if (Method->getPrimaryTemplate()) + continue; const FunctionProtoType *FnType = - Method->getType()->getAsFunctionProtoType(); + Method->getType()->getAs(); assert(FnType && "Overloaded operator has no prototype."); // Don't assert on this; an invalid decl might have been left in the AST. if (FnType->getNumArgs() != 1 || FnType->isVariadic()) continue; bool AcceptsConst = true; QualType ArgType = FnType->getArgType(0); - if (const LValueReferenceType *Ref = ArgType->getAsLValueReferenceType()) { + if (const LValueReferenceType *Ref = ArgType->getAs()) { ArgType = Ref->getPointeeType(); // Is it a non-const lvalue reference? if (!ArgType.isConstQualified()) @@ -127,7 +210,7 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const { } if (Context.getCanonicalType(ArgType).getUnqualifiedType() != ClassType) continue; - + MD = Method; // We have a single argument of type cv X or cv X&, i.e. we've found the // copy assignment operator. Return whether it accepts const arguments. return AcceptsConst; @@ -138,13 +221,13 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const { } void -CXXRecordDecl::addedConstructor(ASTContext &Context, +CXXRecordDecl::addedConstructor(ASTContext &Context, CXXConstructorDecl *ConDecl) { assert(!ConDecl->isImplicit() && "addedConstructor - not for implicit decl"); // Note that we have a user-declared constructor. UserDeclaredConstructor = true; - // C++ [dcl.init.aggr]p1: + // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with no // user-declared constructors (12.1) [...]. Aggregate = false; @@ -156,22 +239,34 @@ CXXRecordDecl::addedConstructor(ASTContext &Context, // 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; - + // Note when we have a user-declared copy constructor, which will // suppress the implicit declaration of a copy constructor. - if (ConDecl->isCopyConstructor(Context)) + if (ConDecl->isCopyConstructor(Context)) { 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; + } } void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, CXXMethodDecl *OpDecl) { // We're interested specifically in copy assignment operators. - const FunctionProtoType *FnType = OpDecl->getType()->getAsFunctionProtoType(); + const FunctionProtoType *FnType = OpDecl->getType()->getAs(); assert(FnType && "Overloaded operator has no proto function type."); assert(FnType->getNumArgs() == 1 && !FnType->isVariadic()); + + // Copy assignment operators must be non-templates. + if (OpDecl->getPrimaryTemplate() || OpDecl->getDescribedFunctionTemplate()) + return; + QualType ArgType = FnType->getArgType(0); - if (const LValueReferenceType *Ref = ArgType->getAsLValueReferenceType()) + if (const LValueReferenceType *Ref = ArgType->getAs()) ArgType = Ref->getPointeeType(); ArgType = ArgType.getUnqualifiedType(); @@ -185,17 +280,212 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, // Suppress the implicit declaration of a copy constructor. 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; + // C++ [class]p4: // A POD-struct is an aggregate class that [...] has no user-defined copy // assignment operator [...]. PlainOldData = false; } -void CXXRecordDecl::addConversionFunction(ASTContext &Context, +void +CXXRecordDecl::collectConversionFunctions( + llvm::SmallPtrSet& ConversionsTypeSet) +{ + OverloadedFunctionDecl *TopConversions = getConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator + TFunc = TopConversions->function_begin(), + TFuncEnd = TopConversions->function_end(); + TFunc != TFuncEnd; ++TFunc) { + NamedDecl *TopConv = TFunc->get(); + CanQualType TConvType; + if (FunctionTemplateDecl *TConversionTemplate = + dyn_cast(TopConv)) + TConvType = + getASTContext().getCanonicalType( + TConversionTemplate->getTemplatedDecl()->getResultType()); + else + TConvType = + getASTContext().getCanonicalType( + cast(TopConv)->getConversionType()); + ConversionsTypeSet.insert(TConvType); + } +} + +/// getNestedVisibleConversionFunctions - imports unique conversion +/// functions from base classes into the visible conversion function +/// list of the class 'RD'. This is a private helper method. +/// TopConversionsTypeSet is the set of conversion functions of the class +/// we are interested in. HiddenConversionTypes is set of conversion functions +/// of the immediate derived class which hides the conversion functions found +/// in current class. +void +CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, + const llvm::SmallPtrSet &TopConversionsTypeSet, + const llvm::SmallPtrSet &HiddenConversionTypes) +{ + bool inTopClass = (RD == this); + QualType ClassType = getASTContext().getTypeDeclType(this); + if (const RecordType *Record = ClassType->getAs()) { + OverloadedFunctionDecl *Conversions + = cast(Record->getDecl())->getConversionFunctions(); + + for (OverloadedFunctionDecl::function_iterator + Func = Conversions->function_begin(), + FuncEnd = Conversions->function_end(); + Func != FuncEnd; ++Func) { + NamedDecl *Conv = Func->get(); + // Only those conversions not exact match of conversions in current + // class are candidateconversion routines. + CanQualType ConvType; + if (FunctionTemplateDecl *ConversionTemplate = + dyn_cast(Conv)) + ConvType = + getASTContext().getCanonicalType( + ConversionTemplate->getTemplatedDecl()->getResultType()); + else + ConvType = + getASTContext().getCanonicalType( + cast(Conv)->getConversionType()); + // We only add conversion functions found in the base class if they + // are not hidden by those found in HiddenConversionTypes which are + // the conversion functions in its derived class. + if (inTopClass || + (!TopConversionsTypeSet.count(ConvType) && + !HiddenConversionTypes.count(ConvType)) ) { + if (FunctionTemplateDecl *ConversionTemplate = + dyn_cast(Conv)) + RD->addVisibleConversionFunction(ConversionTemplate); + else + RD->addVisibleConversionFunction(cast(Conv)); + } + } + } + + if (getNumBases() == 0 && getNumVBases() == 0) + return; + + llvm::SmallPtrSet ConversionFunctions; + if (!inTopClass) + collectConversionFunctions(ConversionFunctions); + + for (CXXRecordDecl::base_class_iterator VBase = vbases_begin(), + E = vbases_end(); VBase != E; ++VBase) { + CXXRecordDecl *VBaseClassDecl + = cast(VBase->getType()->getAs()->getDecl()); + VBaseClassDecl->getNestedVisibleConversionFunctions(RD, + TopConversionsTypeSet, + (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); + + } + for (CXXRecordDecl::base_class_iterator Base = bases_begin(), + E = bases_end(); Base != E; ++Base) { + if (Base->isVirtual()) + continue; + CXXRecordDecl *BaseClassDecl + = cast(Base->getType()->getAs()->getDecl()); + + BaseClassDecl->getNestedVisibleConversionFunctions(RD, + TopConversionsTypeSet, + (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); + + } +} + +/// getVisibleConversionFunctions - get all conversion functions visible +/// in current class; including conversion function templates. +OverloadedFunctionDecl * +CXXRecordDecl::getVisibleConversionFunctions() { + // If root class, all conversions are visible. + if (bases_begin() == bases_end()) + return &Conversions; + // If visible conversion list is already evaluated, return it. + if (ComputedVisibleConversions) + return &VisibleConversions; + llvm::SmallPtrSet TopConversionsTypeSet; + collectConversionFunctions(TopConversionsTypeSet); + getNestedVisibleConversionFunctions(this, TopConversionsTypeSet, + TopConversionsTypeSet); + ComputedVisibleConversions = true; + return &VisibleConversions; +} + +void CXXRecordDecl::addVisibleConversionFunction( CXXConversionDecl *ConvDecl) { + assert(!ConvDecl->getDescribedFunctionTemplate() && + "Conversion function templates should cast to FunctionTemplateDecl."); + VisibleConversions.addOverload(ConvDecl); +} + +void CXXRecordDecl::addVisibleConversionFunction( + FunctionTemplateDecl *ConvDecl) { + assert(isa(ConvDecl->getTemplatedDecl()) && + "Function template is not a conversion function template"); + VisibleConversions.addOverload(ConvDecl); +} + +void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) { + assert(!ConvDecl->getDescribedFunctionTemplate() && + "Conversion function templates should cast to FunctionTemplateDecl."); Conversions.addOverload(ConvDecl); } +void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) { + assert(isa(ConvDecl->getTemplatedDecl()) && + "Function template is not a conversion function template"); + Conversions.addOverload(ConvDecl); +} + +CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const { + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) + return cast(MSInfo->getInstantiatedFrom()); + + return 0; +} + +MemberSpecializationInfo *CXXRecordDecl::getMemberSpecializationInfo() const { + return TemplateOrInstantiation.dyn_cast(); +} + +void +CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD, + TemplateSpecializationKind TSK) { + assert(TemplateOrInstantiation.isNull() && + "Previous template or instantiation?"); + assert(!isa(this)); + TemplateOrInstantiation + = new (getASTContext()) MemberSpecializationInfo(RD, TSK); +} + +TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast(this)) + return Spec->getSpecializationKind(); + + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) + return MSInfo->getTemplateSpecializationKind(); + + return TSK_Undeclared; +} + +void +CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast(this)) { + Spec->setSpecializationKind(TSK); + return; + } + + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) { + MSInfo->setTemplateSpecializationKind(TSK); + return; + } + + assert(false && "Not a class template or member class specialization"); +} CXXConstructorDecl * CXXRecordDecl::getDefaultConstructor(ASTContext &Context) { @@ -203,10 +493,14 @@ CXXRecordDecl::getDefaultConstructor(ASTContext &Context) { DeclarationName ConstructorName = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ClassType.getUnqualifiedType())); - + DeclContext::lookup_const_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = lookup(ConstructorName); Con != ConEnd; ++Con) { + // FIXME: In C++0x, a constructor template can be a default constructor. + if (isa(*Con)) + continue; + CXXConstructorDecl *Constructor = cast(*Con); if (Constructor->isDefaultConstructor()) return Constructor; @@ -217,66 +511,105 @@ CXXRecordDecl::getDefaultConstructor(ASTContext &Context) { const CXXDestructorDecl * CXXRecordDecl::getDestructor(ASTContext &Context) { QualType ClassType = Context.getTypeDeclType(this); - - DeclarationName Name - = Context.DeclarationNames.getCXXDestructorName(ClassType); + + DeclarationName Name + = Context.DeclarationNames.getCXXDestructorName( + Context.getCanonicalType(ClassType)); DeclContext::lookup_iterator I, E; - llvm::tie(I, E) = lookup(Name); + llvm::tie(I, E) = lookup(Name); assert(I != E && "Did not find a destructor!"); - + const CXXDestructorDecl *Dtor = cast(*I); assert(++I == E && "Found more than one destructor!"); - + return Dtor; } CXXMethodDecl * CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, bool isStatic, bool isInline) { - return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, isStatic, isInline); + QualType T, DeclaratorInfo *DInfo, + bool isStatic, bool isInline) { + return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, DInfo, + isStatic, isInline); } +bool CXXMethodDecl::isUsualDeallocationFunction() const { + if (getOverloadedOperator() != OO_Delete && + getOverloadedOperator() != OO_Array_Delete) + return false; + + // C++ [basic.stc.dynamic.deallocation]p2: + // If a class T has a member deallocation function named operator delete + // with exactly one parameter, then that function is a usual (non-placement) + // deallocation function. [...] + if (getNumParams() == 1) + return true; + + // C++ [basic.stc.dynamic.deallocation]p2: + // [...] If class T does not declare such an operator delete but does + // declare a member deallocation function named operator delete with + // exactly two parameters, the second of which has type std::size_t (18.1), + // then this function is a usual deallocation function. + ASTContext &Context = getASTContext(); + if (getNumParams() != 2 || + !Context.hasSameType(getParamDecl(1)->getType(), Context.getSizeType())) + return false; + + // This function is a usual deallocation function if there are no + // single-parameter deallocation functions of the same kind. + for (DeclContext::lookup_const_result R = getDeclContext()->lookup(getDeclName()); + R.first != R.second; ++R.first) { + if (const FunctionDecl *FD = dyn_cast(*R.first)) + if (FD->getNumParams() == 1) + return false; + } + + return true; +} -typedef llvm::DenseMap *> +typedef llvm::DenseMap *> OverriddenMethodsMapTy; +// FIXME: We hate static data. This doesn't survive PCH saving/loading, and +// the vtable building code uses it at CG time. static OverriddenMethodsMapTy *OverriddenMethods = 0; void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) { // FIXME: The CXXMethodDecl dtor needs to remove and free the entry. - + if (!OverriddenMethods) OverriddenMethods = new OverriddenMethodsMapTy(); - + std::vector *&Methods = (*OverriddenMethods)[this]; if (!Methods) Methods = new std::vector; - + Methods->push_back(MD); } CXXMethodDecl::method_iterator CXXMethodDecl::begin_overridden_methods() const { if (!OverriddenMethods) return 0; - + OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this); - if (it == OverriddenMethods->end()) + if (it == OverriddenMethods->end() || it->second->empty()) return 0; + return &(*it->second)[0]; } CXXMethodDecl::method_iterator CXXMethodDecl::end_overridden_methods() const { if (!OverriddenMethods) return 0; - + OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this); - if (it == OverriddenMethods->end()) + if (it == OverriddenMethods->end() || it->second->empty()) return 0; - return &(*it->second)[it->second->size()]; + return &(*it->second)[0] + it->second->size(); } QualType CXXMethodDecl::getThisType(ASTContext &C) const { @@ -292,40 +625,46 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const { if (ClassTemplateDecl *TD = getParent()->getDescribedClassTemplate()) ClassTy = TD->getInjectedClassNameType(C); else - ClassTy = C.getTagDeclType(const_cast(getParent())); - ClassTy = ClassTy.getWithAdditionalQualifiers(getTypeQualifiers()); - return C.getPointerType(ClassTy).withConst(); + ClassTy = C.getTagDeclType(getParent()); + ClassTy = C.getQualifiedType(ClassTy, + Qualifiers::fromCVRMask(getTypeQualifiers())); + return C.getPointerType(ClassTy); } CXXBaseOrMemberInitializer:: CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs, - SourceLocation L) - : Args(0), NumArgs(0), IdLoc(L) { + CXXConstructorDecl *C, + SourceLocation L, SourceLocation R) + : Args(0), NumArgs(0), CtorOrAnonUnion(), IdLoc(L), RParenLoc(R) { BaseOrMember = reinterpret_cast(BaseType.getTypePtr()); assert((BaseOrMember & 0x01) == 0 && "Invalid base class type pointer"); BaseOrMember |= 0x01; - + if (NumArgs > 0) { this->NumArgs = NumArgs; - this->Args = new Expr*[NumArgs]; + // FIXME. Allocation via Context + this->Args = new Stmt*[NumArgs]; for (unsigned Idx = 0; Idx < NumArgs; ++Idx) this->Args[Idx] = Args[Idx]; } + CtorOrAnonUnion = C; } CXXBaseOrMemberInitializer:: CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, - SourceLocation L) - : Args(0), NumArgs(0), IdLoc(L) { + CXXConstructorDecl *C, + SourceLocation L, SourceLocation R) + : Args(0), NumArgs(0), CtorOrAnonUnion(), IdLoc(L), RParenLoc(R) { BaseOrMember = reinterpret_cast(Member); - assert((BaseOrMember & 0x01) == 0 && "Invalid member pointer"); + assert((BaseOrMember & 0x01) == 0 && "Invalid member pointer"); if (NumArgs > 0) { this->NumArgs = NumArgs; - this->Args = new Expr*[NumArgs]; + this->Args = new Stmt*[NumArgs]; for (unsigned Idx = 0; Idx < NumArgs; ++Idx) this->Args[Idx] = Args[Idx]; } + CtorOrAnonUnion = C; } CXXBaseOrMemberInitializer::~CXXBaseOrMemberInitializer() { @@ -335,11 +674,12 @@ CXXBaseOrMemberInitializer::~CXXBaseOrMemberInitializer() { CXXConstructorDecl * CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, bool isExplicit, + QualType T, DeclaratorInfo *DInfo, + bool isExplicit, bool isInline, bool isImplicitlyDeclared) { assert(N.getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); - return new (C) CXXConstructorDecl(RD, L, N, T, isExplicit, isInline, + return new (C) CXXConstructorDecl(RD, L, N, T, DInfo, isExplicit, isInline, isImplicitlyDeclared); } @@ -348,11 +688,11 @@ bool CXXConstructorDecl::isDefaultConstructor() const { // A default constructor for a class X is a constructor of class // X that can be called without an argument. return (getNumParams() == 0) || - (getNumParams() > 0 && getParamDecl(0)->getDefaultArg() != 0); + (getNumParams() > 0 && getParamDecl(0)->hasDefaultArg()); } -bool -CXXConstructorDecl::isCopyConstructor(ASTContext &Context, +bool +CXXConstructorDecl::isCopyConstructor(ASTContext &Context, unsigned &TypeQuals) const { // C++ [class.copy]p2: // A non-template constructor for class X is a copy constructor @@ -360,42 +700,46 @@ CXXConstructorDecl::isCopyConstructor(ASTContext &Context, // const volatile X&, and either there are no other parameters // or else all other parameters have default arguments (8.3.6). if ((getNumParams() < 1) || - (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg())) + (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) || + (getPrimaryTemplate() != 0) || + (getDescribedFunctionTemplate() != 0)) return false; const ParmVarDecl *Param = getParamDecl(0); // Do we have a reference type? Rvalue references don't count. const LValueReferenceType *ParamRefType = - Param->getType()->getAsLValueReferenceType(); + Param->getType()->getAs(); if (!ParamRefType) return false; // Is it a reference to our class type? - QualType PointeeType + CanQualType PointeeType = Context.getCanonicalType(ParamRefType->getPointeeType()); - QualType ClassTy - = Context.getTagDeclType(const_cast(getParent())); + CanQualType ClassTy + = Context.getCanonicalType(Context.getTagDeclType(getParent())); if (PointeeType.getUnqualifiedType() != ClassTy) return false; + // FIXME: other qualifiers? + // We have a copy constructor. TypeQuals = PointeeType.getCVRQualifiers(); return true; } -bool CXXConstructorDecl::isConvertingConstructor() const { +bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const { // C++ [class.conv.ctor]p1: // A constructor declared without the function-specifier explicit // that can be called with a single parameter specifies a // conversion from the type of its first parameter to the type of // its class. Such a constructor is called a converting // constructor. - if (isExplicit()) + if (isExplicit() && !AllowExplicit) return false; - return (getNumParams() == 0 && - getType()->getAsFunctionProtoType()->isVariadic()) || + return (getNumParams() == 0 && + getType()->getAs()->isVariadic()) || (getNumParams() == 1) || (getNumParams() > 1 && getParamDecl(1)->hasDefaultArg()); } @@ -403,42 +747,34 @@ bool CXXConstructorDecl::isConvertingConstructor() const { CXXDestructorDecl * CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, bool isInline, + QualType T, bool isInline, bool isImplicitlyDeclared) { assert(N.getNameKind() == DeclarationName::CXXDestructorName && "Name must refer to a destructor"); - return new (C) CXXDestructorDecl(RD, L, N, T, isInline, + return new (C) CXXDestructorDecl(RD, L, N, T, isInline, isImplicitlyDeclared); } void -CXXConstructorDecl::setBaseOrMemberInitializers( - ASTContext &C, - CXXBaseOrMemberInitializer **Initializers, - unsigned NumInitializers) { - if (NumInitializers > 0) { - NumBaseOrMemberInitializers = NumInitializers; - BaseOrMemberInitializers = - new (C, 8) CXXBaseOrMemberInitializer*[NumInitializers]; - for (unsigned Idx = 0; Idx < NumInitializers; ++Idx) - BaseOrMemberInitializers[Idx] = Initializers[Idx]; - } +CXXDestructorDecl::Destroy(ASTContext& C) { + C.Deallocate(BaseOrMemberDestructions); + CXXMethodDecl::Destroy(C); } void CXXConstructorDecl::Destroy(ASTContext& C) { C.Deallocate(BaseOrMemberInitializers); - this->~CXXMethodDecl(); - C.Deallocate((void *)this); + CXXMethodDecl::Destroy(C); } CXXConversionDecl * CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, bool isInline, bool isExplicit) { + QualType T, DeclaratorInfo *DInfo, + bool isInline, bool isExplicit) { assert(N.getNameKind() == DeclarationName::CXXConversionFunctionName && "Name must refer to a conversion function"); - return new (C) CXXConversionDecl(RD, L, N, T, isInline, isExplicit); + return new (C) CXXConversionDecl(RD, L, N, T, DInfo, isInline, isExplicit); } OverloadedFunctionDecl * @@ -447,13 +783,78 @@ OverloadedFunctionDecl::Create(ASTContext &C, DeclContext *DC, return new (C) OverloadedFunctionDecl(DC, N); } +OverloadIterator::OverloadIterator(NamedDecl *ND) : D(0) { + if (!ND) + return; + + if (isa(ND) || isa(ND)) + D = ND; + else if (OverloadedFunctionDecl *Ovl = dyn_cast(ND)) { + if (Ovl->size() != 0) { + D = ND; + Iter = Ovl->function_begin(); + } + } +} + void OverloadedFunctionDecl::addOverload(AnyFunctionDecl F) { Functions.push_back(F); this->setLocation(F.get()->getLocation()); } +OverloadIterator::reference OverloadIterator::operator*() const { + if (FunctionDecl *FD = dyn_cast(D)) + return FD; + + if (FunctionTemplateDecl *FTD = dyn_cast(D)) + return FTD; + + assert(isa(D)); + return *Iter; +} + +OverloadIterator &OverloadIterator::operator++() { + if (isa(D) || isa(D)) { + D = 0; + return *this; + } + + if (++Iter == cast(D)->function_end()) + D = 0; + + return *this; +} + +bool OverloadIterator::Equals(const OverloadIterator &Other) const { + if (!D || !Other.D) + return D == Other.D; + + if (D != Other.D) + return false; + + return !isa(D) || Iter == Other.Iter; +} + +FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + FriendUnion Friend, + SourceLocation FriendL) { +#ifndef NDEBUG + if (Friend.is()) { + NamedDecl *D = Friend.get(); + assert(isa(D) || + isa(D) || + isa(D) || + isa(D)); + assert(D->getFriendObjectKind()); + } +#endif + + return new (C) FriendDecl(DC, L, Friend, FriendL); +} + LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, - DeclContext *DC, + DeclContext *DC, SourceLocation L, LanguageIDs Lang, bool Braces) { return new (C) LinkageSpecDecl(DC, L, Lang, Braces); @@ -467,19 +868,19 @@ UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation IdentLoc, NamespaceDecl *Used, DeclContext *CommonAncestor) { - return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierRange, + return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierRange, Qualifier, IdentLoc, Used, CommonAncestor); } -NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - SourceLocation AliasLoc, - IdentifierInfo *Alias, +NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + SourceLocation AliasLoc, + IdentifierInfo *Alias, SourceRange QualifierRange, NestedNameSpecifier *Qualifier, - SourceLocation IdentLoc, + SourceLocation IdentLoc, NamedDecl *Namespace) { - return new (C) NamespaceAliasDecl(DC, L, AliasLoc, Alias, QualifierRange, + return new (C) NamespaceAliasDecl(DC, L, AliasLoc, Alias, QualifierRange, Qualifier, IdentLoc, Namespace); } @@ -491,6 +892,17 @@ UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, TargetNNS, IsTypeNameArg); } +UnresolvedUsingDecl *UnresolvedUsingDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation UsingLoc, + SourceRange TargetNNR, + NestedNameSpecifier *TargetNNS, + SourceLocation TargetNameLoc, + DeclarationName TargetName, + bool IsTypeNameArg) { + return new (C) UnresolvedUsingDecl(DC, UsingLoc, TargetNNR, TargetNNS, + TargetNameLoc, TargetName, IsTypeNameArg); +} + StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, Expr *AssertExpr, StringLiteral *Message) { diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 54f13e14ba65..7f38ac1d9ad0 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -30,8 +30,8 @@ void ObjCListBase::Destroy(ASTContext &Ctx) { void ObjCListBase::set(void *const* InList, unsigned Elts, ASTContext &Ctx) { assert(List == 0 && "Elements already set!"); if (Elts == 0) return; // Setting to an empty list is a noop. - - + + List = new (Ctx) void*[Elts]; NumElts = Elts; memcpy(List, InList, sizeof(void*)*Elts); @@ -54,29 +54,9 @@ ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const { return 0; } -// Get the local instance method declared in this interface. -ObjCMethodDecl * -ObjCContainerDecl::getInstanceMethod(Selector Sel) const { - // Since instance & class methods can have the same name, the loop below - // ensures we get the correct method. - // - // @interface Whatever - // - (int) class_method; - // + (float) class_method; - // @end - // - lookup_const_iterator Meth, MethEnd; - for (llvm::tie(Meth, MethEnd) = lookup(Sel); Meth != MethEnd; ++Meth) { - ObjCMethodDecl *MD = dyn_cast(*Meth); - if (MD && MD->isInstanceMethod()) - return MD; - } - return 0; -} - -// Get the local class method declared in this interface. +// Get the local instance/class method declared in this interface. ObjCMethodDecl * -ObjCContainerDecl::getClassMethod(Selector Sel) const { +ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const { // Since instance & class methods can have the same name, the loop below // ensures we get the correct method. // @@ -88,7 +68,7 @@ ObjCContainerDecl::getClassMethod(Selector Sel) const { lookup_const_iterator Meth, MethEnd; for (llvm::tie(Meth, MethEnd) = lookup(Sel); Meth != MethEnd; ++Meth) { ObjCMethodDecl *MD = dyn_cast(*Meth); - if (MD && MD->isClassMethod()) + if (MD && MD->isInstanceMethod() == isInstance) return MD; } return 0; @@ -103,15 +83,15 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { for (prop_iterator I = prop_begin(), E = prop_end(); I != E; ++I) if ((*I)->getIdentifier() == PropertyId) return *I; - + const ObjCProtocolDecl *PID = dyn_cast(this); if (PID) { - for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(), + for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(), E = PID->protocol_end(); I != E; ++I) if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) return P; } - + if (const ObjCInterfaceDecl *OID = dyn_cast(this)) { // Look through categories. for (ObjCCategoryDecl *Category = OID->getCategoryList(); @@ -138,6 +118,45 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { return 0; } +void ObjCInterfaceDecl::mergeClassExtensionProtocolList( + ObjCProtocolDecl *const* ExtList, unsigned ExtNum, + ASTContext &C) +{ + if (ReferencedProtocols.empty()) { + ReferencedProtocols.set(ExtList, ExtNum, C); + return; + } + // Check for duplicate protocol in class's protocol list. + // This is (O)2. But it is extremely rare and number of protocols in + // class or its extension are very few. + llvm::SmallVector ProtocolRefs; + for (unsigned i = 0; i < ExtNum; i++) { + bool protocolExists = false; + ObjCProtocolDecl *ProtoInExtension = ExtList[i]; + for (protocol_iterator p = protocol_begin(), e = protocol_end(); + p != e; p++) { + ObjCProtocolDecl *Proto = (*p); + if (C.ProtocolCompatibleWithProtocol(ProtoInExtension, Proto)) { + protocolExists = true; + break; + } + } + // Do we want to warn on a protocol in extension class which + // already exist in the class? Probably not. + if (!protocolExists) + ProtocolRefs.push_back(ProtoInExtension); + } + if (ProtocolRefs.empty()) + return; + // Merge ProtocolRefs into class's protocol list; + for (protocol_iterator p = protocol_begin(), e = protocol_end(); + p != e; p++) + ProtocolRefs.push_back(*p); + ReferencedProtocols.Destroy(C); + unsigned NumProtoRefs = ProtocolRefs.size(); + setProtocolList((ObjCProtocolDecl**)&ProtocolRefs[0], NumProtoRefs, C); +} + ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID, ObjCInterfaceDecl *&clsDeclared) { ObjCInterfaceDecl* ClassDecl = this; @@ -165,72 +184,37 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass( return NULL; } -/// lookupInstanceMethod - This method returns an instance method by looking in +/// lookupMethod - This method returns an instance/class method by looking in /// the class, its categories, and its super classes (using a linear search). -ObjCMethodDecl *ObjCInterfaceDecl::lookupInstanceMethod(Selector Sel) { - ObjCInterfaceDecl* ClassDecl = this; +ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel, + bool isInstance) const { + const ObjCInterfaceDecl* ClassDecl = this; ObjCMethodDecl *MethodDecl = 0; - + while (ClassDecl != NULL) { - if ((MethodDecl = ClassDecl->getInstanceMethod(Sel))) + if ((MethodDecl = ClassDecl->getMethod(Sel, isInstance))) return MethodDecl; - + // Didn't find one yet - look through protocols. const ObjCList &Protocols = ClassDecl->getReferencedProtocols(); for (ObjCList::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) - if ((MethodDecl = (*I)->lookupInstanceMethod(Sel))) - return MethodDecl; - - // Didn't find one yet - now look through categories. - ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList(); - while (CatDecl) { - if ((MethodDecl = CatDecl->getInstanceMethod(Sel))) + if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance))) return MethodDecl; - - // Didn't find one yet - look through protocols. - const ObjCList &Protocols = - CatDecl->getReferencedProtocols(); - for (ObjCList::iterator I = Protocols.begin(), - E = Protocols.end(); I != E; ++I) - if ((MethodDecl = (*I)->lookupInstanceMethod(Sel))) - return MethodDecl; - CatDecl = CatDecl->getNextClassCategory(); - } - ClassDecl = ClassDecl->getSuperClass(); - } - return NULL; -} - -// lookupClassMethod - This method returns a class method by looking in the -// class, its categories, and its super classes (using a linear search). -ObjCMethodDecl *ObjCInterfaceDecl::lookupClassMethod(Selector Sel) { - ObjCInterfaceDecl* ClassDecl = this; - ObjCMethodDecl *MethodDecl = 0; - - while (ClassDecl != NULL) { - if ((MethodDecl = ClassDecl->getClassMethod(Sel))) - return MethodDecl; - // Didn't find one yet - look through protocols. - for (ObjCInterfaceDecl::protocol_iterator I = ClassDecl->protocol_begin(), - E = ClassDecl->protocol_end(); I != E; ++I) - if ((MethodDecl = (*I)->lookupClassMethod(Sel))) - return MethodDecl; - // Didn't find one yet - now look through categories. ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList(); while (CatDecl) { - if ((MethodDecl = CatDecl->getClassMethod(Sel))) + if ((MethodDecl = CatDecl->getMethod(Sel, isInstance))) return MethodDecl; - + // Didn't find one yet - look through protocols. const ObjCList &Protocols = CatDecl->getReferencedProtocols(); for (ObjCList::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) - if ((MethodDecl = (*I)->lookupClassMethod(Sel))) + if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance))) return MethodDecl; CatDecl = CatDecl->getNextClassCategory(); } @@ -239,14 +223,23 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupClassMethod(Selector Sel) { return NULL; } - +ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateInstanceMethod( + const Selector &Sel) { + ObjCMethodDecl *Method = 0; + if (ObjCImplementationDecl *ImpDecl = getImplementation()) + Method = ImpDecl->getInstanceMethod(Sel); + + if (!Method && getSuperClass()) + return getSuperClass()->lookupPrivateInstanceMethod(Sel); + return Method; +} //===----------------------------------------------------------------------===// // ObjCMethodDecl //===----------------------------------------------------------------------===// ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C, - SourceLocation beginLoc, + SourceLocation beginLoc, SourceLocation endLoc, Selector SelInfo, QualType T, DeclContext *contextDecl, @@ -256,14 +249,14 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C, ImplementationControl impControl) { return new (C) ObjCMethodDecl(beginLoc, endLoc, SelInfo, T, contextDecl, - isInstance, + isInstance, isVariadic, isSynthesized, impControl); } void ObjCMethodDecl::Destroy(ASTContext &C) { if (Body) Body->Destroy(C); if (SelfDecl) SelfDecl->Destroy(C); - + for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I) if (*I) (*I)->Destroy(C); @@ -272,7 +265,57 @@ void ObjCMethodDecl::Destroy(ASTContext &C) { Decl::Destroy(C); } -void ObjCMethodDecl::createImplicitParams(ASTContext &Context, +/// \brief A definition will return its interface declaration. +/// An interface declaration will return its definition. +/// Otherwise it will return itself. +ObjCMethodDecl *ObjCMethodDecl::getNextRedeclaration() { + ASTContext &Ctx = getASTContext(); + ObjCMethodDecl *Redecl = 0; + Decl *CtxD = cast(getDeclContext()); + + if (ObjCInterfaceDecl *IFD = dyn_cast(CtxD)) { + if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD)) + Redecl = ImplD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCCategoryDecl *CD = dyn_cast(CtxD)) { + if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD)) + Redecl = ImplD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCImplementationDecl *ImplD = + dyn_cast(CtxD)) { + if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) + Redecl = IFD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCCategoryImplDecl *CImplD = + dyn_cast(CtxD)) { + if (ObjCCategoryDecl *CatD = CImplD->getCategoryClass()) + Redecl = CatD->getMethod(getSelector(), isInstanceMethod()); + } + + return Redecl ? Redecl : this; +} + +ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() { + Decl *CtxD = cast(getDeclContext()); + + if (ObjCImplementationDecl *ImplD = dyn_cast(CtxD)) { + if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) + if (ObjCMethodDecl *MD = IFD->getMethod(getSelector(), + isInstanceMethod())) + return MD; + + } else if (ObjCCategoryImplDecl *CImplD = + dyn_cast(CtxD)) { + if (ObjCCategoryDecl *CatD = CImplD->getCategoryClass()) + if (ObjCMethodDecl *MD = CatD->getMethod(getSelector(), + isInstanceMethod())) + return MD; + } + + return this; +} + +void ObjCMethodDecl::createImplicitParams(ASTContext &Context, const ObjCInterfaceDecl *OID) { QualType selfTy; if (isInstanceMethod()) { @@ -280,49 +323,30 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context, // of the interface (which has been reported). Recover gracefully. if (OID) { selfTy = Context.getObjCInterfaceType(OID); - selfTy = Context.getPointerType(selfTy); + selfTy = Context.getObjCObjectPointerType(selfTy); } else { selfTy = Context.getObjCIdType(); } } else // we have a factory method. selfTy = Context.getObjCClassType(); - setSelfDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(), + setSelfDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(), &Context.Idents.get("self"), selfTy)); - setCmdDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(), - &Context.Idents.get("_cmd"), + setCmdDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(), + &Context.Idents.get("_cmd"), Context.getObjCSelType())); } - - -/// getSynthesizedMethodSize - Compute size of synthesized method name -/// as done be the rewrite. -/// -unsigned ObjCMethodDecl::getSynthesizedMethodSize() const { - // syntesized method name is a concatenation of -/+[class-name selector] - // Get length of this name. - unsigned length = 3; // _I_ or _C_ - length += getClassInterface()->getNameAsString().size()+1; // extra for _ - if (const ObjCCategoryImplDecl *CID = - dyn_cast(getDeclContext())) - length += CID->getNameAsString().size()+1; - length += getSelector().getAsString().size(); // selector name - return length; -} - ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() { if (ObjCInterfaceDecl *ID = dyn_cast(getDeclContext())) return ID; if (ObjCCategoryDecl *CD = dyn_cast(getDeclContext())) return CD->getClassInterface(); - if (ObjCImplementationDecl *IMD = - dyn_cast(getDeclContext())) + if (ObjCImplDecl *IMD = dyn_cast(getDeclContext())) return IMD->getClassInterface(); - if (ObjCCategoryImplDecl *CID = - dyn_cast(getDeclContext())) - return CID->getClassInterface(); + + assert(!isa(getDeclContext()) && "It's a protocol method"); assert(false && "unknown method context"); return 0; } @@ -334,7 +358,7 @@ ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() { ObjCInterfaceDecl *ObjCInterfaceDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation atLoc, - IdentifierInfo *Id, + IdentifierInfo *Id, SourceLocation ClassLoc, bool ForwardDecl, bool isInternal){ return new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc, ForwardDecl, @@ -350,19 +374,28 @@ ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id, ClassLoc(CLoc) { } -void ObjCInterfaceDecl::Destroy(ASTContext &C) { +void ObjCInterfaceDecl::Destroy(ASTContext &C) { for (ivar_iterator I = ivar_begin(), E = ivar_end(); I != E; ++I) if (*I) (*I)->Destroy(C); - + IVars.Destroy(C); // FIXME: CategoryList? - + // FIXME: Because there is no clear ownership // role between ObjCInterfaceDecls and the ObjCPropertyDecls that they // reference, we destroy ObjCPropertyDecls in ~TranslationUnit. Decl::Destroy(C); } +ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const { + return getASTContext().getObjCImplementation( + const_cast(this)); +} + +void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) { + getASTContext().setObjCImplementation(this, ImplD); +} + /// FindCategoryDeclaration - Finds category declaration in the list of /// categories for this class and returns it. Name of the category is passed @@ -377,14 +410,79 @@ ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const { return 0; } +ObjCMethodDecl * +ObjCInterfaceDecl::getCategoryInstanceMethod(Selector Sel) const { + for (ObjCCategoryDecl *Category = getCategoryList(); + Category; Category = Category->getNextClassCategory()) + if (ObjCCategoryImplDecl *Impl = Category->getImplementation()) + if (ObjCMethodDecl *MD = Impl->getInstanceMethod(Sel)) + return MD; + return 0; +} + +ObjCMethodDecl *ObjCInterfaceDecl::getCategoryClassMethod(Selector Sel) const { + for (ObjCCategoryDecl *Category = getCategoryList(); + Category; Category = Category->getNextClassCategory()) + if (ObjCCategoryImplDecl *Impl = Category->getImplementation()) + if (ObjCMethodDecl *MD = Impl->getClassMethod(Sel)) + return MD; + return 0; +} + +/// ClassImplementsProtocol - Checks that 'lProto' protocol +/// has been implemented in IDecl class, its super class or categories (if +/// lookupCategory is true). +bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto, + bool lookupCategory, + bool RHSIsQualifiedID) { + ObjCInterfaceDecl *IDecl = this; + // 1st, look up the class. + const ObjCList &Protocols = + IDecl->getReferencedProtocols(); + + for (ObjCList::iterator PI = Protocols.begin(), + E = Protocols.end(); PI != E; ++PI) { + if (getASTContext().ProtocolCompatibleWithProtocol(lProto, *PI)) + return true; + // This is dubious and is added to be compatible with gcc. In gcc, it is + // also allowed assigning a protocol-qualified 'id' type to a LHS object + // when protocol in qualified LHS is in list of protocols in the rhs 'id' + // object. This IMO, should be a bug. + // FIXME: Treat this as an extension, and flag this as an error when GCC + // extensions are not enabled. + if (RHSIsQualifiedID && + getASTContext().ProtocolCompatibleWithProtocol(*PI, lProto)) + return true; + } + + // 2nd, look up the category. + if (lookupCategory) + for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl; + CDecl = CDecl->getNextClassCategory()) { + for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(), + E = CDecl->protocol_end(); PI != E; ++PI) + if (getASTContext().ProtocolCompatibleWithProtocol(lProto, *PI)) + return true; + } + + // 3rd, look up the super class(s) + if (IDecl->getSuperClass()) + return + IDecl->getSuperClass()->ClassImplementsProtocol(lProto, lookupCategory, + RHSIsQualifiedID); + + return false; +} + //===----------------------------------------------------------------------===// // ObjCIvarDecl //===----------------------------------------------------------------------===// ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, AccessControl ac, Expr *BW) { - return new (C) ObjCIvarDecl(DC, L, Id, T, ac, BW); + QualType T, DeclaratorInfo *DInfo, + AccessControl ac, Expr *BW) { + return new (C) ObjCIvarDecl(DC, L, Id, T, DInfo, ac, BW); } @@ -401,7 +499,7 @@ ObjCAtDefsFieldDecl void ObjCAtDefsFieldDecl::Destroy(ASTContext& C) { this->~ObjCAtDefsFieldDecl(); - C.Deallocate((void *)this); + C.Deallocate((void *)this); } //===----------------------------------------------------------------------===// @@ -409,7 +507,7 @@ void ObjCAtDefsFieldDecl::Destroy(ASTContext& C) { //===----------------------------------------------------------------------===// ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, + SourceLocation L, IdentifierInfo *Id) { return new (C) ObjCProtocolDecl(DC, L, Id); } @@ -428,34 +526,21 @@ ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) { for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I) if ((PDecl = (*I)->lookupProtocolNamed(Name))) return PDecl; - - return NULL; -} -// lookupInstanceMethod - Lookup a instance method in the protocol and protocols -// it inherited. -ObjCMethodDecl *ObjCProtocolDecl::lookupInstanceMethod(Selector Sel) { - ObjCMethodDecl *MethodDecl = NULL; - - if ((MethodDecl = getInstanceMethod(Sel))) - return MethodDecl; - - for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I) - if ((MethodDecl = (*I)->lookupInstanceMethod(Sel))) - return MethodDecl; return NULL; } -// lookupInstanceMethod - Lookup a class method in the protocol and protocols +// lookupMethod - Lookup a instance/class method in the protocol and protocols // it inherited. -ObjCMethodDecl *ObjCProtocolDecl::lookupClassMethod(Selector Sel) { +ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel, + bool isInstance) const { ObjCMethodDecl *MethodDecl = NULL; - - if ((MethodDecl = getClassMethod(Sel))) + + if ((MethodDecl = getMethod(Sel, isInstance))) return MethodDecl; - + for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I) - if ((MethodDecl = (*I)->lookupClassMethod(Sel))) + if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance))) return MethodDecl; return NULL; } @@ -464,7 +549,7 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupClassMethod(Selector Sel) { // ObjCClassDecl //===----------------------------------------------------------------------===// -ObjCClassDecl::ObjCClassDecl(DeclContext *DC, SourceLocation L, +ObjCClassDecl::ObjCClassDecl(DeclContext *DC, SourceLocation L, ObjCInterfaceDecl *const *Elts, unsigned nElts, ASTContext &C) : Decl(ObjCClass, DC, L) { @@ -480,7 +565,7 @@ ObjCClassDecl *ObjCClassDecl::Create(ASTContext &C, DeclContext *DC, } void ObjCClassDecl::Destroy(ASTContext &C) { - + // FIXME: There is no clear ownership policy now for referenced // ObjCInterfaceDecls. Some of them can be forward declarations that // are never later defined (in which case the ObjCClassDecl owns them) @@ -488,7 +573,7 @@ void ObjCClassDecl::Destroy(ASTContext &C) { // we should have separate objects for forward declarations and definitions, // obviating this problem. Because of this situation, referenced // ObjCInterfaceDecls are destroyed in ~TranslationUnit. - + ForwardDecls.Destroy(C); Decl::Destroy(C); } @@ -501,14 +586,14 @@ ObjCForwardProtocolDecl:: ObjCForwardProtocolDecl(DeclContext *DC, SourceLocation L, ObjCProtocolDecl *const *Elts, unsigned nElts, ASTContext &C) -: Decl(ObjCForwardProtocol, DC, L) { +: Decl(ObjCForwardProtocol, DC, L) { ReferencedProtocols.set(Elts, nElts, C); } ObjCForwardProtocolDecl * ObjCForwardProtocolDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, + SourceLocation L, ObjCProtocolDecl *const *Elts, unsigned NumElts) { return new (C) ObjCForwardProtocolDecl(DC, L, Elts, NumElts, C); @@ -529,6 +614,16 @@ ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC, return new (C) ObjCCategoryDecl(DC, L, Id); } +ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const { + return getASTContext().getObjCImplementation( + const_cast(this)); +} + +void ObjCCategoryDecl::setImplementation(ObjCCategoryImplDecl *ImplD) { + getASTContext().setObjCImplementation(this, ImplD); +} + + //===----------------------------------------------------------------------===// // ObjCCategoryImplDecl //===----------------------------------------------------------------------===// @@ -540,6 +635,10 @@ ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC, return new (C) ObjCCategoryImplDecl(DC, L, Id, ClassInterface); } +ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryClass() const { + return getClassInterface()->FindCategoryDeclaration(getIdentifier()); +} + void ObjCImplDecl::addPropertyImplementation(ObjCPropertyImplDecl *property) { // FIXME: The context should be correct before we get here. @@ -547,6 +646,23 @@ void ObjCImplDecl::addPropertyImplementation(ObjCPropertyImplDecl *property) { addDecl(property); } +void ObjCImplDecl::setClassInterface(ObjCInterfaceDecl *IFace) { + ASTContext &Ctx = getASTContext(); + + if (ObjCImplementationDecl *ImplD + = dyn_cast_or_null(this)) { + if (IFace) + Ctx.setObjCImplementation(IFace, ImplD); + + } else if (ObjCCategoryImplDecl *ImplD = + dyn_cast_or_null(this)) { + if (ObjCCategoryDecl *CD = IFace->FindCategoryDeclaration(getIdentifier())) + Ctx.setObjCImplementation(CD, ImplD); + } + + ClassInterface = IFace; +} + /// FindPropertyImplIvarDecl - This method lookup the ivar in the list of /// properties implemented in this category @implementation block and returns /// the implemented property that uses it. @@ -576,56 +692,12 @@ FindPropertyImplDecl(IdentifierInfo *Id) const { return 0; } -// getInstanceMethod - This method returns an instance method by looking in -// the class implementation. Unlike interfaces, we don't look outside the -// implementation. -ObjCMethodDecl *ObjCImplDecl::getInstanceMethod(Selector Sel) const { - // Since instance & class methods can have the same name, the loop below - // ensures we get the correct method. - // - // @interface Whatever - // - (int) class_method; - // + (float) class_method; - // @end - // - lookup_const_iterator Meth, MethEnd; - for (llvm::tie(Meth, MethEnd) = lookup(Sel); - Meth != MethEnd; ++Meth) { - ObjCMethodDecl *MD = dyn_cast(*Meth); - if (MD && MD->isInstanceMethod()) - return MD; - } - return 0; -} - -// getClassMethod - This method returns an instance method by looking in -// the class implementation. Unlike interfaces, we don't look outside the -// implementation. -ObjCMethodDecl *ObjCImplDecl::getClassMethod(Selector Sel) const { - // Since instance & class methods can have the same name, the loop below - // ensures we get the correct method. - // - // @interface Whatever - // - (int) class_method; - // + (float) class_method; - // @end - // - lookup_const_iterator Meth, MethEnd; - for (llvm::tie(Meth, MethEnd) = lookup(Sel); - Meth != MethEnd; ++Meth) { - ObjCMethodDecl *MD = dyn_cast(*Meth); - if (MD && MD->isClassMethod()) - return MD; - } - return 0; -} - //===----------------------------------------------------------------------===// // ObjCImplementationDecl //===----------------------------------------------------------------------===// ObjCImplementationDecl * -ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC, +ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, ObjCInterfaceDecl *ClassInterface, ObjCInterfaceDecl *SuperDecl) { @@ -639,7 +711,7 @@ ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC, ObjCCompatibleAliasDecl * ObjCCompatibleAliasDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, + IdentifierInfo *Id, ObjCInterfaceDecl* AliasedClass) { return new (C) ObjCCompatibleAliasDecl(DC, L, Id, AliasedClass); } diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 12e89cd80d19..9d0d836cf62b 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -19,7 +19,6 @@ #include "clang/AST/Expr.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/Streams.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -34,8 +33,10 @@ namespace { llvm::raw_ostream& Indent(); void ProcessDeclGroup(llvm::SmallVectorImpl& Decls); + void Print(AccessSpecifier AS); + public: - DeclPrinter(llvm::raw_ostream &Out, ASTContext &Context, + DeclPrinter(llvm::raw_ostream &Out, ASTContext &Context, const PrintingPolicy &Policy, unsigned Indentation = 0) : Out(Out), Context(Context), Policy(Policy), Indentation(Indentation) { } @@ -71,17 +72,19 @@ namespace { void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); + void VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D); + void VisitUsingDecl(UsingDecl *D); }; } -void Decl::print(llvm::raw_ostream &Out, unsigned Indentation) { +void Decl::print(llvm::raw_ostream &Out, unsigned Indentation) const { print(Out, getASTContext().PrintingPolicy, Indentation); } void Decl::print(llvm::raw_ostream &Out, const PrintingPolicy &Policy, - unsigned Indentation) { + unsigned Indentation) const { DeclPrinter Printer(Out, getASTContext(), Policy, Indentation); - Printer.Visit(this); + Printer.Visit(const_cast(this)); } static QualType GetBaseType(QualType T) { @@ -90,13 +93,13 @@ static QualType GetBaseType(QualType T) { while (!BaseType->isSpecifierType()) { if (isa(BaseType)) break; - else if (const PointerType* PTy = BaseType->getAsPointerType()) + else if (const PointerType* PTy = BaseType->getAs()) BaseType = PTy->getPointeeType(); else if (const ArrayType* ATy = dyn_cast(BaseType)) BaseType = ATy->getElementType(); - else if (const FunctionType* FTy = BaseType->getAsFunctionType()) + else if (const FunctionType* FTy = BaseType->getAs()) BaseType = FTy->getResultType(); - else if (const VectorType *VTy = BaseType->getAsVectorType()) + else if (const VectorType *VTy = BaseType->getAs()) BaseType = VTy->getElementType(); else assert(0 && "Unknown declarator!"); @@ -146,7 +149,7 @@ void Decl::printGroup(Decl** Begin, unsigned NumDecls, } } -void Decl::dump() { +void Decl::dump() const { print(llvm::errs()); } @@ -164,6 +167,15 @@ void DeclPrinter::ProcessDeclGroup(llvm::SmallVectorImpl& Decls) { } +void DeclPrinter::Print(AccessSpecifier AS) { + switch(AS) { + case AS_none: assert(0 && "No access specifier!"); break; + case AS_public: Out << "public"; break; + case AS_protected: Out << "protected"; break; + case AS_private: Out << " private"; break; + } +} + //---------------------------------------------------------------------------- // Common C declarations //---------------------------------------------------------------------------- @@ -172,6 +184,9 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { if (Indent) Indentation += Policy.Indentation; + bool PrintAccess = isa(DC); + AccessSpecifier CurAS = AS_none; + llvm::SmallVector Decls; for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end(); D != DEnd; ++D) { @@ -185,6 +200,16 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { continue; } + if (PrintAccess) { + AccessSpecifier AS = D->getAccess(); + + if (AS != CurAS) { + Print(AS); + Out << ":\n"; + CurAS = AS; + } + } + // The next bits of code handles stuff like "struct {int x;} a,b"; we're // forced to merge the declarations because there's no other way to // refer to the struct in question. This limited merging is safe without @@ -215,16 +240,16 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { } this->Indent(); Visit(*D); - - // FIXME: Need to be able to tell the DeclPrinter when + + // FIXME: Need to be able to tell the DeclPrinter when const char *Terminator = 0; - if (isa(*D) && + if (isa(*D) && cast(*D)->isThisDeclarationADefinition()) Terminator = 0; else if (isa(*D) && cast(*D)->getBody()) Terminator = 0; else if (isa(*D) || isa(*D) || - isa(*D) || + isa(*D) || isa(*D) || isa(*D) || isa(*D) || @@ -274,7 +299,7 @@ void DeclPrinter::VisitRecordDecl(RecordDecl *D) { Out << " "; Out << D->getNameAsString(); } - + if (D->isDefinition()) { Out << " {\n"; VisitDeclContext(D); @@ -290,7 +315,7 @@ void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) { } } -void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { +void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (!Policy.SuppressSpecifiers) { switch (D->getStorageClass()) { case FunctionDecl::None: break; @@ -307,7 +332,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { SubPolicy.SuppressSpecifiers = false; std::string Proto = D->getNameAsString(); if (isa(D->getType().getTypePtr())) { - const FunctionType *AFT = D->getType()->getAsFunctionType(); + const FunctionType *AFT = D->getType()->getAs(); const FunctionProtoType *FT = 0; if (D->hasWrittenPrototype()) @@ -321,7 +346,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (i) POut << ", "; ParamPrinter.VisitParmVarDecl(D->getParamDecl(i)); } - + if (FT->isVariadic()) { if (D->getNumParams()) POut << ", "; POut << "..."; @@ -335,7 +360,81 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { } Proto += ")"; - AFT->getResultType().getAsStringInternal(Proto, Policy); + if (D->hasAttr()) + Proto += " __attribute((noreturn))"; + if (CXXConstructorDecl *CDecl = dyn_cast(D)) { + if (CDecl->getNumBaseOrMemberInitializers() > 0) { + Proto += " : "; + Out << Proto; + Proto.clear(); + for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(), + E = CDecl->init_end(); + B != E; ++B) { + 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 // FIXME. skip dependent types for now. + if (const RecordType *RT = + BMInitializer->getBaseClass()->getAs()) { + const CXXRecordDecl *BaseDecl = + cast(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 << ")"; + } else + Out << "()"; + } + } + } + else if (CXXDestructorDecl *DDecl = dyn_cast(D)) { + if (DDecl->getNumBaseOrMemberDestructions() > 0) { + // List order of base/member destruction for visualization purposes. + assert (D->isThisDeclarationADefinition() && "Destructor with dtor-list"); + Proto += "/* : "; + for (CXXDestructorDecl::destr_const_iterator *B = DDecl->destr_begin(), + *E = DDecl->destr_end(); + B != E; ++B) { + uintptr_t BaseOrMember = (*B); + if (B != DDecl->destr_begin()) + Proto += ", "; + + if (DDecl->isMemberToDestroy(BaseOrMember)) { + FieldDecl *FD = DDecl->getMemberToDestroy(BaseOrMember); + Proto += "~"; + Proto += FD->getNameAsString(); + } + else // FIXME. skip dependent types for now. + if (const RecordType *RT = + DDecl->getAnyBaseClassToDestroy(BaseOrMember) + ->getAs()) { + const CXXRecordDecl *BaseDecl = + cast(RT->getDecl()); + Proto += "~"; + Proto += BaseDecl->getNameAsString(); + } + Proto += "()"; + } + Proto += " */"; + } + } + else + AFT->getResultType().getAsStringInternal(Proto, Policy); } else { D->getType().getAsStringInternal(Proto, Policy); } @@ -423,7 +522,7 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { // C++ declarations //---------------------------------------------------------------------------- void DeclPrinter::VisitOverloadedFunctionDecl(OverloadedFunctionDecl *D) { - assert(false && + assert(false && "OverloadedFunctionDecls aren't really decls and are never printed"); } @@ -453,28 +552,23 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { Out << " "; Out << D->getNameAsString(); } - + if (D->isDefinition()) { // Print the base classes if (D->getNumBases()) { Out << " : "; - for(CXXRecordDecl::base_class_iterator Base = D->bases_begin(), - BaseEnd = D->bases_end(); - Base != BaseEnd; ++Base) { + for (CXXRecordDecl::base_class_iterator Base = D->bases_begin(), + BaseEnd = D->bases_end(); Base != BaseEnd; ++Base) { if (Base != D->bases_begin()) Out << ", "; if (Base->isVirtual()) Out << "virtual "; - switch(Base->getAccessSpecifierAsWritten()) { - case AS_none: break; - case AS_public: Out << "public "; break; - case AS_protected: Out << "protected "; break; - case AS_private: Out << " private "; break; - } - - Out << Base->getType().getAsString(Policy); + AccessSpecifier AS = Base->getAccessSpecifierAsWritten(); + if (AS != AS_none) + Print(AS); + Out << " " << Base->getType().getAsString(Policy); } } @@ -483,7 +577,7 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { Out << " {\n"; VisitDeclContext(D); Indent() << "}"; - } + } } void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { @@ -507,17 +601,17 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { Out << "template <"; - + TemplateParameterList *Params = D->getTemplateParameters(); for (unsigned i = 0, e = Params->size(); i != e; ++i) { if (i != 0) Out << ", "; - + const Decl *Param = Params->getParam(i); - if (const TemplateTypeParmDecl *TTP = + if (const TemplateTypeParmDecl *TTP = dyn_cast(Param)) { - - QualType ParamType = + + QualType ParamType = Context.getTypeDeclType(const_cast(TTP)); if (TTP->wasDeclaredWithTypename()) @@ -527,14 +621,14 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { if (TTP->isParameterPack()) Out << "... "; - + Out << ParamType.getAsString(Policy); if (TTP->hasDefaultArgument()) { Out << " = "; Out << TTP->getDefaultArgument().getAsString(Policy); }; - } else if (const NonTypeTemplateParmDecl *NTTP = + } else if (const NonTypeTemplateParmDecl *NTTP = dyn_cast(Param)) { Out << NTTP->getType().getAsString(Policy); @@ -542,15 +636,15 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { Out << ' '; Out << Name->getName(); } - + if (NTTP->hasDefaultArgument()) { Out << " = "; - NTTP->getDefaultArgument()->printPretty(Out, Context, 0, Policy, + NTTP->getDefaultArgument()->printPretty(Out, Context, 0, Policy, Indentation); } } } - + Out << "> "; Visit(D->getTemplatedDecl()); @@ -572,29 +666,29 @@ void DeclPrinter::VisitObjCClassDecl(ObjCClassDecl *D) { void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { if (OMD->isInstanceMethod()) Out << "- "; - else + else Out << "+ "; if (!OMD->getResultType().isNull()) Out << '(' << OMD->getResultType().getAsString(Policy) << ")"; - + std::string name = OMD->getSelector().getAsString(); std::string::size_type pos, lastPos = 0; for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), E = OMD->param_end(); PI != E; ++PI) { - // FIXME: selector is missing here! + // FIXME: selector is missing here! pos = name.find_first_of(":", lastPos); Out << " " << name.substr(lastPos, pos - lastPos); Out << ":(" << (*PI)->getType().getAsString(Policy) << ")" - << (*PI)->getNameAsString(); + << (*PI)->getNameAsString(); lastPos = pos + 1; } - + if (OMD->param_begin() == OMD->param_end()) Out << " " << name; - + if (OMD->isVariadic()) Out << ", ..."; - + if (OMD->getBody()) { Out << ' '; OMD->getBody()->printPretty(Out, Context, 0, Policy); @@ -623,7 +717,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { Out << "@interface " << I << " : " << SID->getNameAsString(); else Out << "@interface " << I; - + // Protocols? const ObjCList &Protocols = OID->getReferencedProtocols(); if (!Protocols.empty()) { @@ -631,22 +725,22 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { E = Protocols.end(); I != E; ++I) Out << (I == Protocols.begin() ? '<' : ',') << (*I)->getNameAsString(); } - + if (!Protocols.empty()) Out << "> "; - + if (OID->ivar_size() > 0) { Out << "{\n"; Indentation += Policy.Indentation; for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(), E = OID->ivar_end(); I != E; ++I) { Indent() << (*I)->getType().getAsString(Policy) - << ' ' << (*I)->getNameAsString() << ";\n"; + << ' ' << (*I)->getNameAsString() << ";\n"; } Indentation -= Policy.Indentation; Out << "}\n"; } - + VisitDeclContext(OID, false); Out << "@end"; // FIXME: implement the rest... @@ -654,7 +748,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { void DeclPrinter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { Out << "@protocol "; - for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(), + for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) { if (I != D->protocol_begin()) Out << ", "; @@ -671,7 +765,7 @@ void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { Out << "@implementation " << PID->getClassInterface()->getNameAsString() - << '(' << PID->getNameAsString() << ")\n"; + << '(' << PID->getNameAsString() << ")\n"; VisitDeclContext(PID, false); Out << "@end"; @@ -679,18 +773,18 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { } void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { - Out << "@interface " + Out << "@interface " << PID->getClassInterface()->getNameAsString() << '(' << PID->getNameAsString() << ")\n"; VisitDeclContext(PID, false); Out << "@end"; - + // FIXME: implement the rest... } void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) { - Out << "@compatibility_alias " << AID->getNameAsString() - << ' ' << AID->getClassInterface()->getNameAsString() << ";\n"; + Out << "@compatibility_alias " << AID->getNameAsString() + << ' ' << AID->getClassInterface()->getNameAsString() << ";\n"; } /// PrintObjCPropertyDecl - print a property declaration. @@ -700,17 +794,17 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { Out << "@required\n"; else if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Optional) Out << "@optional\n"; - + Out << "@property"; if (PDecl->getPropertyAttributes() != ObjCPropertyDecl::OBJC_PR_noattr) { bool first = true; Out << " ("; - if (PDecl->getPropertyAttributes() & + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly) { Out << (first ? ' ' : ',') << "readonly"; first = false; } - + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) { Out << (first ? ' ' : ',') << "getter = " << PDecl->getGetterName().getAsString(); @@ -721,29 +815,29 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { << PDecl->getSetterName().getAsString(); first = false; } - + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign) { Out << (first ? ' ' : ',') << "assign"; first = false; } - + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) { Out << (first ? ' ' : ',') << "readwrite"; first = false; } - + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain) { Out << (first ? ' ' : ',') << "retain"; first = false; } - + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) { Out << (first ? ' ' : ',') << "copy"; first = false; } - - if (PDecl->getPropertyAttributes() & + + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) { Out << (first ? ' ' : ',') << "nonatomic"; first = false; @@ -763,3 +857,15 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { if (PID->getPropertyIvarDecl()) Out << "=" << PID->getPropertyIvarDecl()->getNameAsString(); } + +void DeclPrinter::VisitUsingDecl(UsingDecl *D) { + Out << "using "; + D->getTargetNestedNameDecl()->print(Out, Policy); + Out << D->getTargetDecl()->getNameAsString(); +} + +void DeclPrinter::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) { + Out << "using "; + D->getTargetNestedNameSpecifier()->print(Out, Policy); + Out << D->getTargetName().getAsString(); +} diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index f1bd1b67d21e..7836b3f827ce 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -25,7 +25,7 @@ using namespace clang; TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc, - Decl **Params, unsigned NumParams, + NamedDecl **Params, unsigned NumParams, SourceLocation RAngleLoc) : TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc), NumParams(NumParams) { @@ -35,31 +35,32 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc, TemplateParameterList * TemplateParameterList::Create(ASTContext &C, SourceLocation TemplateLoc, - SourceLocation LAngleLoc, Decl **Params, + SourceLocation LAngleLoc, NamedDecl **Params, unsigned NumParams, SourceLocation RAngleLoc) { - unsigned Size = sizeof(TemplateParameterList) + sizeof(Decl *) * NumParams; + unsigned Size = sizeof(TemplateParameterList) + + sizeof(NamedDecl *) * NumParams; unsigned Align = llvm::AlignOf::Alignment; void *Mem = C.Allocate(Size, Align); - return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params, + return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params, NumParams, RAngleLoc); } unsigned TemplateParameterList::getMinRequiredArguments() const { unsigned NumRequiredArgs = size(); - iterator Param = const_cast(this)->end(), + iterator Param = const_cast(this)->end(), ParamBegin = const_cast(this)->begin(); while (Param != ParamBegin) { --Param; - + if (!(*Param)->isTemplateParameterPack() && - !(isa(*Param) && + !(isa(*Param) && cast(*Param)->hasDefaultArgument()) && !(isa(*Param) && cast(*Param)->hasDefaultArgument()) && !(isa(*Param) && cast(*Param)->hasDefaultArgument())) break; - + --NumRequiredArgs; } @@ -94,16 +95,23 @@ void FunctionTemplateDecl::Destroy(ASTContext &C) { Spec != SpecEnd; ++Spec) C.Deallocate(&*Spec); } - + Decl::Destroy(C); } +FunctionTemplateDecl *FunctionTemplateDecl::getCanonicalDecl() { + FunctionTemplateDecl *FunTmpl = this; + while (FunTmpl->getPreviousDeclaration()) + FunTmpl = FunTmpl->getPreviousDeclaration(); + return FunTmpl; +} + FunctionTemplateDecl::Common *FunctionTemplateDecl::getCommonPtr() { // Find the first declaration of this function template. FunctionTemplateDecl *First = this; while (First->getPreviousDeclaration()) First = First->getPreviousDeclaration(); - + if (First->CommonOrPrev.isNull()) { // FIXME: Allocate with the ASTContext First->CommonOrPrev = new Common; @@ -115,6 +123,13 @@ FunctionTemplateDecl::Common *FunctionTemplateDecl::getCommonPtr() { // ClassTemplateDecl Implementation //===----------------------------------------------------------------------===// +ClassTemplateDecl *ClassTemplateDecl::getCanonicalDecl() { + ClassTemplateDecl *Template = this; + while (Template->getPreviousDeclaration()) + Template = Template->getPreviousDeclaration(); + return Template; +} + ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, @@ -128,7 +143,7 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, else CommonPtr = new (C) Common; - return new (C) ClassTemplateDecl(DC, L, Name, Params, Decl, PrevDecl, + return new (C) ClassTemplateDecl(DC, L, Name, Params, Decl, PrevDecl, CommonPtr); } @@ -147,6 +162,21 @@ void ClassTemplateDecl::Destroy(ASTContext& C) { C.Deallocate((void*)this); } +ClassTemplatePartialSpecializationDecl * +ClassTemplateDecl::findPartialSpecialization(QualType T) { + ASTContext &Context = getASTContext(); + typedef llvm::FoldingSet::iterator + partial_spec_iterator; + for (partial_spec_iterator P = getPartialSpecializations().begin(), + PEnd = getPartialSpecializations().end(); + P != PEnd; ++P) { + if (Context.hasSameType(Context.getTypeDeclType(&*P), T)) + return &*P; + } + + return 0; +} + QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { if (!CommonPtr->InjectedClassNameType.isNull()) return CommonPtr->InjectedClassNameType; @@ -157,52 +187,32 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { // better to fix that redundancy. TemplateParameterList *Params = getTemplateParameters(); - llvm::SmallVector TemplateArgs; - llvm::SmallVector CanonTemplateArgs; TemplateArgs.reserve(Params->size()); - CanonTemplateArgs.reserve(Params->size()); - - for (TemplateParameterList::iterator - Param = Params->begin(), ParamEnd = Params->end(); + for (TemplateParameterList::iterator Param = Params->begin(), + ParamEnd = Params->end(); Param != ParamEnd; ++Param) { if (isa(*Param)) { QualType ParamType = Context.getTypeDeclType(cast(*Param)); - TemplateArgs.push_back(TemplateArgument((*Param)->getLocation(), + TemplateArgs.push_back(TemplateArgument((*Param)->getLocation(), ParamType)); - CanonTemplateArgs.push_back( - TemplateArgument((*Param)->getLocation(), - Context.getCanonicalType(ParamType))); - } else if (NonTypeTemplateParmDecl *NTTP = + } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast(*Param)) { - // FIXME: Build canonical expression, too! Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(), NTTP->getLocation(), NTTP->getType()->isDependentType(), /*Value-dependent=*/true); TemplateArgs.push_back(TemplateArgument(E)); - CanonTemplateArgs.push_back(TemplateArgument(E)); - } else { + } else { TemplateTemplateParmDecl *TTP = cast(*Param); TemplateArgs.push_back(TemplateArgument(TTP->getLocation(), TTP)); - CanonTemplateArgs.push_back(TemplateArgument(TTP->getLocation(), - Context.getCanonicalDecl(TTP))); } } - // FIXME: I should really move the "build-the-canonical-type" logic - // into ASTContext::getTemplateSpecializationType. - TemplateName Name = TemplateName(this); - QualType CanonType = Context.getTemplateSpecializationType( - Context.getCanonicalTemplateName(Name), - &CanonTemplateArgs[0], - CanonTemplateArgs.size()); - CommonPtr->InjectedClassNameType - = Context.getTemplateSpecializationType(Name, + = Context.getTemplateSpecializationType(TemplateName(this), &TemplateArgs[0], - TemplateArgs.size(), - CanonType); + TemplateArgs.size()); return CommonPtr->InjectedClassNameType; } @@ -227,14 +237,13 @@ NonTypeTemplateParmDecl * NonTypeTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, IdentifierInfo *Id, QualType T, - SourceLocation TypeSpecStartLoc) { - return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, - TypeSpecStartLoc); + DeclaratorInfo *DInfo) { + return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, DInfo); } SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const { return DefaultArgument? DefaultArgument->getSourceRange().getBegin() - : SourceLocation(); + : SourceLocation(); } //===----------------------------------------------------------------------===// @@ -251,7 +260,7 @@ TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const { return DefaultArgument? DefaultArgument->getSourceRange().getBegin() - : SourceLocation(); + : SourceLocation(); } //===----------------------------------------------------------------------===// @@ -264,10 +273,10 @@ TemplateArgument::TemplateArgument(Expr *E) : Kind(Expression) { } /// \brief Construct a template argument pack. -void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs, +void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs, bool CopyArgs) { assert(isNull() && "Must call setArgumentPack on a null argument"); - + Kind = Pack; Args.NumArgs = NumArgs; Args.CopyArgs = CopyArgs; @@ -275,7 +284,8 @@ void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs, Args.Args = args; return; } - + + // FIXME: Allocate in ASTContext Args.Args = new TemplateArgument[NumArgs]; for (unsigned I = 0; I != Args.NumArgs; ++I) Args.Args[I] = args[I]; @@ -292,21 +302,21 @@ void TemplateArgumentListBuilder::Append(const TemplateArgument& Arg) { assert(Arg.getAsType()->isCanonical() && "Type must be canonical!"); break; } - + assert(NumFlatArgs < MaxFlatArgs && "Argument list builder is full!"); - assert(!StructuredArgs && + assert(!StructuredArgs && "Can't append arguments when an argument pack has been added!"); - + if (!FlatArgs) FlatArgs = new TemplateArgument[MaxFlatArgs]; - + FlatArgs[NumFlatArgs++] = Arg; } void TemplateArgumentListBuilder::BeginPack() { assert(!AddingToPack && "Already adding to pack!"); assert(!StructuredArgs && "Argument list already contains a pack!"); - + AddingToPack = true; PackBeginIndex = NumFlatArgs; } @@ -314,24 +324,24 @@ void TemplateArgumentListBuilder::BeginPack() { void TemplateArgumentListBuilder::EndPack() { assert(AddingToPack && "Not adding to pack!"); assert(!StructuredArgs && "Argument list already contains a pack!"); - + AddingToPack = false; StructuredArgs = new TemplateArgument[MaxStructuredArgs]; - + // First copy the flat entries over to the list (if any) for (unsigned I = 0; I != PackBeginIndex; ++I) { NumStructuredArgs++; StructuredArgs[I] = FlatArgs[I]; } - + // Next, set the pack. TemplateArgument *PackArgs = 0; unsigned NumPackArgs = NumFlatArgs - PackBeginIndex; if (NumPackArgs) PackArgs = &FlatArgs[PackBeginIndex]; - - StructuredArgs[NumStructuredArgs++].setArgumentPack(PackArgs, NumPackArgs, + + StructuredArgs[NumStructuredArgs++].setArgumentPack(PackArgs, NumPackArgs, /*CopyArgs=*/false); } @@ -350,19 +360,25 @@ void TemplateArgumentListBuilder::ReleaseArgs() { TemplateArgumentList::TemplateArgumentList(ASTContext &Context, TemplateArgumentListBuilder &Builder, bool TakeArgs) - : FlatArguments(Builder.getFlatArguments(), TakeArgs), - NumFlatArguments(Builder.flatSize()), + : FlatArguments(Builder.getFlatArguments(), TakeArgs), + NumFlatArguments(Builder.flatSize()), StructuredArguments(Builder.getStructuredArguments(), TakeArgs), NumStructuredArguments(Builder.structuredSize()) { - + if (!TakeArgs) return; - + if (Builder.getStructuredArguments() == Builder.getFlatArguments()) StructuredArguments.setInt(0); Builder.ReleaseArgs(); } +TemplateArgumentList::TemplateArgumentList(const TemplateArgumentList &Other) + : FlatArguments(Other.FlatArguments.getPointer(), 1), + NumFlatArguments(Other.flat_size()), + StructuredArguments(Other.StructuredArguments.getPointer(), 1), + NumStructuredArguments(Other.NumStructuredArguments) { } + TemplateArgumentList::~TemplateArgumentList() { // FIXME: Deallocate template arguments } @@ -374,34 +390,66 @@ ClassTemplateSpecializationDecl:: ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, - TemplateArgumentListBuilder &Builder) - : CXXRecordDecl(DK, - SpecializedTemplate->getTemplatedDecl()->getTagKind(), + TemplateArgumentListBuilder &Builder, + ClassTemplateSpecializationDecl *PrevDecl) + : CXXRecordDecl(DK, + SpecializedTemplate->getTemplatedDecl()->getTagKind(), DC, L, // FIXME: Should we use DeclarationName for the name of // class template specializations? - SpecializedTemplate->getIdentifier()), + SpecializedTemplate->getIdentifier(), + PrevDecl), SpecializedTemplate(SpecializedTemplate), TemplateArgs(Context, Builder, /*TakeArgs=*/true), SpecializationKind(TSK_Undeclared) { } - + ClassTemplateSpecializationDecl * -ClassTemplateSpecializationDecl::Create(ASTContext &Context, +ClassTemplateSpecializationDecl::Create(ASTContext &Context, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, ClassTemplateSpecializationDecl *PrevDecl) { ClassTemplateSpecializationDecl *Result - = new (Context)ClassTemplateSpecializationDecl(Context, + = new (Context)ClassTemplateSpecializationDecl(Context, ClassTemplateSpecialization, - DC, L, + DC, L, SpecializedTemplate, - Builder); + Builder, + PrevDecl); Context.getTypeDeclType(Result, PrevDecl); return Result; } +void ClassTemplateSpecializationDecl::Destroy(ASTContext &C) { + if (SpecializedPartialSpecialization *PartialSpec + = SpecializedTemplate.dyn_cast()) + C.Deallocate(PartialSpec); + + CXXRecordDecl::Destroy(C); +} + +void +ClassTemplateSpecializationDecl::getNameForDiagnostic(std::string &S, + const PrintingPolicy &Policy, + bool Qualified) const { + NamedDecl::getNameForDiagnostic(S, Policy, Qualified); + + const TemplateArgumentList &TemplateArgs = getTemplateArgs(); + S += TemplateSpecializationType::PrintTemplateArgumentList( + TemplateArgs.getFlatArgumentList(), + TemplateArgs.flat_size(), + Policy); +} + +ClassTemplateDecl * +ClassTemplateSpecializationDecl::getSpecializedTemplate() const { + if (SpecializedPartialSpecialization *PartialSpec + = SpecializedTemplate.dyn_cast()) + return PartialSpec->PartialSpecialization->getSpecializedTemplate(); + return SpecializedTemplate.get(); +} + //===----------------------------------------------------------------------===// // ClassTemplatePartialSpecializationDecl Implementation //===----------------------------------------------------------------------===// @@ -413,11 +461,27 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L, TemplateArgumentListBuilder &Builder, ClassTemplatePartialSpecializationDecl *PrevDecl) { ClassTemplatePartialSpecializationDecl *Result - = new (Context)ClassTemplatePartialSpecializationDecl(Context, + = new (Context)ClassTemplatePartialSpecializationDecl(Context, DC, L, Params, SpecializedTemplate, - Builder); + Builder, PrevDecl); Result->setSpecializationKind(TSK_ExplicitSpecialization); Context.getTypeDeclType(Result, PrevDecl); return Result; } + +//===----------------------------------------------------------------------===// +// FriendTemplateDecl Implementation +//===----------------------------------------------------------------------===// + +FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context, + DeclContext *DC, + SourceLocation L, + unsigned NParams, + TemplateParameterList **Params, + FriendUnion Friend, + SourceLocation FLoc) { + FriendTemplateDecl *Result + = new (Context) FriendTemplateDecl(DC, L, NParams, Params, Friend, FLoc); + return Result; +} diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index a17abde77730..101ddd250933 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -23,7 +23,7 @@ namespace clang { /// CXXSpecialName - Records the type associated with one of the /// "special" kinds of declaration names in C++, e.g., constructors, /// destructors, and conversion functions. -class CXXSpecialName +class CXXSpecialName : public DeclarationNameExtra, public llvm::FoldingSetNode { public: /// Type - The type associated with this declaration name. @@ -40,7 +40,7 @@ public: }; /// CXXOperatorIdName - Contains extra information for the name of an -/// overloaded operator in C++, such as "operator+. +/// overloaded operator in C++, such as "operator+. class CXXOperatorIdName : public DeclarationNameExtra { public: /// FETokenInfo - Extra information associated with this operator @@ -93,13 +93,13 @@ DeclarationName::NameKind DeclarationName::getNameKind() const { case StoredDeclarationNameExtra: switch (getExtra()->ExtraKindOrNumArgs) { - case DeclarationNameExtra::CXXConstructor: + case DeclarationNameExtra::CXXConstructor: return CXXConstructorName; - case DeclarationNameExtra::CXXDestructor: + case DeclarationNameExtra::CXXDestructor: return CXXDestructorName; - case DeclarationNameExtra::CXXConversionFunction: + case DeclarationNameExtra::CXXConversionFunction: return CXXConversionFunctionName; case DeclarationNameExtra::CXXUsingDirective: @@ -107,7 +107,7 @@ DeclarationName::NameKind DeclarationName::getNameKind() const { default: // Check if we have one of the CXXOperator* enumeration values. - if (getExtra()->ExtraKindOrNumArgs < + if (getExtra()->ExtraKindOrNumArgs < DeclarationNameExtra::CXXUsingDirective) return CXXOperatorName; @@ -135,7 +135,7 @@ std::string DeclarationName::getAsString() const { case CXXConstructorName: { QualType ClassType = getCXXNameType(); - if (const RecordType *ClassRec = ClassType->getAsRecordType()) + if (const RecordType *ClassRec = ClassType->getAs()) return ClassRec->getDecl()->getNameAsString(); return ClassType.getAsString(); } @@ -143,7 +143,7 @@ std::string DeclarationName::getAsString() const { case CXXDestructorName: { std::string Result = "~"; QualType Type = getCXXNameType(); - if (const RecordType *Rec = Type->getAsRecordType()) + if (const RecordType *Rec = Type->getAs()) Result += Rec->getDecl()->getNameAsString(); else Result += Type.getAsString(); @@ -159,7 +159,7 @@ std::string DeclarationName::getAsString() const { }; const char *OpName = OperatorNames[getCXXOverloadedOperator()]; assert(OpName && "not an overloaded operator"); - + std::string Result = "operator"; if (OpName[0] >= 'a' && OpName[0] <= 'z') Result += ' '; @@ -170,7 +170,7 @@ std::string DeclarationName::getAsString() const { case CXXConversionFunctionName: { std::string Result = "operator "; QualType Type = getCXXNameType(); - if (const RecordType *Rec = Type->getAsRecordType()) + if (const RecordType *Rec = Type->getAs()) Result += Rec->getDecl()->getNameAsString(); else Result += Type.getAsString(); @@ -193,7 +193,7 @@ QualType DeclarationName::getCXXNameType() const { OverloadedOperatorKind DeclarationName::getCXXOverloadedOperator() const { if (CXXOperatorIdName *CXXOp = getAsCXXOperatorIdName()) { - unsigned value + unsigned value = CXXOp->ExtraKindOrNumArgs - DeclarationNameExtra::CXXConversionFunction; return static_cast(value); } else { @@ -276,7 +276,7 @@ DeclarationNameTable::DeclarationNameTable() { // Initialize the overloaded operator names. CXXOperatorNames = new CXXOperatorIdName[NUM_OVERLOADED_OPERATORS]; for (unsigned Op = 0; Op < NUM_OVERLOADED_OPERATORS; ++Op) { - CXXOperatorNames[Op].ExtraKindOrNumArgs + CXXOperatorNames[Op].ExtraKindOrNumArgs = Op + DeclarationNameExtra::CXXConversionFunction; CXXOperatorNames[Op].FETokenInfo = 0; } @@ -296,26 +296,24 @@ DeclarationNameTable::~DeclarationNameTable() { delete [] CXXOperatorNames; } -DeclarationName -DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind, - QualType Ty) { +DeclarationName +DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind, + CanQualType Ty) { assert(Kind >= DeclarationName::CXXConstructorName && Kind <= DeclarationName::CXXConversionFunctionName && "Kind must be a C++ special name kind"); - assert(Ty->isCanonical() && - "Can only build C++ special names from canonical types"); - llvm::FoldingSet *SpecialNames + llvm::FoldingSet *SpecialNames = static_cast*>(CXXSpecialNamesImpl); DeclarationNameExtra::ExtraKind EKind; switch (Kind) { - case DeclarationName::CXXConstructorName: + case DeclarationName::CXXConstructorName: EKind = DeclarationNameExtra::CXXConstructor; - assert(Ty.getCVRQualifiers() == 0 &&"Constructor type must be unqualified"); + assert(!Ty.hasQualifiers() &&"Constructor type must be unqualified"); break; case DeclarationName::CXXDestructorName: EKind = DeclarationNameExtra::CXXDestructor; - assert(Ty.getCVRQualifiers() == 0 && "Destructor type must be unqualified"); + assert(!Ty.hasQualifiers() && "Destructor type must be unqualified"); break; case DeclarationName::CXXConversionFunctionName: EKind = DeclarationNameExtra::CXXConversionFunction; @@ -342,12 +340,12 @@ DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind, return DeclarationName(SpecialName); } -DeclarationName +DeclarationName DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) { return DeclarationName(&CXXOperatorNames[(unsigned)Op]); } -unsigned +unsigned llvm::DenseMapInfo:: getHashValue(clang::DeclarationName N) { return DenseMapInfo::getHashValue(N.getAsOpaquePtr()); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 482e1062d88c..0e4a29f916fa 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -21,6 +22,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/Support/raw_ostream.h" #include using namespace clang; @@ -28,34 +30,80 @@ using namespace clang; // Primary Expressions. //===----------------------------------------------------------------------===// -PredefinedExpr* PredefinedExpr::Clone(ASTContext &C) const { - return new (C) PredefinedExpr(Loc, getType(), Type); -} +// 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) { + if (const FunctionDecl *FD = dyn_cast(CurrentDecl)) { + if (IT != PrettyFunction) + return FD->getNameAsString(); -IntegerLiteral* IntegerLiteral::Clone(ASTContext &C) const { - return new (C) IntegerLiteral(Value, getType(), Loc); -} + llvm::SmallString<256> Name; + llvm::raw_svector_ostream Out(Name); -CharacterLiteral* CharacterLiteral::Clone(ASTContext &C) const { - return new (C) CharacterLiteral(Value, IsWide, getType(), Loc); -} + if (const CXXMethodDecl *MD = dyn_cast(FD)) { + if (MD->isVirtual()) + Out << "virtual "; + } -FloatingLiteral* FloatingLiteral::Clone(ASTContext &C) const { - return new (C) FloatingLiteral(Value, IsExact, getType(), Loc); -} + PrintingPolicy Policy(Context.getLangOptions()); + Policy.SuppressTagKind = true; -ImaginaryLiteral* ImaginaryLiteral::Clone(ASTContext &C) const { - // FIXME: Use virtual Clone(), once it is available - Expr *ClonedVal = 0; - if (const IntegerLiteral *IntLit = dyn_cast(Val)) - ClonedVal = IntLit->Clone(C); - else - ClonedVal = cast(Val)->Clone(C); - return new (C) ImaginaryLiteral(ClonedVal, getType()); -} + std::string Proto = FD->getQualifiedNameAsString(Policy); + + const FunctionType *AFT = FD->getType()->getAs(); + const FunctionProtoType *FT = 0; + if (FD->hasWrittenPrototype()) + FT = dyn_cast(AFT); + + Proto += "("; + if (FT) { + llvm::raw_string_ostream POut(Proto); + for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) { + if (i) POut << ", "; + std::string Param; + FD->getParamDecl(i)->getType().getAsStringInternal(Param, Policy); + POut << Param; + } + + if (FT->isVariadic()) { + if (FD->getNumParams()) POut << ", "; + POut << "..."; + } + } + Proto += ")"; + + AFT->getResultType().getAsStringInternal(Proto, Policy); + + Out << Proto; + + Out.flush(); + return Name.str().str(); + } + if (const ObjCMethodDecl *MD = dyn_cast(CurrentDecl)) { + llvm::SmallString<256> Name; + llvm::raw_svector_ostream Out(Name); + Out << (MD->isInstanceMethod() ? '-' : '+'); + Out << '['; + Out << MD->getClassInterface()->getNameAsString(); + if (const ObjCCategoryImplDecl *CID = + dyn_cast(MD->getDeclContext())) { + Out << '('; + Out << CID->getNameAsString(); + Out << ')'; + } + Out << ' '; + Out << MD->getSelector().getAsString(); + Out << ']'; -GNUNullExpr* GNUNullExpr::Clone(ASTContext &C) const { - return new (C) GNUNullExpr(getType(), TokenLoc); + Out.flush(); + return Name.str().str(); + } + if (isa(CurrentDecl) && IT == PrettyFunction) { + // __PRETTY_FUNCTION__ -> "top level", the others produce an empty string. + return "top level"; + } + return ""; } /// getValueAsApproximateDouble - This returns the value as an inaccurate @@ -72,7 +120,7 @@ double FloatingLiteral::getValueAsApproximateDouble() const { StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData, unsigned ByteLength, bool Wide, QualType Ty, - const SourceLocation *Loc, + const SourceLocation *Loc, unsigned NumStrs) { // Allocate enough space for the StringLiteral plus an array of locations for // any concatenated string tokens. @@ -80,7 +128,7 @@ StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData, sizeof(SourceLocation)*(NumStrs-1), llvm::alignof()); StringLiteral *SL = new (Mem) StringLiteral(Ty); - + // OPTIMIZE: could allocate this appended to the StringLiteral. char *AStrData = new (C, 1) char[ByteLength]; memcpy(AStrData, StrData, ByteLength); @@ -106,25 +154,19 @@ StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) { return SL; } -StringLiteral* StringLiteral::Clone(ASTContext &C) const { - return Create(C, StrData, ByteLength, IsWide, getType(), - TokLocs, NumConcatenated); -} - -void StringLiteral::Destroy(ASTContext &C) { +void StringLiteral::DoDestroy(ASTContext &C) { C.Deallocate(const_cast(StrData)); - this->~StringLiteral(); - C.Deallocate(this); + Expr::DoDestroy(C); } -void StringLiteral::setStrData(ASTContext &C, const char *Str, unsigned Len) { +void StringLiteral::setString(ASTContext &C, llvm::StringRef Str) { if (StrData) C.Deallocate(const_cast(StrData)); - char *AStrData = new (C, 1) char[Len]; - memcpy(AStrData, Str, Len); + char *AStrData = new (C, 1) char[Str.size()]; + memcpy(AStrData, Str.data(), Str.size()); StrData = AStrData; - ByteLength = Len; + ByteLength = Str.size(); } /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it @@ -149,7 +191,7 @@ const char *UnaryOperator::getOpcodeStr(Opcode Op) { } } -UnaryOperator::Opcode +UnaryOperator::Opcode UnaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix) { switch (OO) { default: assert(false && "No unary operator for overloaded function"); @@ -185,11 +227,11 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) { CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, Expr **args, unsigned numargs, QualType t, SourceLocation rparenloc) - : Expr(SC, t, + : Expr(SC, t, fn->isTypeDependent() || hasAnyTypeDependentArguments(args, numargs), fn->isValueDependent() || hasAnyValueDependentArguments(args,numargs)), NumArgs(numargs) { - + SubExprs = new (C) Stmt*[numargs+1]; SubExprs[FN] = fn; for (unsigned i = 0; i != numargs; ++i) @@ -213,25 +255,33 @@ CallExpr::CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, RParenLoc = rparenloc; } -CallExpr::CallExpr(ASTContext &C, EmptyShell Empty) - : Expr(CallExprClass, Empty), SubExprs(0), NumArgs(0) { +CallExpr::CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty) + : Expr(SC, Empty), SubExprs(0), NumArgs(0) { SubExprs = new (C) Stmt*[1]; } -void CallExpr::Destroy(ASTContext& C) { +void CallExpr::DoDestroy(ASTContext& C) { DestroyChildren(C); if (SubExprs) C.Deallocate(SubExprs); this->~CallExpr(); C.Deallocate(this); } +FunctionDecl *CallExpr::getDirectCallee() { + Expr *CEE = getCallee()->IgnoreParenCasts(); + if (DeclRefExpr *DRE = dyn_cast(CEE)) + return dyn_cast(DRE->getDecl()); + + return 0; +} + /// setNumArgs - This changes the number of arguments present in this call. /// Any orphaned expressions are deleted by this, and any new operands are set /// to null. void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) { // No change, just return. if (NumArgs == getNumArgs()) return; - + // If shrinking # arguments, just delete the extras and forgot them. if (NumArgs < getNumArgs()) { for (unsigned i = NumArgs, e = getNumArgs(); i != e; ++i) @@ -241,14 +291,14 @@ void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) { } // Otherwise, we are growing the # arguments. New an bigger argument array. - Stmt **NewSubExprs = new Stmt*[NumArgs+1]; + Stmt **NewSubExprs = new (C) Stmt*[NumArgs+1]; // Copy over args. for (unsigned i = 0; i != getNumArgs()+ARGS_START; ++i) NewSubExprs[i] = SubExprs[i]; // Null out new args. for (unsigned i = getNumArgs()+ARGS_START; i != NumArgs+ARGS_START; ++i) NewSubExprs[i] = 0; - + if (SubExprs) C.Deallocate(SubExprs); SubExprs = NewSubExprs; this->NumArgs = NumArgs; @@ -258,37 +308,130 @@ void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) { /// not, return 0. unsigned CallExpr::isBuiltinCall(ASTContext &Context) const { // All simple function calls (e.g. func()) are implicitly cast to pointer to - // function. As a result, we try and obtain the DeclRefExpr from the + // function. As a result, we try and obtain the DeclRefExpr from the // ImplicitCastExpr. const ImplicitCastExpr *ICE = dyn_cast(getCallee()); if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()). return 0; - + const DeclRefExpr *DRE = dyn_cast(ICE->getSubExpr()); if (!DRE) return 0; - + const FunctionDecl *FDecl = dyn_cast(DRE->getDecl()); if (!FDecl) return 0; - + if (!FDecl->getIdentifier()) return 0; - return FDecl->getBuiltinID(Context); + return FDecl->getBuiltinID(); } QualType CallExpr::getCallReturnType() const { QualType CalleeType = getCallee()->getType(); - if (const PointerType *FnTypePtr = CalleeType->getAsPointerType()) + if (const PointerType *FnTypePtr = CalleeType->getAs()) CalleeType = FnTypePtr->getPointeeType(); - else if (const BlockPointerType *BPT = CalleeType->getAsBlockPointerType()) + else if (const BlockPointerType *BPT = CalleeType->getAs()) CalleeType = BPT->getPointeeType(); - - const FunctionType *FnType = CalleeType->getAsFunctionType(); + + const FunctionType *FnType = CalleeType->getAs(); return FnType->getResultType(); } +MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, + SourceRange qualrange, NamedDecl *memberdecl, + SourceLocation l, bool has_explicit, + SourceLocation langle, + const TemplateArgument *targs, unsigned numtargs, + SourceLocation rangle, QualType ty) + : Expr(MemberExprClass, ty, + base->isTypeDependent() || (qual && qual->isDependent()), + base->isValueDependent() || (qual && qual->isDependent())), + Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow), + HasQualifier(qual != 0), HasExplicitTemplateArgumentList(has_explicit) { + // Initialize the qualifier, if any. + if (HasQualifier) { + NameQualifier *NQ = getMemberQualifier(); + NQ->NNS = qual; + NQ->Range = qualrange; + } + + // Initialize the explicit template argument list, if any. + if (HasExplicitTemplateArgumentList) { + ExplicitTemplateArgumentList *ETemplateArgs + = getExplicitTemplateArgumentList(); + ETemplateArgs->LAngleLoc = langle; + ETemplateArgs->RAngleLoc = rangle; + ETemplateArgs->NumTemplateArgs = numtargs; + + TemplateArgument *TemplateArgs = ETemplateArgs->getTemplateArgs(); + for (unsigned I = 0; I < numtargs; ++I) + new (TemplateArgs + I) TemplateArgument(targs[I]); + } +} + +MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, + NestedNameSpecifier *qual, + SourceRange qualrange, + NamedDecl *memberdecl, + SourceLocation l, + bool has_explicit, + SourceLocation langle, + const TemplateArgument *targs, + unsigned numtargs, + SourceLocation rangle, + QualType ty) { + std::size_t Size = sizeof(MemberExpr); + if (qual != 0) + Size += sizeof(NameQualifier); + + if (has_explicit) + Size += sizeof(ExplicitTemplateArgumentList) + + sizeof(TemplateArgument) * numtargs; + + void *Mem = C.Allocate(Size, llvm::alignof()); + return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l, + has_explicit, langle, targs, numtargs, rangle, + ty); +} + +const char *CastExpr::getCastKindName() const { + switch (getCastKind()) { + case CastExpr::CK_Unknown: + return "Unknown"; + case CastExpr::CK_BitCast: + return "BitCast"; + case CastExpr::CK_NoOp: + return "NoOp"; + case CastExpr::CK_DerivedToBase: + return "DerivedToBase"; + case CastExpr::CK_Dynamic: + return "Dynamic"; + case CastExpr::CK_ToUnion: + return "ToUnion"; + case CastExpr::CK_ArrayToPointerDecay: + return "ArrayToPointerDecay"; + case CastExpr::CK_FunctionToPointerDecay: + return "FunctionToPointerDecay"; + case CastExpr::CK_NullToMemberPointer: + return "NullToMemberPointer"; + case CastExpr::CK_BaseToDerivedMemberPointer: + return "BaseToDerivedMemberPointer"; + case CastExpr::CK_UserDefinedConversion: + return "UserDefinedConversion"; + case CastExpr::CK_ConstructorConversion: + return "ConstructorConversion"; + case CastExpr::CK_IntegralToPointer: + return "IntegralToPointer"; + case CastExpr::CK_PointerToIntegral: + return "PointerToIntegral"; + } + + assert(0 && "Unhandled cast kind!"); + return 0; +} + /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "<<=". const char *BinaryOperator::getOpcodeStr(Opcode Op) { @@ -330,7 +473,7 @@ const char *BinaryOperator::getOpcodeStr(Opcode Op) { return ""; } -BinaryOperator::Opcode +BinaryOperator::Opcode BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) { switch (OO) { default: assert(false && "Not an overloadable binary operator"); @@ -392,13 +535,13 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { return OverOps[Opc]; } -InitListExpr::InitListExpr(SourceLocation lbraceloc, +InitListExpr::InitListExpr(SourceLocation lbraceloc, Expr **initExprs, unsigned numInits, SourceLocation rbraceloc) : Expr(InitListExprClass, QualType(), hasAnyTypeDependentArguments(initExprs, numInits), hasAnyValueDependentArguments(initExprs, numInits)), - LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), + LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), UnionFieldInit(0), HadArrayRangeDesignator(false) { InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits); @@ -422,7 +565,7 @@ Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) { InitExprs.back() = expr; return 0; } - + Expr *Result = cast_or_null(InitExprs[Init]); InitExprs[Init] = expr; return Result; @@ -431,18 +574,18 @@ Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) { /// getFunctionType - Return the underlying function type for this block. /// const FunctionType *BlockExpr::getFunctionType() const { - return getType()->getAsBlockPointerType()-> - getPointeeType()->getAsFunctionType(); + return getType()->getAs()-> + getPointeeType()->getAs(); } -SourceLocation BlockExpr::getCaretLocation() const { - return TheBlock->getCaretLocation(); +SourceLocation BlockExpr::getCaretLocation() const { + return TheBlock->getCaretLocation(); } -const Stmt *BlockExpr::getBody() const { +const Stmt *BlockExpr::getBody() const { return TheBlock->getBody(); } -Stmt *BlockExpr::getBody() { - return TheBlock->getBody(); +Stmt *BlockExpr::getBody() { + return TheBlock->getBody(); } @@ -460,7 +603,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, // instantiating to void. if (isTypeDependent()) return false; - + switch (getStmtClass()) { default: Loc = getExprLoc(); @@ -471,7 +614,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, isUnusedResultAWarning(Loc, R1, R2); case UnaryOperatorClass: { const UnaryOperator *UO = cast(this); - + switch (UO->getOpcode()) { default: break; case UnaryOperator::PostInc: @@ -503,7 +646,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, if (BO->getOpcode() == BinaryOperator::Comma) return BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2) || BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2); - + if (BO->isAssignmentOp()) return false; Loc = BO->getOperatorLoc(); @@ -518,7 +661,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, // The condition must be evaluated, but if either the LHS or RHS is a // warning, warn about them. const ConditionalOperator *Exp = cast(this); - if (Exp->getLHS() && + if (Exp->getLHS() && Exp->getLHS()->isUnusedResultAWarning(Loc, R1, R2)) return true; return Exp->getRHS()->isUnusedResultAWarning(Loc, R1, R2); @@ -533,7 +676,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, R1 = SourceRange(Loc, Loc); R2 = cast(this)->getBase()->getSourceRange(); return true; - + case ArraySubscriptExprClass: // If the base pointer or element is to a volatile pointer/field, accessing // it is a side effect. @@ -549,26 +692,43 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, case CXXMemberCallExprClass: { // If this is a direct call, get the callee. const CallExpr *CE = cast(this); - const Expr *CalleeExpr = CE->getCallee()->IgnoreParenCasts(); - if (const DeclRefExpr *CalleeDRE = dyn_cast(CalleeExpr)) { + if (const FunctionDecl *FD = CE->getDirectCallee()) { // If the callee has attribute pure, const, or warn_unused_result, warn // about it. void foo() { strlen("bar"); } should warn. - if (const FunctionDecl *FD = dyn_cast(CalleeDRE->getDecl())) - if (FD->getAttr() || - FD->getAttr() || FD->getAttr()) { - Loc = CE->getCallee()->getLocStart(); - R1 = CE->getCallee()->getSourceRange(); - - if (unsigned NumArgs = CE->getNumArgs()) - R2 = SourceRange(CE->getArg(0)->getLocStart(), - CE->getArg(NumArgs-1)->getLocEnd()); - return true; - } + // + // Note: If new cases are added here, DiagnoseUnusedExprResult should be + // updated to match for QoI. + if (FD->getAttr() || + FD->getAttr() || FD->getAttr()) { + Loc = CE->getCallee()->getLocStart(); + R1 = CE->getCallee()->getSourceRange(); + + if (unsigned NumArgs = CE->getNumArgs()) + R2 = SourceRange(CE->getArg(0)->getLocStart(), + CE->getArg(NumArgs-1)->getLocEnd()); + return true; + } } return false; } case ObjCMessageExprClass: return false; + + case ObjCImplicitSetterGetterRefExprClass: { // Dot syntax for message send. +#if 0 + const ObjCImplicitSetterGetterRefExpr *Ref = + cast(this); + // FIXME: We really want the location of the '.' here. + Loc = Ref->getLocation(); + R1 = SourceRange(Ref->getLocation(), Ref->getLocation()); + if (Ref->getBase()) + R2 = Ref->getBase()->getSourceRange(); +#else + Loc = getExprLoc(); + R1 = getSourceRange(); +#endif + return true; + } case StmtExprClass: { // Statement exprs don't logically have side effects themselves, but are // sometimes used in macros in ways that give them a type that is unused. @@ -579,17 +739,16 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, if (!CS->body_empty()) if (const Expr *E = dyn_cast(CS->body_back())) return E->isUnusedResultAWarning(Loc, R1, R2); - + Loc = cast(this)->getLParenLoc(); R1 = getSourceRange(); return true; } case CStyleCastExprClass: - // If this is a cast to void, check the operand. Otherwise, the result of - // the cast is unused. + // If this is an explicit cast to void, allow it. People do this when they + // think they know what they're doing :). if (getType()->isVoidType()) - return cast(this)->getSubExpr() - ->isUnusedResultAWarning(Loc, R1, R2); + return false; Loc = cast(this)->getLParenLoc(); R1 = cast(this)->getSubExpr()->getSourceRange(); return true; @@ -602,7 +761,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, Loc = cast(this)->getTypeBeginLoc(); R1 = cast(this)->getSubExpr()->getSourceRange(); return true; - + case ImplicitCastExprClass: // Check the operand, since implicit casts are inserted by Sema return cast(this) @@ -617,6 +776,9 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, // effects (e.g. a placement new with an uninitialized POD). case CXXDeleteExprClass: return false; + case CXXBindTemporaryExprClass: + return cast(this) + ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); case CXXExprWithTemporariesClass: return cast(this) ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); @@ -628,14 +790,15 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, static bool DeclCanBeLvalue(const NamedDecl *Decl, ASTContext &Ctx) { // C++ [temp.param]p6: // A non-type non-reference template-parameter is not an lvalue. - if (const NonTypeTemplateParmDecl *NTTParm + if (const NonTypeTemplateParmDecl *NTTParm = dyn_cast(Decl)) return NTTParm->getType()->isReferenceType(); return isa(Decl) || isa(Decl) || // C++ 3.10p2: An lvalue refers to an object or function. (Ctx.getLangOptions().CPlusPlus && - (isa(Decl) || isa(Decl))); + (isa(Decl) || isa(Decl) || + isa(Decl))); } /// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or an @@ -659,11 +822,11 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const { // first, check the type (C99 6.3.2.1). Expressions with function // type in C are not lvalues, but they can be lvalues in C++. - if (TR->isFunctionType()) + if (TR->isFunctionType() || TR == Ctx.OverloadTy) return LV_NotObjectType; // Allow qualified void which is an incomplete type other than void (yuck). - if (TR->isVoidType() && !Ctx.getCanonicalType(TR).getCVRQualifiers()) + if (TR->isVoidType() && !Ctx.getCanonicalType(TR).hasQualifiers()) return LV_IncompleteVoidType; return LV_Valid; @@ -680,7 +843,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { if (cast(this)->getBase()->getType()->isVectorType()) return cast(this)->getBase()->isLvalue(Ctx); return LV_Valid; - case DeclRefExprClass: + case DeclRefExprClass: case QualifiedDeclRefExprClass: { // C99 6.5.1p2 const NamedDecl *RefdDecl = cast(this)->getDecl(); if (DeclCanBeLvalue(RefdDecl, Ctx)) @@ -693,7 +856,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { return LV_Valid; break; } - case MemberExprClass: { + case MemberExprClass: { const MemberExpr *m = cast(this); if (Ctx.getLangOptions().CPlusPlus) { // C++ [expr.ref]p4: NamedDecl *Member = m->getMemberDecl(); @@ -727,7 +890,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { // Not an lvalue. return LV_InvalidExpression; - } + } // C99 6.5.2.3p4 return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx); @@ -747,7 +910,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { return LV_Valid; break; case ImplicitCastExprClass: - return cast(this)->isLvalueCast()? LV_Valid + return cast(this)->isLvalueCast()? LV_Valid : LV_InvalidExpression; case ParenExprClass: // C99 6.5.1p5 return cast(this)->getSubExpr()->isLvalue(Ctx); @@ -760,16 +923,26 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { return BinOp->getRHS()->isLvalue(Ctx); // C++ [expr.mptr.oper]p6 - if ((BinOp->getOpcode() == BinaryOperator::PtrMemD || - BinOp->getOpcode() == BinaryOperator::PtrMemI) && + // The result of a .* expression is an lvalue only if its first operand is + // an lvalue and its second operand is a pointer to data member. + if (BinOp->getOpcode() == BinaryOperator::PtrMemD && !BinOp->getType()->isFunctionType()) return BinOp->getLHS()->isLvalue(Ctx); + // The result of an ->* expression is an lvalue only if its second operand + // is a pointer to data member. + if (BinOp->getOpcode() == BinaryOperator::PtrMemI && + !BinOp->getType()->isFunctionType()) { + QualType Ty = BinOp->getRHS()->getType(); + if (Ty->isMemberPointerType() && !Ty->isMemberFunctionPointerType()) + return LV_Valid; + } + if (!BinOp->isAssignmentOp()) return LV_InvalidExpression; if (Ctx.getLangOptions().CPlusPlus) - // C++ [expr.ass]p1: + // C++ [expr.ass]p1: // The result of an assignment operation [...] is an lvalue. return LV_Valid; @@ -778,7 +951,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { // An assignment expression [...] is not an lvalue. return LV_InvalidExpression; } - case CallExprClass: + case CallExprClass: case CXXOperatorCallExprClass: case CXXMemberCallExprClass: { // C++0x [expr.call]p10 @@ -803,7 +976,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { return LV_Valid; case ObjCPropertyRefExprClass: // FIXME: check if read-only property. return LV_Valid; - case ObjCKVCRefExprClass: // FIXME: check if read-only property. + case ObjCImplicitSetterGetterRefExprClass: // FIXME: check if read-only property. return LV_Valid; case PredefinedExprClass: return LV_Valid; @@ -828,6 +1001,9 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { case CXXTypeidExprClass: // C++ 5.2.8p1: The result of a typeid expression is an lvalue of ... return LV_Valid; + case CXXBindTemporaryExprClass: + return cast(this)->getSubExpr()-> + isLvalueInternal(Ctx); case ConditionalOperatorClass: { // Complicated handling is only for C++. if (!Ctx.getLangOptions().CPlusPlus) @@ -862,15 +1038,15 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { /// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type, /// does not have an incomplete type, does not have a const-qualified type, and -/// if it is a structure or union, does not have any member (including, +/// if it is a structure or union, does not have any member (including, /// recursively, any member or element of all contained aggregates or unions) /// with a const-qualified type. -Expr::isModifiableLvalueResult +Expr::isModifiableLvalueResult Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const { isLvalueResult lvalResult = isLvalue(Ctx); - + switch (lvalResult) { - case LV_Valid: + case LV_Valid: // C++ 3.10p11: Functions cannot be modified, but pointers to // functions can be modifiable. if (Ctx.getLangOptions().CPlusPlus && TR->isFunctionType()) @@ -900,74 +1076,37 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const { // void takeclosure(void (^C)(void)); // void func() { int x = 1; takeclosure(^{ x = 7; }); } // - if (isa(this)) { - const BlockDeclRefExpr *BDR = cast(this); + if (const BlockDeclRefExpr *BDR = dyn_cast(this)) { if (!BDR->isByRef() && isa(BDR->getDecl())) return MLV_NotBlockQualified; } + // Assigning to an 'implicit' property? + if (const ObjCImplicitSetterGetterRefExpr* Expr = + dyn_cast(this)) { + if (Expr->getSetterMethod() == 0) + return MLV_NoSetterProperty; + } + QualType CT = Ctx.getCanonicalType(getType()); - + if (CT.isConstQualified()) return MLV_ConstQualified; if (CT->isArrayType()) return MLV_ArrayType; if (CT->isIncompleteType()) return MLV_IncompleteType; - - if (const RecordType *r = CT->getAsRecordType()) { - if (r->hasConstFields()) + + if (const RecordType *r = CT->getAs()) { + if (r->hasConstFields()) return MLV_ConstQualified; } - - // Assigning to an 'implicit' property? - else if (isa(this)) { - const ObjCKVCRefExpr* KVCExpr = cast(this); - if (KVCExpr->getSetterMethod() == 0) - return MLV_NoSetterProperty; - } - return MLV_Valid; -} -/// hasGlobalStorage - Return true if this expression has static storage -/// duration. This means that the address of this expression is a link-time -/// constant. -bool Expr::hasGlobalStorage() const { - switch (getStmtClass()) { - default: - return false; - case BlockExprClass: - return true; - case ParenExprClass: - return cast(this)->getSubExpr()->hasGlobalStorage(); - case ImplicitCastExprClass: - return cast(this)->getSubExpr()->hasGlobalStorage(); - case CompoundLiteralExprClass: - return cast(this)->isFileScope(); - case DeclRefExprClass: - case QualifiedDeclRefExprClass: { - const Decl *D = cast(this)->getDecl(); - if (const VarDecl *VD = dyn_cast(D)) - return VD->hasGlobalStorage(); - if (isa(D)) - return true; - return false; - } - case MemberExprClass: { - const MemberExpr *M = cast(this); - return !M->isArrow() && M->getBase()->hasGlobalStorage(); - } - case ArraySubscriptExprClass: - return cast(this)->getBase()->hasGlobalStorage(); - case PredefinedExprClass: - return true; - case CXXDefaultArgExprClass: - return cast(this)->getExpr()->hasGlobalStorage(); - } + return MLV_Valid; } /// isOBJCGCCandidate - Check if an expression is objc gc'able. -/// +/// returns true, if it is; false otherwise. bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { switch (getStmtClass()) { default: @@ -989,11 +1128,10 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { if (VD->hasGlobalStorage()) return true; QualType T = VD->getType(); - // dereferencing to an object pointer is always a gc'able candidate - if (T->isPointerType() && - Ctx.isObjCObjectPointerType(T->getAsPointerType()->getPointeeType())) - return true; - + // dereferencing to a pointer is always a gc'able candidate, + // unless it is __weak. + return T->isPointerType() && + (Ctx.getObjCGCAttrKind(T) != Qualifiers::Weak); } return false; } @@ -1009,7 +1147,7 @@ Expr* Expr::IgnoreParens() { Expr* E = this; while (ParenExpr* P = dyn_cast(E)) E = P->getSubExpr(); - + return E; } @@ -1037,17 +1175,17 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { E = P->getSubExpr(); continue; } - + if (CastExpr *P = dyn_cast(E)) { // We ignore integer <-> casts that are of the same width, ptr<->ptr and // ptr<->int casts of the same width. We also ignore all identify casts. Expr *SE = P->getSubExpr(); - + if (Ctx.hasSameUnqualifiedType(E->getType(), SE->getType())) { E = SE; continue; } - + if ((E->getType()->isPointerType() || E->getType()->isIntegralType()) && (SE->getType()->isPointerType() || SE->getType()->isIntegralType()) && Ctx.getTypeSize(E->getType()) == Ctx.getTypeSize(SE->getType())) { @@ -1055,7 +1193,7 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { continue; } } - + return E; } } @@ -1094,6 +1232,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { switch (getStmtClass()) { default: break; case StringLiteralClass: + case ObjCStringLiteralClass: case ObjCEncodeExprClass: return true; case CompoundLiteralExprClass: { @@ -1110,22 +1249,31 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { const InitListExpr *Exp = cast(this); unsigned numInits = Exp->getNumInits(); for (unsigned i = 0; i < numInits; i++) { - if (!Exp->getInit(i)->isConstantInitializer(Ctx)) + if (!Exp->getInit(i)->isConstantInitializer(Ctx)) return false; } return true; } case ImplicitValueInitExprClass: return true; - case ParenExprClass: { + case ParenExprClass: return cast(this)->getSubExpr()->isConstantInitializer(Ctx); - } case UnaryOperatorClass: { const UnaryOperator* Exp = cast(this); if (Exp->getOpcode() == UnaryOperator::Extension) return Exp->getSubExpr()->isConstantInitializer(Ctx); break; } + case BinaryOperatorClass: { + // Special case &&foo - &&bar. It would be nice to generalize this somehow + // but this handles the common case. + const BinaryOperator *Exp = cast(this); + if (Exp->getOpcode() == BinaryOperator::Sub && + isa(Exp->getLHS()->IgnoreParenNoopCasts(Ctx)) && + isa(Exp->getRHS()->IgnoreParenNoopCasts(Ctx))) + return true; + break; + } case ImplicitCastExprClass: case CStyleCastExprClass: // Handle casts with a destination that's a struct or union; this @@ -1133,9 +1281,15 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { // cast-to-union extension. if (getType()->isRecordType()) return cast(this)->getSubExpr()->isConstantInitializer(Ctx); + + // Integer->integer casts can be handled here, which is important for + // things like (int)(&&x-&&y). Scary but true. + if (getType()->isIntegerType() && + cast(this)->getSubExpr()->getType()->isIntegerType()) + return cast(this)->getSubExpr()->isConstantInitializer(Ctx); + break; } - return isEvaluatable(Ctx); } @@ -1152,9 +1306,9 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { // CheckICE - This function does the fundamental ICE checking: the returned // ICEDiag contains a Val of 0, 1, or 2, and a possibly null SourceLocation. // Note that to reduce code duplication, this helper does no evaluation -// itself; the caller checks whether the expression is evaluatable, and +// itself; the caller checks whether the expression is evaluatable, and // in the rare cases where CheckICE actually cares about the evaluated -// value, it calls into Evalute. +// value, it calls into Evalute. // // Meanings of Val: // 0: This expression is an ICE if it can be evaluated by Evaluate. @@ -1190,8 +1344,65 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { } switch (E->getStmtClass()) { - default: +#define STMT(Node, Base) case Expr::Node##Class: +#define EXPR(Node, Base) +#include "clang/AST/StmtNodes.def" + case Expr::PredefinedExprClass: + case Expr::FloatingLiteralClass: + case Expr::ImaginaryLiteralClass: + case Expr::StringLiteralClass: + case Expr::ArraySubscriptExprClass: + case Expr::MemberExprClass: + case Expr::CompoundAssignOperatorClass: + case Expr::CompoundLiteralExprClass: + case Expr::ExtVectorElementExprClass: + case Expr::InitListExprClass: + case Expr::DesignatedInitExprClass: + case Expr::ImplicitValueInitExprClass: + case Expr::ParenListExprClass: + case Expr::VAArgExprClass: + case Expr::AddrLabelExprClass: + case Expr::StmtExprClass: + case Expr::CXXMemberCallExprClass: + case Expr::CXXDynamicCastExprClass: + case Expr::CXXTypeidExprClass: + case Expr::CXXNullPtrLiteralExprClass: + case Expr::CXXThisExprClass: + case Expr::CXXThrowExprClass: + case Expr::CXXConditionDeclExprClass: // FIXME: is this correct? + case Expr::CXXNewExprClass: + case Expr::CXXDeleteExprClass: + case Expr::CXXPseudoDestructorExprClass: + case Expr::UnresolvedFunctionNameExprClass: + case Expr::UnresolvedDeclRefExprClass: + case Expr::TemplateIdRefExprClass: + case Expr::CXXConstructExprClass: + case Expr::CXXBindTemporaryExprClass: + case Expr::CXXExprWithTemporariesClass: + case Expr::CXXTemporaryObjectExprClass: + case Expr::CXXUnresolvedConstructExprClass: + case Expr::CXXUnresolvedMemberExprClass: + case Expr::ObjCStringLiteralClass: + case Expr::ObjCEncodeExprClass: + case Expr::ObjCMessageExprClass: + case Expr::ObjCSelectorExprClass: + case Expr::ObjCProtocolExprClass: + case Expr::ObjCIvarRefExprClass: + case Expr::ObjCPropertyRefExprClass: + case Expr::ObjCImplicitSetterGetterRefExprClass: + case Expr::ObjCSuperExprClass: + case Expr::ObjCIsaExprClass: + case Expr::ShuffleVectorExprClass: + case Expr::BlockExprClass: + case Expr::BlockDeclRefExprClass: + case Expr::NoStmtClass: + case Expr::ExprClass: return ICEDiag(2, E->getLocStart()); + + case Expr::GNUNullExprClass: + // GCC considers the GNU __null value to be an integral constant expression. + return NoDiag(); + case Expr::ParenExprClass: return CheckICE(cast(E)->getSubExpr(), Ctx); case Expr::IntegerLiteralClass: @@ -1201,7 +1412,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::TypesCompatibleExprClass: case Expr::UnaryTypeTraitExprClass: return NoDiag(); - case Expr::CallExprClass: + case Expr::CallExprClass: case Expr::CXXOperatorCallExprClass: { const CallExpr *CE = cast(E); if (CE->isBuiltinCall(Ctx)) @@ -1213,7 +1424,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { if (isa(cast(E)->getDecl())) return NoDiag(); if (Ctx.getLangOptions().CPlusPlus && - E->getType().getCVRQualifiers() == QualType::Const) { + E->getType().getCVRQualifiers() == Qualifiers::Const) { // C++ 7.1.5.1p2 // A variable of non-volatile const-qualified integral or enumeration // type initialized by an ICE can be used in ICEs. @@ -1240,8 +1451,14 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::UnaryOperatorClass: { const UnaryOperator *Exp = cast(E); switch (Exp->getOpcode()) { - default: + case UnaryOperator::PostInc: + case UnaryOperator::PostDec: + case UnaryOperator::PreInc: + case UnaryOperator::PreDec: + case UnaryOperator::AddrOf: + case UnaryOperator::Deref: return ICEDiag(2, E->getLocStart()); + case UnaryOperator::Extension: case UnaryOperator::LNot: case UnaryOperator::Plus: @@ -1269,8 +1486,21 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::BinaryOperatorClass: { const BinaryOperator *Exp = cast(E); switch (Exp->getOpcode()) { - default: + case BinaryOperator::PtrMemD: + case BinaryOperator::PtrMemI: + case BinaryOperator::Assign: + case BinaryOperator::MulAssign: + case BinaryOperator::DivAssign: + case BinaryOperator::RemAssign: + case BinaryOperator::AddAssign: + case BinaryOperator::SubAssign: + case BinaryOperator::ShlAssign: + case BinaryOperator::ShrAssign: + case BinaryOperator::AndAssign: + case BinaryOperator::XorAssign: + case BinaryOperator::OrAssign: return ICEDiag(2, E->getLocStart()); + case BinaryOperator::Mul: case BinaryOperator::Div: case BinaryOperator::Rem: @@ -1340,9 +1570,15 @@ 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::CXXFunctionalCastExprClass: + case Expr::CXXNamedCastExprClass: + case Expr::CXXStaticCastExprClass: + case Expr::CXXReinterpretCastExprClass: + case Expr::CXXConstCastExprClass: { const Expr *SubExpr = cast(E)->getSubExpr(); if (SubExpr->getType()->isIntegralType()) return CheckICE(SubExpr, Ctx); @@ -1352,7 +1588,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { } case Expr::ConditionalOperatorClass: { const ConditionalOperator *Exp = cast(E); - // If the condition (ignoring parens) is a __builtin_constant_p call, + // If the condition (ignoring parens) is a __builtin_constant_p call, // then only the true side is actually considered in an integer constant // expression, and it is fully evaluated. This is an important GNU // extension. See GCC PR38377 for discussion. @@ -1392,6 +1628,9 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { return CheckICE(cast(E)->getChosenSubExpr(Ctx), Ctx); } } + + // Silence a GCC warning + return ICEDiag(2, E->getLocStart()); } bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, @@ -1413,31 +1652,45 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, /// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an /// integer constant expression with the value zero, or if this is one that is /// cast to void*. -bool Expr::isNullPointerConstant(ASTContext &Ctx) const -{ +bool Expr::isNullPointerConstant(ASTContext &Ctx, + NullPointerConstantValueDependence NPC) const { + if (isValueDependent()) { + switch (NPC) { + case NPC_NeverValueDependent: + assert(false && "Unexpected value dependent expression!"); + // If the unthinkable happens, fall through to the safest alternative. + + case NPC_ValueDependentIsNull: + return isTypeDependent() || getType()->isIntegralType(); + + case NPC_ValueDependentIsNotNull: + return false; + } + } + // Strip off a cast to void*, if it exists. Except in C++. if (const ExplicitCastExpr *CE = dyn_cast(this)) { if (!Ctx.getLangOptions().CPlusPlus) { // Check that it is a cast to void*. - if (const PointerType *PT = CE->getType()->getAsPointerType()) { + if (const PointerType *PT = CE->getType()->getAs()) { QualType Pointee = PT->getPointeeType(); - if (Pointee.getCVRQualifiers() == 0 && + if (!Pointee.hasQualifiers() && Pointee->isVoidType() && // to void* CE->getSubExpr()->getType()->isIntegerType()) // from int. - return CE->getSubExpr()->isNullPointerConstant(Ctx); + return CE->getSubExpr()->isNullPointerConstant(Ctx, NPC); } } } else if (const ImplicitCastExpr *ICE = dyn_cast(this)) { // Ignore the ImplicitCastExpr type entirely. - return ICE->getSubExpr()->isNullPointerConstant(Ctx); + return ICE->getSubExpr()->isNullPointerConstant(Ctx, NPC); } else if (const ParenExpr *PE = dyn_cast(this)) { // Accept ((void*)0) as a null pointer constant, as many other // implementations do. - return PE->getSubExpr()->isNullPointerConstant(Ctx); - } else if (const CXXDefaultArgExpr *DefaultArg + return PE->getSubExpr()->isNullPointerConstant(Ctx, NPC); + } else if (const CXXDefaultArgExpr *DefaultArg = dyn_cast(this)) { // See through default argument expressions - return DefaultArg->getExpr()->isNullPointerConstant(Ctx); + return DefaultArg->getExpr()->isNullPointerConstant(Ctx, NPC); } else if (isa(this)) { // The GNU __null extension is always a null pointer constant. return true; @@ -1448,9 +1701,10 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx) const return true; // This expression must be an integer type. - if (!getType()->isIntegerType()) + if (!getType()->isIntegerType() || + (Ctx.getLangOptions().CPlusPlus && getType()->isEnumeralType())) return false; - + // If we have an integer constant expression, we need to *evaluate* it and // test for the value 0. llvm::APSInt Result; @@ -1458,7 +1712,7 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx) const } FieldDecl *Expr::getBitField() { - Expr *E = this->IgnoreParenCasts(); + Expr *E = this->IgnoreParens(); if (MemberExpr *MemRef = dyn_cast(E)) if (FieldDecl *Field = dyn_cast(MemRef->getMemberDecl())) @@ -1479,7 +1733,7 @@ bool ExtVectorElementExpr::isArrow() const { } unsigned ExtVectorElementExpr::getNumElements() const { - if (const VectorType *VT = getType()->getAsVectorType()) + if (const VectorType *VT = getType()->getAs()) return VT->getNumElements(); return 1; } @@ -1490,20 +1744,20 @@ bool ExtVectorElementExpr::containsDuplicateElements() const { unsigned length = Accessor->getLength(); // Halving swizzles do not contain duplicate elements. - if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") || + if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") || !strcmp(compStr, "even") || !strcmp(compStr, "odd")) return false; - + // Advance past s-char prefix on hex swizzles. if (*compStr == 's' || *compStr == 'S') { compStr++; length--; } - + for (unsigned i = 0; i != length-1; i++) { const char *s = compStr+i; for (const char c = *s++; *s; s++) - if (c == *s) + if (c == *s) return true; } return false; @@ -1515,15 +1769,15 @@ void ExtVectorElementExpr::getEncodedElementAccess( const char *compStr = Accessor->getName(); if (*compStr == 's' || *compStr == 'S') compStr++; - + bool isHi = !strcmp(compStr, "hi"); bool isLo = !strcmp(compStr, "lo"); bool isEven = !strcmp(compStr, "even"); bool isOdd = !strcmp(compStr, "odd"); - + for (unsigned i = 0, e = getNumElements(); i != e; ++i) { uint64_t Index; - + if (isHi) Index = e + i; else if (isLo) @@ -1544,7 +1798,7 @@ ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo, QualType retType, ObjCMethodDecl *mproto, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned nargs) - : Expr(ObjCMessageExprClass, retType), SelName(selInfo), + : Expr(ObjCMessageExprClass, retType), SelName(selInfo), MethodProto(mproto) { NumArgs = nargs; SubExprs = new Stmt*[NumArgs+1]; @@ -1557,29 +1811,13 @@ ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo, RBracloc = RBrac; } -ObjCStringLiteral* ObjCStringLiteral::Clone(ASTContext &C) const { - // Clone the string literal. - StringLiteral *NewString = - String ? cast(String)->Clone(C) : 0; - - return new (C) ObjCStringLiteral(NewString, getType(), AtLoc); -} - -ObjCSelectorExpr *ObjCSelectorExpr::Clone(ASTContext &C) const { - return new (C) ObjCSelectorExpr(getType(), SelName, AtLoc, RParenLoc); -} - -ObjCProtocolExpr *ObjCProtocolExpr::Clone(ASTContext &C) const { - return new (C) ObjCProtocolExpr(getType(), TheProtocol, AtLoc, RParenLoc); -} - -// constructor for class messages. +// 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) - : Expr(ObjCMessageExprClass, retType), SelName(selInfo), + : Expr(ObjCMessageExprClass, retType), SelName(selInfo), MethodProto(mproto) { NumArgs = nargs; SubExprs = new Stmt*[NumArgs+1]; @@ -1592,12 +1830,12 @@ ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo, RBracloc = RBrac; } -// constructor for class messages. +// constructor for class messages. ObjCMessageExpr::ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo, QualType retType, ObjCMethodDecl *mproto, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned nargs) -: Expr(ObjCMessageExprClass, retType), SelName(selInfo), +: Expr(ObjCMessageExprClass, retType), SelName(selInfo), MethodProto(mproto) { NumArgs = nargs; SubExprs = new Stmt*[NumArgs+1]; @@ -1640,16 +1878,23 @@ bool ChooseExpr::isConditionTrue(ASTContext &C) const { return getCond()->EvaluateAsInt(C) != 0; } -void ShuffleVectorExpr::setExprs(Expr ** Exprs, unsigned NumExprs) { - if (NumExprs) - delete [] SubExprs; - - SubExprs = new Stmt* [NumExprs]; +void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs, + unsigned NumExprs) { + if (SubExprs) C.Deallocate(SubExprs); + + SubExprs = new (C) Stmt* [NumExprs]; this->NumExprs = NumExprs; memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs); } -void SizeOfAlignOfExpr::Destroy(ASTContext& C) { +void ShuffleVectorExpr::DoDestroy(ASTContext& C) { + DestroyChildren(C); + if (SubExprs) C.Deallocate(SubExprs); + this->~ShuffleVectorExpr(); + C.Deallocate(this); +} + +void SizeOfAlignOfExpr::DoDestroy(ASTContext& C) { // Override default behavior of traversing children. If this has a type // operand and the type is a variable-length array, the child iteration // will iterate over the size expression. However, this expression belongs @@ -1660,7 +1905,7 @@ void SizeOfAlignOfExpr::Destroy(ASTContext& C) { C.Deallocate(this); } else - Expr::Destroy(C); + Expr::DoDestroy(C); } //===----------------------------------------------------------------------===// @@ -1675,17 +1920,17 @@ IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() { return getField()->getIdentifier(); } -DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators, +DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators, const Designator *Designators, - SourceLocation EqualOrColonLoc, + SourceLocation EqualOrColonLoc, bool GNUSyntax, - Expr **IndexExprs, + Expr **IndexExprs, unsigned NumIndexExprs, Expr *Init) - : Expr(DesignatedInitExprClass, Ty, + : Expr(DesignatedInitExprClass, Ty, Init->isTypeDependent(), Init->isValueDependent()), - EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax), - NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) { + EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax), + NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) { this->Designators = new Designator[NumDesignators]; // Record the initializer itself. @@ -1701,7 +1946,7 @@ DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators, if (this->Designators[I].isArrayDesignator()) { // Compute type- and value-dependence. Expr *Index = IndexExprs[IndexIdx]; - ValueDependent = ValueDependent || + ValueDependent = ValueDependent || Index->isTypeDependent() || Index->isValueDependent(); // Copy the index expressions into permanent storage. @@ -1710,7 +1955,7 @@ DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators, // Compute type- and value-dependence. Expr *Start = IndexExprs[IndexIdx]; Expr *End = IndexExprs[IndexIdx + 1]; - ValueDependent = ValueDependent || + ValueDependent = ValueDependent || Start->isTypeDependent() || Start->isValueDependent() || End->isTypeDependent() || End->isValueDependent(); @@ -1724,7 +1969,7 @@ DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators, } DesignatedInitExpr * -DesignatedInitExpr::Create(ASTContext &C, Designator *Designators, +DesignatedInitExpr::Create(ASTContext &C, Designator *Designators, unsigned NumDesignators, Expr **IndexExprs, unsigned NumIndexExprs, SourceLocation ColonOrEqualLoc, @@ -1736,14 +1981,14 @@ DesignatedInitExpr::Create(ASTContext &C, Designator *Designators, IndexExprs, NumIndexExprs, Init); } -DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C, +DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C, unsigned NumIndexExprs) { void *Mem = C.Allocate(sizeof(DesignatedInitExpr) + sizeof(Stmt *) * (NumIndexExprs + 1), 8); return new (Mem) DesignatedInitExpr(NumIndexExprs + 1); } -void DesignatedInitExpr::setDesignators(const Designator *Desigs, +void DesignatedInitExpr::setDesignators(const Designator *Desigs, unsigned NumDesigs) { if (Designators) delete [] Designators; @@ -1778,7 +2023,7 @@ Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) { } Expr *DesignatedInitExpr::getArrayRangeStart(const Designator& D) { - assert(D.Kind == Designator::ArrayRangeDesignator && + assert(D.Kind == Designator::ArrayRangeDesignator && "Requires array range designator"); char* Ptr = static_cast(static_cast(this)); Ptr += sizeof(DesignatedInitExpr); @@ -1787,7 +2032,7 @@ Expr *DesignatedInitExpr::getArrayRangeStart(const Designator& D) { } Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) { - assert(D.Kind == Designator::ArrayRangeDesignator && + assert(D.Kind == Designator::ArrayRangeDesignator && "Requires array range designator"); char* Ptr = static_cast(static_cast(this)); Ptr += sizeof(DesignatedInitExpr); @@ -1797,8 +2042,8 @@ Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) { /// \brief Replaces the designator at index @p Idx with the series /// of designators in [First, Last). -void DesignatedInitExpr::ExpandDesignator(unsigned Idx, - const Designator *First, +void DesignatedInitExpr::ExpandDesignator(unsigned Idx, + const Designator *First, const Designator *Last) { unsigned NumNewDesignators = Last - First; if (NumNewDesignators == 0) { @@ -1812,7 +2057,7 @@ void DesignatedInitExpr::ExpandDesignator(unsigned Idx, return; } - Designator *NewDesignators + Designator *NewDesignators = new Designator[NumDesignators - 1 + NumNewDesignators]; std::copy(Designators, Designators + Idx, NewDesignators); std::copy(First, Last, NewDesignators + Idx); @@ -1823,13 +2068,29 @@ void DesignatedInitExpr::ExpandDesignator(unsigned Idx, NumDesignators = NumDesignators - 1 + NumNewDesignators; } -void DesignatedInitExpr::Destroy(ASTContext &C) { +void DesignatedInitExpr::DoDestroy(ASTContext &C) { delete [] Designators; - Expr::Destroy(C); + Expr::DoDestroy(C); } -ImplicitValueInitExpr *ImplicitValueInitExpr::Clone(ASTContext &C) const { - return new (C) ImplicitValueInitExpr(getType()); +ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc, + Expr **exprs, unsigned nexprs, + SourceLocation rparenloc) +: Expr(ParenListExprClass, QualType(), + hasAnyTypeDependentArguments(exprs, nexprs), + hasAnyValueDependentArguments(exprs, nexprs)), + NumExprs(nexprs), LParenLoc(lparenloc), RParenLoc(rparenloc) { + + Exprs = new (C) Stmt*[nexprs]; + for (unsigned i = 0; i != nexprs; ++i) + Exprs[i] = exprs[i]; +} + +void ParenListExpr::DoDestroy(ASTContext& C) { + DestroyChildren(C); + if (Exprs) C.Deallocate(Exprs); + this->~ParenListExpr(); + C.Deallocate(this); } //===----------------------------------------------------------------------===// @@ -1861,14 +2122,22 @@ Stmt::child_iterator ObjCIvarRefExpr::child_end() { return &Base+1; } Stmt::child_iterator ObjCPropertyRefExpr::child_begin() { return &Base; } Stmt::child_iterator ObjCPropertyRefExpr::child_end() { return &Base+1; } -// ObjCKVCRefExpr -Stmt::child_iterator ObjCKVCRefExpr::child_begin() { return &Base; } -Stmt::child_iterator ObjCKVCRefExpr::child_end() { return &Base+1; } +// ObjCImplicitSetterGetterRefExpr +Stmt::child_iterator ObjCImplicitSetterGetterRefExpr::child_begin() { + return &Base; +} +Stmt::child_iterator ObjCImplicitSetterGetterRefExpr::child_end() { + return &Base+1; +} // ObjCSuperExpr Stmt::child_iterator ObjCSuperExpr::child_begin() { return child_iterator(); } Stmt::child_iterator ObjCSuperExpr::child_end() { return child_iterator(); } +// ObjCIsaExpr +Stmt::child_iterator ObjCIsaExpr::child_begin() { return &Base; } +Stmt::child_iterator ObjCIsaExpr::child_end() { return &Base+1; } + // PredefinedExpr Stmt::child_iterator PredefinedExpr::child_begin() { return child_iterator(); } Stmt::child_iterator PredefinedExpr::child_end() { return child_iterator(); } @@ -1902,7 +2171,7 @@ Stmt::child_iterator UnaryOperator::child_begin() { return &Val; } Stmt::child_iterator UnaryOperator::child_end() { return &Val+1; } // SizeOfAlignOfExpr -Stmt::child_iterator SizeOfAlignOfExpr::child_begin() { +Stmt::child_iterator SizeOfAlignOfExpr::child_begin() { // If this is of a type and the type is a VLA type (and not a typedef), the // size expression of the VLA needs to be treated as an executable expression. // Why isn't this weirdness documented better in StmtIterator? @@ -2024,16 +2293,24 @@ Stmt::child_iterator DesignatedInitExpr::child_end() { } // ImplicitValueInitExpr -Stmt::child_iterator ImplicitValueInitExpr::child_begin() { - return child_iterator(); +Stmt::child_iterator ImplicitValueInitExpr::child_begin() { + return child_iterator(); } -Stmt::child_iterator ImplicitValueInitExpr::child_end() { - return child_iterator(); +Stmt::child_iterator ImplicitValueInitExpr::child_end() { + return child_iterator(); +} + +// ParenListExpr +Stmt::child_iterator ParenListExpr::child_begin() { + return &Exprs[0]; +} +Stmt::child_iterator ParenListExpr::child_end() { + return &Exprs[0]+NumExprs; } // ObjCStringLiteral -Stmt::child_iterator ObjCStringLiteral::child_begin() { +Stmt::child_iterator ObjCStringLiteral::child_begin() { return &String; } Stmt::child_iterator ObjCStringLiteral::child_end() { @@ -2045,7 +2322,7 @@ Stmt::child_iterator ObjCEncodeExpr::child_begin() { return child_iterator(); } Stmt::child_iterator ObjCEncodeExpr::child_end() { return child_iterator(); } // ObjCSelectorExpr -Stmt::child_iterator ObjCSelectorExpr::child_begin() { +Stmt::child_iterator ObjCSelectorExpr::child_begin() { return child_iterator(); } Stmt::child_iterator ObjCSelectorExpr::child_end() { @@ -2061,7 +2338,7 @@ Stmt::child_iterator ObjCProtocolExpr::child_end() { } // ObjCMessageExpr -Stmt::child_iterator ObjCMessageExpr::child_begin() { +Stmt::child_iterator ObjCMessageExpr::child_begin() { return getReceiver() ? &SubExprs[0] : &SubExprs[0] + ARGS_START; } Stmt::child_iterator ObjCMessageExpr::child_end() { diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 399c30255a8f..cba0e220952e 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -17,14 +17,6 @@ #include "clang/AST/ExprCXX.h" using namespace clang; -void CXXConditionDeclExpr::Destroy(ASTContext& C) { - // FIXME: Cannot destroy the decl here, because it is linked into the - // DeclContext's chain. - //getVarDecl()->Destroy(C); - this->~CXXConditionDeclExpr(); - C.Deallocate(this); -} - //===----------------------------------------------------------------------===// // Child Iterators for iterating over subexpressions/substatements //===----------------------------------------------------------------------===// @@ -38,7 +30,7 @@ Stmt::child_iterator CXXTypeidExpr::child_end() { } // CXXBoolLiteralExpr -Stmt::child_iterator CXXBoolLiteralExpr::child_begin() { +Stmt::child_iterator CXXBoolLiteralExpr::child_begin() { return child_iterator(); } Stmt::child_iterator CXXBoolLiteralExpr::child_end() { @@ -46,7 +38,7 @@ Stmt::child_iterator CXXBoolLiteralExpr::child_end() { } // CXXNullPtrLiteralExpr -Stmt::child_iterator CXXNullPtrLiteralExpr::child_begin() { +Stmt::child_iterator CXXNullPtrLiteralExpr::child_begin() { return child_iterator(); } Stmt::child_iterator CXXNullPtrLiteralExpr::child_end() { @@ -73,7 +65,7 @@ Stmt::child_iterator CXXDefaultArgExpr::child_end() { } // CXXZeroInitValueExpr -Stmt::child_iterator CXXZeroInitValueExpr::child_begin() { +Stmt::child_iterator CXXZeroInitValueExpr::child_begin() { return child_iterator(); } Stmt::child_iterator CXXZeroInitValueExpr::child_end() { @@ -101,8 +93,7 @@ CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, Initializer(initializer), Array(arraySize), NumPlacementArgs(numPlaceArgs), NumConstructorArgs(numConsArgs), OperatorNew(operatorNew), OperatorDelete(operatorDelete), Constructor(constructor), - StartLoc(startLoc), EndLoc(endLoc) -{ + StartLoc(startLoc), EndLoc(endLoc) { unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs; SubExprs = new Stmt*[TotalSize]; unsigned i = 0; @@ -124,19 +115,19 @@ Stmt::child_iterator CXXNewExpr::child_end() { Stmt::child_iterator CXXDeleteExpr::child_begin() { return &Argument; } Stmt::child_iterator CXXDeleteExpr::child_end() { return &Argument+1; } +// CXXPseudoDestructorExpr +Stmt::child_iterator CXXPseudoDestructorExpr::child_begin() { return &Base; } +Stmt::child_iterator CXXPseudoDestructorExpr::child_end() { + return &Base + 1; +} + // UnresolvedFunctionNameExpr -Stmt::child_iterator UnresolvedFunctionNameExpr::child_begin() { - return child_iterator(); +Stmt::child_iterator UnresolvedFunctionNameExpr::child_begin() { + return child_iterator(); } Stmt::child_iterator UnresolvedFunctionNameExpr::child_end() { return child_iterator(); } - -UnresolvedFunctionNameExpr* -UnresolvedFunctionNameExpr::Clone(ASTContext &C) const { - return new (C) UnresolvedFunctionNameExpr(Name, getType(), Loc); -} - // UnaryTypeTraitExpr Stmt::child_iterator UnaryTypeTraitExpr::child_begin() { return child_iterator(); @@ -155,16 +146,16 @@ StmtIterator UnresolvedDeclRefExpr::child_end() { } TemplateIdRefExpr::TemplateIdRefExpr(QualType T, - NestedNameSpecifier *Qualifier, + NestedNameSpecifier *Qualifier, SourceRange QualifierRange, - TemplateName Template, + TemplateName Template, SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, + SourceLocation LAngleLoc, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) : Expr(TemplateIdRefExprClass, T, - (Template.isDependent() || + (Template.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( TemplateArgs, NumTemplateArgs)), (Template.isDependent() || @@ -172,10 +163,8 @@ TemplateIdRefExpr::TemplateIdRefExpr(QualType T, TemplateArgs, NumTemplateArgs))), Qualifier(Qualifier), QualifierRange(QualifierRange), Template(Template), TemplateNameLoc(TemplateNameLoc), LAngleLoc(LAngleLoc), - RAngleLoc(RAngleLoc), NumTemplateArgs(NumTemplateArgs) - -{ - TemplateArgument *StoredTemplateArgs + RAngleLoc(RAngleLoc), NumTemplateArgs(NumTemplateArgs) { + TemplateArgument *StoredTemplateArgs = reinterpret_cast (this+1); for (unsigned I = 0; I != NumTemplateArgs; ++I) new (StoredTemplateArgs + I) TemplateArgument(TemplateArgs[I]); @@ -183,10 +172,10 @@ TemplateIdRefExpr::TemplateIdRefExpr(QualType T, TemplateIdRefExpr * TemplateIdRefExpr::Create(ASTContext &Context, QualType T, - NestedNameSpecifier *Qualifier, + NestedNameSpecifier *Qualifier, SourceRange QualifierRange, TemplateName Template, SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, + SourceLocation LAngleLoc, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) { void *Mem = Context.Allocate(sizeof(TemplateIdRefExpr) + @@ -196,11 +185,13 @@ TemplateIdRefExpr::Create(ASTContext &Context, QualType T, NumTemplateArgs, RAngleLoc); } -void TemplateIdRefExpr::Destroy(ASTContext &Context) { +void TemplateIdRefExpr::DoDestroy(ASTContext &Context) { const TemplateArgument *TemplateArgs = getTemplateArgs(); for (unsigned I = 0; I != NumTemplateArgs; ++I) if (Expr *E = TemplateArgs[I].getAsExpr()) E->Destroy(Context); + this->~TemplateIdRefExpr(); + Context.Deallocate(this); } Stmt::child_iterator TemplateIdRefExpr::child_begin() { @@ -213,34 +204,87 @@ Stmt::child_iterator TemplateIdRefExpr::child_end() { return Stmt::child_iterator(); } -bool UnaryTypeTraitExpr::EvaluateTrait() const { +bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const { switch(UTT) { default: assert(false && "Unknown type trait or not implemented"); case UTT_IsPOD: return QueriedType->isPODType(); case UTT_IsClass: // Fallthrough case UTT_IsUnion: - if (const RecordType *Record = QueriedType->getAsRecordType()) { + if (const RecordType *Record = QueriedType->getAs()) { bool Union = Record->getDecl()->isUnion(); return UTT == UTT_IsUnion ? Union : !Union; } return false; case UTT_IsEnum: return QueriedType->isEnumeralType(); case UTT_IsPolymorphic: - if (const RecordType *Record = QueriedType->getAsRecordType()) { + if (const RecordType *Record = QueriedType->getAs()) { // Type traits are only parsed in C++, so we've got CXXRecords. return cast(Record->getDecl())->isPolymorphic(); } return false; case UTT_IsAbstract: - if (const RecordType *RT = QueriedType->getAsRecordType()) + if (const RecordType *RT = QueriedType->getAs()) return cast(RT->getDecl())->isAbstract(); return false; + case UTT_IsEmpty: + if (const RecordType *Record = QueriedType->getAs()) { + return !Record->getDecl()->isUnion() + && cast(Record->getDecl())->isEmpty(); + } + return false; case UTT_HasTrivialConstructor: - if (const RecordType *RT = QueriedType->getAsRecordType()) + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __is_pod (type) is true then the trait is true, else if type is + // a cv class or union type (or array thereof) with a trivial default + // constructor ([class.ctor]) then the trait is true, else it is false. + if (QueriedType->isPODType()) + return true; + if (const RecordType *RT = + C.getBaseElementType(QueriedType)->getAs()) return cast(RT->getDecl())->hasTrivialConstructor(); return false; + case UTT_HasTrivialCopy: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __is_pod (type) is true or type is a reference type then + // the trait is true, else if type is a cv class or union type + // with a trivial copy constructor ([class.copy]) then the trait + // is true, else it is false. + if (QueriedType->isPODType() || QueriedType->isReferenceType()) + return true; + if (const RecordType *RT = QueriedType->getAs()) + return cast(RT->getDecl())->hasTrivialCopyConstructor(); + return false; + case UTT_HasTrivialAssign: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If type is const qualified or is a reference type then the + // trait is false. Otherwise if __is_pod (type) is true then the + // trait is true, else if type is a cv class or union type with + // a trivial copy assignment ([class.copy]) then the trait is + // true, else it is false. + // Note: the const and reference restrictions are interesting, + // given that const and reference members don't prevent a class + // from having a trivial copy assignment operator (but do cause + // errors if the copy assignment operator is actually used, q.v. + // [class.copy]p12). + + if (C.getBaseElementType(QueriedType).isConstQualified()) + return false; + if (QueriedType->isPODType()) + return true; + if (const RecordType *RT = QueriedType->getAs()) + return cast(RT->getDecl())->hasTrivialCopyAssignment(); + return false; case UTT_HasTrivialDestructor: - if (const RecordType *RT = QueriedType->getAsRecordType()) + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __is_pod (type) is true or type is a reference type + // then the trait is true, else if type is a cv class or union + // type (or array thereof) with a trivial destructor + // ([class.dtor]) then the trait is true, else it is + // false. + if (QueriedType->isPODType() || QueriedType->isReferenceType()) + return true; + if (const RecordType *RT = + C.getBaseElementType(QueriedType)->getAs()) return cast(RT->getDecl())->hasTrivialDestructor(); return false; } @@ -251,7 +295,7 @@ SourceRange CXXOperatorCallExpr::getSourceRange() const { if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) { if (getNumArgs() == 1) // Prefix operator - return SourceRange(getOperatorLoc(), + return SourceRange(getOperatorLoc(), getArg(0)->getSourceRange().getEnd()); else // Postfix operator @@ -296,26 +340,26 @@ const char *CXXNamedCastExpr::getCastName() const { } } -CXXTemporary *CXXTemporary::Create(ASTContext &C, +CXXTemporary *CXXTemporary::Create(ASTContext &C, const CXXDestructorDecl *Destructor) { return new (C) CXXTemporary(Destructor); } -void CXXTemporary::Destroy(ASTContext &C) { +void CXXTemporary::Destroy(ASTContext &Ctx) { this->~CXXTemporary(); - C.Deallocate(this); + Ctx.Deallocate(this); } -CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C, +CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C, CXXTemporary *Temp, Expr* SubExpr) { - assert(SubExpr->getType()->isRecordType() && + assert(SubExpr->getType()->isRecordType() && "Expression bound to a temporary must have record type!"); return new (C) CXXBindTemporaryExpr(Temp, SubExpr); } -void CXXBindTemporaryExpr::Destroy(ASTContext &C) { +void CXXBindTemporaryExpr::DoDestroy(ASTContext &C) { Temp->Destroy(C); this->~CXXBindTemporaryExpr(); C.Deallocate(this); @@ -324,38 +368,49 @@ void CXXBindTemporaryExpr::Destroy(ASTContext &C) { CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons, QualType writtenTy, - SourceLocation tyBeginLoc, + SourceLocation tyBeginLoc, Expr **Args, - unsigned NumArgs, + unsigned NumArgs, SourceLocation rParenLoc) - : CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, Cons, - false, Args, NumArgs), + : CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, Cons, + false, Args, NumArgs), TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) { } -CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, +CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, CXXConstructorDecl *D, bool Elidable, Expr **Args, unsigned NumArgs) { - return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, D, Elidable, + return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, D, Elidable, Args, NumArgs); } -CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, +CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, CXXConstructorDecl *D, bool elidable, - Expr **args, unsigned numargs) + Expr **args, unsigned numargs) : Expr(SC, T, T->isDependentType(), (T->isDependentType() || CallExpr::hasAnyValueDependentArguments(args, numargs))), Constructor(D), Elidable(elidable), Args(0), NumArgs(numargs) { - if (NumArgs > 0) { + if (NumArgs) { Args = new (C) Stmt*[NumArgs]; - for (unsigned i = 0; i < NumArgs; ++i) + + for (unsigned i = 0; i != NumArgs; ++i) { + assert(args[i] && "NULL argument in CXXConstructExpr"); Args[i] = args[i]; + } } } -void CXXConstructExpr::Destroy(ASTContext &C) { +CXXConstructExpr::CXXConstructExpr(EmptyShell Empty, ASTContext &C, + unsigned numargs) + : Expr(CXXConstructExprClass, Empty), Args(0), NumArgs(numargs) +{ + if (NumArgs) + Args = new (C) Stmt*[NumArgs]; +} + +void CXXConstructExpr::DoDestroy(ASTContext &C) { DestroyChildren(C); if (Args) C.Deallocate(Args); @@ -363,13 +418,13 @@ void CXXConstructExpr::Destroy(ASTContext &C) { C.Deallocate(this); } -CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr, - CXXTemporary **temps, +CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr, + CXXTemporary **temps, unsigned numtemps, bool shoulddestroytemps) : Expr(CXXExprWithTemporariesClass, subexpr->getType(), - subexpr->isTypeDependent(), subexpr->isValueDependent()), - SubExpr(subexpr), Temps(0), NumTemps(numtemps), + subexpr->isTypeDependent(), subexpr->isValueDependent()), + SubExpr(subexpr), Temps(0), NumTemps(numtemps), ShouldDestroyTemps(shoulddestroytemps) { if (NumTemps > 0) { Temps = new CXXTemporary*[NumTemps]; @@ -378,16 +433,16 @@ CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr, } } -CXXExprWithTemporaries *CXXExprWithTemporaries::Create(ASTContext &C, +CXXExprWithTemporaries *CXXExprWithTemporaries::Create(ASTContext &C, Expr *SubExpr, - CXXTemporary **Temps, + CXXTemporary **Temps, unsigned NumTemps, bool ShouldDestroyTemps){ - return new (C) CXXExprWithTemporaries(SubExpr, Temps, NumTemps, + return new (C) CXXExprWithTemporaries(SubExpr, Temps, NumTemps, ShouldDestroyTemps); } -void CXXExprWithTemporaries::Destroy(ASTContext &C) { +void CXXExprWithTemporaries::DoDestroy(ASTContext &C) { DestroyChildren(C); this->~CXXExprWithTemporaries(); C.Deallocate(this); @@ -402,7 +457,7 @@ Stmt::child_iterator CXXBindTemporaryExpr::child_begin() { return &SubExpr; } -Stmt::child_iterator CXXBindTemporaryExpr::child_end() { +Stmt::child_iterator CXXBindTemporaryExpr::child_end() { return &SubExpr + 1; } @@ -419,7 +474,7 @@ Stmt::child_iterator CXXExprWithTemporaries::child_begin() { return &SubExpr; } -Stmt::child_iterator CXXExprWithTemporaries::child_end() { +Stmt::child_iterator CXXExprWithTemporaries::child_end() { return &SubExpr + 1; } @@ -442,7 +497,7 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr( } CXXUnresolvedConstructExpr * -CXXUnresolvedConstructExpr::Create(ASTContext &C, +CXXUnresolvedConstructExpr::Create(ASTContext &C, SourceLocation TyBegin, QualType T, SourceLocation LParenLoc, @@ -463,26 +518,79 @@ Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() { return child_iterator(reinterpret_cast(this + 1) + NumArgs); } -Stmt::child_iterator CXXUnresolvedMemberExpr::child_begin() { - return child_iterator(&Base); -} - -Stmt::child_iterator CXXUnresolvedMemberExpr::child_end() { - return child_iterator(&Base + 1); +CXXUnresolvedMemberExpr::CXXUnresolvedMemberExpr(ASTContext &C, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + NamedDecl *FirstQualifierFoundInScope, + DeclarationName Member, + SourceLocation MemberLoc, + bool HasExplicitTemplateArgs, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc) + : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true), + Base(Base), IsArrow(IsArrow), + HasExplicitTemplateArgumentList(HasExplicitTemplateArgs), + OperatorLoc(OperatorLoc), + Qualifier(Qualifier), QualifierRange(QualifierRange), + FirstQualifierFoundInScope(FirstQualifierFoundInScope), + Member(Member), MemberLoc(MemberLoc) { + if (HasExplicitTemplateArgumentList) { + ExplicitTemplateArgumentList *ETemplateArgs + = getExplicitTemplateArgumentList(); + ETemplateArgs->LAngleLoc = LAngleLoc; + ETemplateArgs->RAngleLoc = RAngleLoc; + ETemplateArgs->NumTemplateArgs = NumTemplateArgs; + + TemplateArgument *SavedTemplateArgs = ETemplateArgs->getTemplateArgs(); + for (unsigned I = 0; I < NumTemplateArgs; ++I) + new (SavedTemplateArgs + I) TemplateArgument(TemplateArgs[I]); + } } -//===----------------------------------------------------------------------===// -// Cloners -//===----------------------------------------------------------------------===// - -CXXBoolLiteralExpr* CXXBoolLiteralExpr::Clone(ASTContext &C) const { - return new (C) CXXBoolLiteralExpr(Value, getType(), Loc); +CXXUnresolvedMemberExpr * +CXXUnresolvedMemberExpr::Create(ASTContext &C, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + NamedDecl *FirstQualifierFoundInScope, + DeclarationName Member, + SourceLocation MemberLoc, + bool HasExplicitTemplateArgs, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc) { + if (!HasExplicitTemplateArgs) + return new (C) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc, + Qualifier, QualifierRange, + FirstQualifierFoundInScope, + Member, MemberLoc); + + void *Mem = C.Allocate(sizeof(CXXUnresolvedMemberExpr) + + sizeof(ExplicitTemplateArgumentList) + + sizeof(TemplateArgument) * NumTemplateArgs, + llvm::alignof()); + return new (Mem) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc, + Qualifier, QualifierRange, + FirstQualifierFoundInScope, + Member, + MemberLoc, + HasExplicitTemplateArgs, + LAngleLoc, + TemplateArgs, + NumTemplateArgs, + RAngleLoc); } -CXXNullPtrLiteralExpr* CXXNullPtrLiteralExpr::Clone(ASTContext &C) const { - return new (C) CXXNullPtrLiteralExpr(getType(), Loc); +Stmt::child_iterator CXXUnresolvedMemberExpr::child_begin() { + return child_iterator(&Base); } -CXXZeroInitValueExpr* CXXZeroInitValueExpr::Clone(ASTContext &C) const { - return new (C) CXXZeroInitValueExpr(getType(), TyBeginLoc, RParenLoc); +Stmt::child_iterator CXXUnresolvedMemberExpr::child_end() { + return child_iterator(&Base + 1); } diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index eb6b5b725ff5..94d22998ebbe 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -42,12 +42,16 @@ using llvm::APFloat; /// certain things in certain situations. struct EvalInfo { ASTContext &Ctx; - + /// EvalResult - Contains information about the evaluation. Expr::EvalResult &EvalResult; - EvalInfo(ASTContext &ctx, Expr::EvalResult& evalresult) : Ctx(ctx), - EvalResult(evalresult) {} + /// AnyLValue - Stack based LValue results are not discarded. + bool AnyLValue; + + EvalInfo(ASTContext &ctx, Expr::EvalResult& evalresult, + bool anylvalue = false) + : Ctx(ctx), EvalResult(evalresult), AnyLValue(anylvalue) {} }; @@ -104,12 +108,12 @@ static bool HandleConversionToBool(Expr* E, bool& Result, EvalInfo &Info) { return false; } -static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType, +static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType, APFloat &Value, ASTContext &Ctx) { unsigned DestWidth = Ctx.getIntWidth(DestType); // Determine whether we are converting to unsigned or signed. bool DestSigned = DestType->isSignedIntegerType(); - + // FIXME: Warning for overflow. uint64_t Space[4]; bool ignored; @@ -118,16 +122,16 @@ static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType, return APSInt(llvm::APInt(DestWidth, 4, Space), !DestSigned); } -static APFloat HandleFloatToFloatCast(QualType DestType, QualType SrcType, +static APFloat HandleFloatToFloatCast(QualType DestType, QualType SrcType, APFloat &Value, ASTContext &Ctx) { bool ignored; APFloat Result = Value; - Result.convert(Ctx.getFloatTypeSemantics(DestType), + Result.convert(Ctx.getFloatTypeSemantics(DestType), APFloat::rmNearestTiesToEven, &ignored); return Result; } -static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType, +static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType, APSInt &Value, ASTContext &Ctx) { unsigned DestWidth = Ctx.getIntWidth(DestType); APSInt Result = Value; @@ -138,7 +142,7 @@ static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType, return Result; } -static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType, +static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType, APSInt &Value, ASTContext &Ctx) { APFloat Result(Ctx.getFloatTypeSemantics(DestType), 1); @@ -155,7 +159,7 @@ class VISIBILITY_HIDDEN LValueExprEvaluator : public StmtVisitor { EvalInfo &Info; public: - + LValueExprEvaluator(EvalInfo &info) : Info(info) {} APValue VisitStmt(Stmt *S) { @@ -176,6 +180,16 @@ public: { return Visit(E->getSubExpr()); } APValue VisitChooseExpr(const ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } + + APValue VisitCastExpr(CastExpr *E) { + switch (E->getCastKind()) { + default: + return APValue(); + + case CastExpr::CK_NoOp: + return Visit(E->getSubExpr()); + } + } // FIXME: Missing: __real__, __imag__ }; } // end anonymous namespace @@ -185,16 +199,15 @@ static bool EvaluateLValue(const Expr* E, APValue& Result, EvalInfo &Info) { return Result.isLValue(); } -APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) -{ - if (!E->hasGlobalStorage()) - return APValue(); - +APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) { if (isa(E->getDecl())) { return APValue(E, 0); } else if (VarDecl* VD = dyn_cast(E->getDecl())) { + if (!Info.AnyLValue && !VD->hasGlobalStorage()) + return APValue(); if (!VD->getType()->isReferenceType()) return APValue(E, 0); + // FIXME: Check whether VD might be overridden! if (VD->getInit()) return Visit(VD->getInit()); } @@ -202,18 +215,17 @@ APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) return APValue(); } -APValue LValueExprEvaluator::VisitBlockExpr(BlockExpr *E) -{ +APValue LValueExprEvaluator::VisitBlockExpr(BlockExpr *E) { if (E->hasBlockDeclRefExprs()) return APValue(); - + return APValue(E, 0); } APValue LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { - if (E->isFileScope()) - return APValue(E, 0); - return APValue(); + if (!Info.AnyLValue && !E->isFileScope()) + return APValue(); + return APValue(E, 0); } APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { @@ -222,7 +234,7 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { if (E->isArrow()) { if (!EvaluatePointer(E->getBase(), result, Info)) return APValue(); - Ty = E->getBase()->getType()->getAsPointerType()->getPointeeType(); + Ty = E->getBase()->getType()->getAs()->getPointeeType(); } else { result = Visit(E->getBase()); if (result.isUninit()) @@ -230,7 +242,7 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { Ty = E->getBase()->getType(); } - RecordDecl *RD = Ty->getAsRecordType()->getDecl(); + RecordDecl *RD = Ty->getAs()->getDecl(); const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); FieldDecl *FD = dyn_cast(E->getMemberDecl()); @@ -255,13 +267,12 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { return result; } -APValue LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) -{ +APValue LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { APValue Result; - + if (!EvaluatePointer(E->getBase(), Result, Info)) return APValue(); - + APSInt Index; if (!EvaluateInteger(E->getIdx(), Index, Info)) return APValue(); @@ -269,13 +280,12 @@ APValue LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) uint64_t ElementSize = Info.Ctx.getTypeSize(E->getType()) / 8; uint64_t Offset = Index.getSExtValue() * ElementSize; - Result.setLValue(Result.getLValueBase(), + Result.setLValue(Result.getLValueBase(), Result.getLValueOffset() + Offset); return Result; } -APValue LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) -{ +APValue LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) { APValue Result; if (!EvaluatePointer(E->getSubExpr(), Result, Info)) return APValue(); @@ -291,7 +301,7 @@ class VISIBILITY_HIDDEN PointerExprEvaluator : public StmtVisitor { EvalInfo &Info; public: - + PointerExprEvaluator(EvalInfo &info) : Info(info) {} APValue VisitStmt(Stmt *S) { @@ -337,23 +347,23 @@ APValue PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (E->getOpcode() != BinaryOperator::Add && E->getOpcode() != BinaryOperator::Sub) return APValue(); - + const Expr *PExp = E->getLHS(); const Expr *IExp = E->getRHS(); if (IExp->getType()->isPointerType()) std::swap(PExp, IExp); - + APValue ResultLValue; if (!EvaluatePointer(PExp, ResultLValue, Info)) return APValue(); - + llvm::APSInt AdditionalOffset(32); if (!EvaluateInteger(IExp, AdditionalOffset, Info)) return APValue(); - QualType PointeeType = PExp->getType()->getAsPointerType()->getPointeeType(); + QualType PointeeType = PExp->getType()->getAs()->getPointeeType(); uint64_t SizeOfPointee; - + // Explicitly handle GNU void* and function pointer arithmetic extensions. if (PointeeType->isVoidType() || PointeeType->isFunctionType()) SizeOfPointee = 1; @@ -376,19 +386,21 @@ APValue PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) { return result; return APValue(); } - + APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { const Expr* SubExpr = E->getSubExpr(); // Check for pointer->pointer cast - if (SubExpr->getType()->isPointerType()) { + if (SubExpr->getType()->isPointerType() || + SubExpr->getType()->isObjCObjectPointerType() || + SubExpr->getType()->isNullPtrType()) { APValue Result; if (EvaluatePointer(SubExpr, Result, Info)) return Result; return APValue(); } - + if (SubExpr->getType()->isIntegralType()) { APValue Result; if (!EvaluateIntegerOrLValue(SubExpr, Result, Info)) @@ -398,7 +410,7 @@ APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType())); return APValue(0, Result.getInt().getZExtValue()); } - + // Cast is of an lvalue, no need to change value. return Result; } @@ -413,10 +425,10 @@ APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { } return APValue(); -} +} APValue PointerExprEvaluator::VisitCallExpr(CallExpr *E) { - if (E->isBuiltinCall(Info.Ctx) == + if (E->isBuiltinCall(Info.Ctx) == Builtin::BI__builtin___CFStringMakeConstantString) return APValue(E, 0); return APValue(); @@ -445,13 +457,13 @@ namespace { EvalInfo &Info; APValue GetZeroVector(QualType VecType); public: - + VectorExprEvaluator(EvalInfo &info) : Info(info) {} - + APValue VisitStmt(Stmt *S) { return APValue(); } - + APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } APValue VisitUnaryExtension(const UnaryOperator *E) @@ -485,11 +497,11 @@ static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) { } APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { - const VectorType *VTy = E->getType()->getAsVectorType(); + const VectorType *VTy = E->getType()->getAs(); QualType EltTy = VTy->getElementType(); unsigned NElts = VTy->getNumElements(); unsigned EltWidth = Info.Ctx.getTypeSize(EltTy); - + const Expr* SE = E->getSubExpr(); QualType SETy = SE->getType(); APValue Result = APValue(); @@ -539,12 +551,12 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { // element. APSInt Init; Init = Result.isInt() ? Result.getInt() : Result.getFloat().bitcastToAPInt(); - + llvm::SmallVector Elts; for (unsigned i = 0; i != NElts; ++i) { APSInt Tmp = Init; Tmp.extOrTrunc(EltWidth); - + if (EltTy->isIntegerType()) Elts.push_back(APValue(Tmp)); else if (EltTy->isRealFloatingType()) @@ -557,17 +569,17 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { return APValue(&Elts[0], Elts.size()); } -APValue +APValue VectorExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { return this->Visit(const_cast(E->getInitializer())); } -APValue +APValue VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { - const VectorType *VT = E->getType()->getAsVectorType(); + const VectorType *VT = E->getType()->getAs(); unsigned NumInits = E->getNumInits(); unsigned NumElements = VT->getNumElements(); - + QualType EltTy = VT->getElementType(); llvm::SmallVector Elements; @@ -595,9 +607,9 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { return APValue(&Elements[0], Elements.size()); } -APValue +APValue VectorExprEvaluator::GetZeroVector(QualType T) { - const VectorType *VT = T->getAsVectorType(); + const VectorType *VT = T->getAs(); QualType EltTy = VT->getElementType(); APValue ZeroElement; if (EltTy->isIntegerType()) @@ -676,20 +688,20 @@ public: } return false; } - + //===--------------------------------------------------------------------===// // Visitor Methods //===--------------------------------------------------------------------===// - + bool VisitStmt(Stmt *) { assert(0 && "This should be called on integers, stmts are not integers"); return false; } - + bool VisitExpr(Expr *E) { return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); } - + bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } bool VisitIntegerLiteral(const IntegerLiteral *E) { @@ -704,7 +716,7 @@ public: // be able to strip CRV qualifiers from the type. QualType T0 = Info.Ctx.getCanonicalType(E->getArgType1()); QualType T1 = Info.Ctx.getCanonicalType(E->getArgType2()); - return Success(Info.Ctx.typesAreCompatible(T0.getUnqualifiedType(), + return Success(Info.Ctx.typesAreCompatible(T0.getUnqualifiedType(), T1.getUnqualifiedType()), E); } @@ -720,11 +732,11 @@ public: bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { return Success(E->getValue(), E); } - + bool VisitGNUNullExpr(const GNUNullExpr *E) { return Success(0, E); } - + bool VisitCXXZeroInitValueExpr(const CXXZeroInitValueExpr *E) { return Success(0, E); } @@ -734,7 +746,7 @@ public: } bool VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) { - return Success(E->EvaluateTrait(), E); + return Success(E->EvaluateTrait(Info.Ctx), E); } bool VisitChooseExpr(const ChooseExpr *E) { @@ -754,7 +766,7 @@ private: static bool EvaluateIntegerOrLValue(const Expr* E, APValue &Result, EvalInfo &Info) { if (!E->getType()->isIntegralType()) return false; - + return IntExprEvaluator(Info, Result).Visit(const_cast(E)); } @@ -781,7 +793,7 @@ bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { // In C++, const, non-volatile integers initialized with ICEs are ICEs. // In C, they can also be folded, although they are not ICEs. - if (E->getType().getCVRQualifiers() == QualType::Const) { + if (E->getType().getCVRQualifiers() == Qualifiers::Const) { if (const VarDecl *D = dyn_cast(E->getDecl())) { if (APValue *V = D->getEvaluatedValue()) return Success(V->getInt(), E); @@ -817,12 +829,12 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) { array_type_class, string_type_class, lang_type_class }; - - // If no argument was supplied, default to "no_type_class". This isn't + + // If no argument was supplied, default to "no_type_class". This isn't // ideal, however it is what gcc does. if (E->getNumArgs() == 0) return no_type_class; - + QualType ArgTy = E->getArg(0)->getType(); if (ArgTy->isVoidType()) return void_type_class; @@ -863,11 +875,17 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); case Builtin::BI__builtin_classify_type: return Success(EvaluateBuiltinClassifyType(E), E); - + case Builtin::BI__builtin_constant_p: // __builtin_constant_p always has one operand: it returns true if that // operand can be folded, false otherwise. return Success(E->getArg(0)->isEvaluatable(Info.Ctx), E); + + case Builtin::BI__builtin_eh_return_data_regno: { + int Operand = E->getArg(0)->EvaluateAsInt(Info.Ctx).getZExtValue(); + Operand = Info.Ctx.Target.getEHDataRegisterNumber(Operand); + return Success(Operand, E); + } } } @@ -888,7 +906,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // These need to be handled specially because the operands aren't // necessarily integral bool lhsResult, rhsResult; - + if (HandleConversionToBool(E->getLHS(), lhsResult, Info)) { // We were able to evaluate the LHS, see if we can get away with not // evaluating the RHS: 0 && X -> 0, 1 || X -> 1 @@ -905,7 +923,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) { // We can't evaluate the LHS; however, sometimes the result // is determined by the RHS: X && 0 -> 0, X || 1 -> 1. - if (rhsResult == (E->getOpcode() == BinaryOperator::LOr) || + if (rhsResult == (E->getOpcode() == BinaryOperator::LOr) || !rhsResult == (E->getOpcode() == BinaryOperator::LAnd)) { // Since we weren't able to evaluate the left hand side, it // must have had side effects. @@ -933,9 +951,9 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { return false; if (LHS.isComplexFloat()) { - APFloat::cmpResult CR_r = + APFloat::cmpResult CR_r = LHS.getComplexFloatReal().compare(RHS.getComplexFloatReal()); - APFloat::cmpResult CR_i = + APFloat::cmpResult CR_i = LHS.getComplexFloatImag().compare(RHS.getComplexFloatImag()); if (E->getOpcode() == BinaryOperator::EQ) @@ -944,9 +962,9 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { else { assert(E->getOpcode() == BinaryOperator::NE && "Invalid complex comparison."); - return Success(((CR_r == APFloat::cmpGreaterThan || + return Success(((CR_r == APFloat::cmpGreaterThan || CR_r == APFloat::cmpLessThan) && - (CR_i == APFloat::cmpGreaterThan || + (CR_i == APFloat::cmpGreaterThan || CR_i == APFloat::cmpLessThan)), E); } } else { @@ -961,17 +979,17 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } } } - + if (LHSTy->isRealFloatingType() && RHSTy->isRealFloatingType()) { APFloat RHS(0.0), LHS(0.0); - + if (!EvaluateFloat(E->getRHS(), RHS, Info)) return false; - + if (!EvaluateFloat(E->getLHS(), LHS, Info)) return false; - + APFloat::cmpResult CR = LHS.compare(RHS); switch (E->getOpcode()) { @@ -984,16 +1002,16 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { case BinaryOperator::LE: return Success(CR == APFloat::cmpLessThan || CR == APFloat::cmpEqual, E); case BinaryOperator::GE: - return Success(CR == APFloat::cmpGreaterThan || CR == APFloat::cmpEqual, + return Success(CR == APFloat::cmpGreaterThan || CR == APFloat::cmpEqual, E); case BinaryOperator::EQ: return Success(CR == APFloat::cmpEqual, E); case BinaryOperator::NE: - return Success(CR == APFloat::cmpGreaterThan + return Success(CR == APFloat::cmpGreaterThan || CR == APFloat::cmpLessThan, E); } } - + if (LHSTy->isPointerType() && RHSTy->isPointerType()) { if (E->getOpcode() == BinaryOperator::Sub || E->isEqualityOp()) { APValue LHSValue; @@ -1028,7 +1046,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (E->getOpcode() == BinaryOperator::Sub) { const QualType Type = E->getLHS()->getType(); - const QualType ElementType = Type->getAsPointerType()->getPointeeType(); + const QualType ElementType = Type->getAs()->getPointeeType(); uint64_t D = LHSValue.getLValueOffset() - RHSValue.getLValueOffset(); if (!ElementType->isVoidType() && !ElementType->isFunctionType()) @@ -1105,16 +1123,16 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { return Success(Result.getInt() % RHS, E); case BinaryOperator::Shl: { // FIXME: Warn about out of range shift amounts! - unsigned SA = + unsigned SA = (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1); return Success(Result.getInt() << SA, E); } case BinaryOperator::Shr: { - unsigned SA = + unsigned SA = (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1); return Success(Result.getInt() >> SA, E); } - + case BinaryOperator::LT: return Success(Result.getInt() < RHS, E); case BinaryOperator::GT: return Success(Result.getInt() > RHS, E); case BinaryOperator::LE: return Success(Result.getInt() <= RHS, E); @@ -1144,7 +1162,7 @@ unsigned 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. + // to 1 in those cases. if (const DeclRefExpr *DRE = dyn_cast(E)) return Info.Ctx.getDeclAlignInBytes(DRE->getDecl()); @@ -1224,7 +1242,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { // If so, we could clear the diagnostic ID. return true; case UnaryOperator::Plus: - // The result is always just the subexpr. + // The result is always just the subexpr. return true; case UnaryOperator::Minus: if (!Result.isInt()) return false; @@ -1234,7 +1252,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { return Success(~Result.getInt(), E); } } - + /// HandleCast - This is used to evaluate implicit or explicit casts where the /// result type is integer. bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { @@ -1262,7 +1280,7 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { return Success(HandleIntToIntCast(DestType, SrcType, Result.getInt(), Info.Ctx), E); } - + // FIXME: Clean this up! if (SrcType->isPointerType()) { APValue LV; @@ -1316,7 +1334,7 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { APFloat F(0.0); if (!EvaluateFloat(SubExpr, F, Info)) return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E); - + return Success(HandleFloatToIntCast(DestType, SrcType, F, Info.Ctx), E); } @@ -1399,13 +1417,13 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { Result = llvm::APFloat::getInf(Sem); return true; } - + case Builtin::BI__builtin_nan: case Builtin::BI__builtin_nanf: case Builtin::BI__builtin_nanl: // If this is __builtin_nan() turn this into a nan, otherwise we // can't constant fold it. - if (const StringLiteral *S = + if (const StringLiteral *S = dyn_cast(E->getArg(0)->IgnoreParenCasts())) { if (!S->isWide()) { const llvm::fltSemantics &Sem = @@ -1430,13 +1448,13 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_fabsl: if (!EvaluateFloat(E->getArg(0), Result, Info)) return false; - + if (Result.isNegative()) Result.changeSign(); return true; - case Builtin::BI__builtin_copysign: - case Builtin::BI__builtin_copysignf: + case Builtin::BI__builtin_copysign: + case Builtin::BI__builtin_copysignf: case Builtin::BI__builtin_copysignl: { APFloat RHS(0.); if (!EvaluateFloat(E->getArg(0), Result, Info) || @@ -1457,7 +1475,7 @@ bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { switch (E->getOpcode()) { default: return false; - case UnaryOperator::Plus: + case UnaryOperator::Plus: return true; case UnaryOperator::Minus: Result.changeSign(); @@ -1498,12 +1516,12 @@ bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) { bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) { Expr* SubExpr = E->getSubExpr(); - + if (SubExpr->getType()->isIntegralType()) { APSInt IntResult; if (!EvaluateInteger(SubExpr, IntResult, Info)) return false; - Result = HandleIntToFloatCast(E->getType(), SubExpr->getType(), + Result = HandleIntToFloatCast(E->getType(), SubExpr->getType(), IntResult, Info.Ctx); return true; } @@ -1532,10 +1550,10 @@ namespace { class VISIBILITY_HIDDEN ComplexExprEvaluator : public StmtVisitor { EvalInfo &Info; - + public: ComplexExprEvaluator(EvalInfo &info) : Info(info) {} - + //===--------------------------------------------------------------------===// // Visitor Methods //===--------------------------------------------------------------------===// @@ -1543,7 +1561,7 @@ public: APValue VisitStmt(Stmt *S) { return APValue(); } - + APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } APValue VisitImaginaryLiteral(ImaginaryLiteral *E) { @@ -1554,17 +1572,17 @@ public: if (!EvaluateFloat(SubExpr, Result, Info)) return APValue(); - - return APValue(APFloat(Result.getSemantics(), APFloat::fcZero, false), + + return APValue(APFloat(Result.getSemantics(), APFloat::fcZero, false), Result); } else { - assert(SubExpr->getType()->isIntegerType() && + assert(SubExpr->getType()->isIntegerType() && "Unexpected imaginary literal."); llvm::APSInt Result; if (!EvaluateInteger(SubExpr, Result, Info)) return APValue(); - + llvm::APSInt Zero(Result.getBitWidth(), !Result.isSigned()); Zero = 0; return APValue(Zero, Result); @@ -1573,7 +1591,7 @@ public: APValue VisitCastExpr(CastExpr *E) { Expr* SubExpr = E->getSubExpr(); - QualType EltType = E->getType()->getAsComplexType()->getElementType(); + QualType EltType = E->getType()->getAs()->getElementType(); QualType SubType = SubExpr->getType(); if (SubType->isRealFloatingType()) { @@ -1584,7 +1602,7 @@ public: if (EltType->isRealFloatingType()) { Result = HandleFloatToFloatCast(EltType, SubType, Result, Info.Ctx); - return APValue(Result, + return APValue(Result, APFloat(Result.getSemantics(), APFloat::fcZero, false)); } else { llvm::APSInt IResult; @@ -1602,7 +1620,7 @@ public: if (EltType->isRealFloatingType()) { APFloat FResult = HandleIntToFloatCast(EltType, SubType, Result, Info.Ctx); - return APValue(FResult, + return APValue(FResult, APFloat(FResult.getSemantics(), APFloat::fcZero, false)); } else { Result = HandleIntToIntCast(EltType, SubType, Result, Info.Ctx); @@ -1610,7 +1628,7 @@ public: Zero = 0; return APValue(Result, Zero); } - } else if (const ComplexType *CT = SubType->getAsComplexType()) { + } else if (const ComplexType *CT = SubType->getAs()) { APValue Src; if (!EvaluateComplex(SubExpr, Src, Info)) @@ -1620,36 +1638,36 @@ public: if (Src.isComplexFloat()) { if (EltType->isRealFloatingType()) { - return APValue(HandleFloatToFloatCast(EltType, SrcType, + return APValue(HandleFloatToFloatCast(EltType, SrcType, Src.getComplexFloatReal(), Info.Ctx), - HandleFloatToFloatCast(EltType, SrcType, + HandleFloatToFloatCast(EltType, SrcType, Src.getComplexFloatImag(), Info.Ctx)); } else { return APValue(HandleFloatToIntCast(EltType, SrcType, Src.getComplexFloatReal(), Info.Ctx), - HandleFloatToIntCast(EltType, SrcType, + HandleFloatToIntCast(EltType, SrcType, Src.getComplexFloatImag(), - Info.Ctx)); + Info.Ctx)); } } else { assert(Src.isComplexInt() && "Invalid evaluate result."); if (EltType->isRealFloatingType()) { - return APValue(HandleIntToFloatCast(EltType, SrcType, + return APValue(HandleIntToFloatCast(EltType, SrcType, Src.getComplexIntReal(), Info.Ctx), - HandleIntToFloatCast(EltType, SrcType, + HandleIntToFloatCast(EltType, SrcType, Src.getComplexIntImag(), Info.Ctx)); } else { return APValue(HandleIntToIntCast(EltType, SrcType, Src.getComplexIntReal(), Info.Ctx), - HandleIntToIntCast(EltType, SrcType, + HandleIntToIntCast(EltType, SrcType, Src.getComplexIntImag(), - Info.Ctx)); + Info.Ctx)); } } } @@ -1657,7 +1675,7 @@ public: // FIXME: Handle more casts. return APValue(); } - + APValue VisitBinaryOperator(const BinaryOperator *E); APValue VisitChooseExpr(const ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } @@ -1668,23 +1686,21 @@ public: }; } // end anonymous namespace -static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info) -{ +static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info) { Result = ComplexExprEvaluator(Info).Visit(const_cast(E)); assert((!Result.isComplexFloat() || - (&Result.getComplexFloatReal().getSemantics() == - &Result.getComplexFloatImag().getSemantics())) && + (&Result.getComplexFloatReal().getSemantics() == + &Result.getComplexFloatImag().getSemantics())) && "Invalid complex evaluation."); return Result.isComplexFloat() || Result.isComplexInt(); } -APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) -{ +APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { APValue Result, RHS; - + if (!EvaluateComplex(E->getLHS(), Result, Info)) return APValue(); - + if (!EvaluateComplex(E->getRHS(), RHS, Info)) return APValue(); @@ -1721,7 +1737,7 @@ APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) APFloat &LHS_i = LHS.getComplexFloatImag(); APFloat &RHS_r = RHS.getComplexFloatReal(); APFloat &RHS_i = RHS.getComplexFloatImag(); - + APFloat Tmp = LHS_r; Tmp.multiply(RHS_r, APFloat::rmNearestTiesToEven); Result.getComplexFloatReal() = Tmp; @@ -1737,10 +1753,10 @@ APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) Result.getComplexFloatImag().add(Tmp, APFloat::rmNearestTiesToEven); } else { APValue LHS = Result; - Result.getComplexIntReal() = + Result.getComplexIntReal() = (LHS.getComplexIntReal() * RHS.getComplexIntReal() - LHS.getComplexIntImag() * RHS.getComplexIntImag()); - Result.getComplexIntImag() = + Result.getComplexIntImag() = (LHS.getComplexIntReal() * RHS.getComplexIntImag() + LHS.getComplexIntImag() * RHS.getComplexIntReal()); } @@ -1774,7 +1790,7 @@ bool Expr::Evaluate(EvalResult &Result, ASTContext &Ctx) const { llvm::APFloat f(0.0); if (!EvaluateFloat(this, f, Info)) return false; - + Result.Val = APValue(f); } else if (getType()->isAnyComplexType()) { if (!EvaluateComplex(this, Result.Val, Info)) @@ -1791,6 +1807,12 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const { return EvaluateLValue(this, Result.Val, Info) && !Result.HasSideEffects; } +bool Expr::EvaluateAsAnyLValue(EvalResult &Result, ASTContext &Ctx) const { + EvalInfo Info(Ctx, Result, true); + + return EvaluateLValue(this, Result.Val, Info) && !Result.HasSideEffects; +} + /// isEvaluatable - Call Evaluate to see if this expression can be constant /// folded, but discard the result. bool Expr::isEvaluatable(ASTContext &Ctx) const { diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp index dd2fc14ab2a4..c47a9dadbadd 100644 --- a/lib/AST/InheritViz.cpp +++ b/lib/AST/InheritViz.cpp @@ -89,8 +89,8 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) { Out << " \"];\n"; // Display the base classes. - const CXXRecordDecl *Decl - = static_cast(Type->getAsRecordType()->getDecl()); + const CXXRecordDecl *Decl + = static_cast(Type->getAs()->getDecl()); for (CXXRecordDecl::base_class_const_iterator Base = Decl->bases_begin(); Base != Decl->bases_end(); ++Base) { QualType CanonBaseType = Context.getCanonicalType(Base->getType()); @@ -120,8 +120,8 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) { /// WriteNodeReference - Write out a reference to the given node, /// using a unique identifier for each direct base and for the /// (only) virtual base. -llvm::raw_ostream& -InheritanceHierarchyWriter::WriteNodeReference(QualType Type, +llvm::raw_ostream& +InheritanceHierarchyWriter::WriteNodeReference(QualType Type, bool FromVirtual) { QualType CanonType = Context.getCanonicalType(Type); @@ -149,7 +149,7 @@ void CXXRecordDecl::viewInheritance(ASTContext& Context) const { llvm::errs() << "Writing '" << Filename.c_str() << "'... "; - llvm::raw_fd_ostream O(Filename.c_str(), false, ErrMsg); + llvm::raw_fd_ostream O(Filename.c_str(), ErrMsg); if (ErrMsg.empty()) { InheritanceHierarchyWriter Writer(Context, O); diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp index 90ec4d33fdfe..d969776aa0ee 100644 --- a/lib/AST/NestedNameSpecifier.cpp +++ b/lib/AST/NestedNameSpecifier.cpp @@ -22,13 +22,13 @@ using namespace clang; NestedNameSpecifier * -NestedNameSpecifier::FindOrInsert(ASTContext &Context, +NestedNameSpecifier::FindOrInsert(ASTContext &Context, const NestedNameSpecifier &Mockup) { llvm::FoldingSetNodeID ID; Mockup.Profile(ID); void *InsertPos = 0; - NestedNameSpecifier *NNS + NestedNameSpecifier *NNS = Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos); if (!NNS) { NNS = new (Context, 4) NestedNameSpecifier(Mockup); @@ -39,10 +39,10 @@ NestedNameSpecifier::FindOrInsert(ASTContext &Context, } NestedNameSpecifier * -NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, +NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, IdentifierInfo *II) { assert(II && "Identifier cannot be NULL"); - assert(Prefix && Prefix->isDependent() && "Prefix must be dependent"); + assert((!Prefix || Prefix->isDependent()) && "Prefix must be dependent"); NestedNameSpecifier Mockup; Mockup.Prefix.setPointer(Prefix); @@ -52,10 +52,10 @@ NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, } NestedNameSpecifier * -NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, +NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, NamespaceDecl *NS) { assert(NS && "Namespace cannot be NULL"); - assert((!Prefix || + assert((!Prefix || (Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) && "Broken nested name specifier"); NestedNameSpecifier Mockup; @@ -75,7 +75,17 @@ NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, Mockup.Specifier = T; return FindOrInsert(Context, Mockup); } - + +NestedNameSpecifier * +NestedNameSpecifier::Create(ASTContext &Context, IdentifierInfo *II) { + assert(II && "Identifier cannot be NULL"); + NestedNameSpecifier Mockup; + Mockup.Prefix.setPointer(0); + Mockup.Prefix.setInt(Identifier); + Mockup.Specifier = II; + return FindOrInsert(Context, Mockup); +} + NestedNameSpecifier *NestedNameSpecifier::GlobalSpecifier(ASTContext &Context) { if (!Context.GlobalNestedNameSpecifier) Context.GlobalNestedNameSpecifier = new (Context, 4) NestedNameSpecifier(); @@ -105,8 +115,8 @@ bool NestedNameSpecifier::isDependent() const { /// \brief Print this nested name specifier to the given output /// stream. -void -NestedNameSpecifier::print(llvm::raw_ostream &OS, +void +NestedNameSpecifier::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const { if (getPrefix()) getPrefix()->print(OS, Policy); @@ -131,15 +141,34 @@ NestedNameSpecifier::print(llvm::raw_ostream &OS, std::string TypeStr; Type *T = getAsType(); - // If this is a qualified name type, suppress the qualification: - // it's part of our nested-name-specifier sequence anyway. FIXME: - // We should be able to assert that this doesn't happen. - if (const QualifiedNameType *QualT = dyn_cast(T)) - T = QualT->getNamedType().getTypePtr(); - PrintingPolicy InnerPolicy(Policy); InnerPolicy.SuppressTagKind = true; - T->getAsStringInternal(TypeStr, InnerPolicy); + InnerPolicy.SuppressScope = true; + + // Nested-name-specifiers are intended to contain minimally-qualified + // types. An actual QualifiedNameType will not occur, since we'll store + // just the type that is referred to in the nested-name-specifier (e.g., + // a TypedefType, TagType, etc.). However, when we are dealing with + // dependent template-id types (e.g., Outer::template Inner), + // the type requires its own nested-name-specifier for uniqueness, so we + // suppress that nested-name-specifier during printing. + assert(!isa(T) && + "Qualified name type in nested-name-specifier"); + if (const TemplateSpecializationType *SpecType + = dyn_cast(T)) { + // Print the template name without its corresponding + // nested-name-specifier. + SpecType->getTemplateName().print(OS, InnerPolicy, true); + + // Print the template argument list. + TypeStr = TemplateSpecializationType::PrintTemplateArgumentList( + SpecType->getArgs(), + SpecType->getNumArgs(), + InnerPolicy); + } else { + // Print the type normally + T->getAsStringInternal(TypeStr, InnerPolicy); + } OS << TypeStr; break; } diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp index 9d87daa0bfd8..48251d52fd2a 100644 --- a/lib/AST/ParentMap.cpp +++ b/lib/AST/ParentMap.cpp @@ -32,7 +32,7 @@ ParentMap::ParentMap(Stmt* S) : Impl(0) { if (S) { MapTy *M = new MapTy(); BuildParentMap(*M, S); - Impl = M; + Impl = M; } } @@ -54,16 +54,16 @@ Stmt *ParentMap::getParentIgnoreParens(Stmt *S) const { bool ParentMap::isConsumedExpr(Expr* E) const { Stmt *P = getParent(E); Stmt *DirectChild = E; - + // Ignore parents that are parentheses or casts. while (P && (isa(P) || isa(P))) { DirectChild = P; P = getParent(P); } - + if (!P) return false; - + switch (P->getStmtClass()) { default: return isa(P); @@ -78,7 +78,7 @@ bool ParentMap::isConsumedExpr(Expr* E) const { case Stmt::ForStmtClass: return DirectChild == cast(P)->getCond(); case Stmt::WhileStmtClass: - return DirectChild == cast(P)->getCond(); + return DirectChild == cast(P)->getCond(); case Stmt::DoStmtClass: return DirectChild == cast(P)->getCond(); case Stmt::IfStmtClass: diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp new file mode 100644 index 000000000000..c79cc3c1dbb1 --- /dev/null +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -0,0 +1,674 @@ +//=== ASTRecordLayoutBuilder.cpp - Helper class for building record layouts ==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "RecordLayoutBuilder.h" + +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "clang/AST/RecordLayout.h" +#include "clang/Basic/TargetInfo.h" +#include +#include + +using namespace clang; + +ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx) + : Ctx(Ctx), Size(0), Alignment(8), Packed(false), MaxFieldAlignment(0), + DataSize(0), IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8), + PrimaryBase(0), PrimaryBaseWasVirtual(false) {} + +/// LayoutVtable - Lay out the vtable and set PrimaryBase. +void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) { + if (!RD->isDynamicClass()) { + // There is no primary base in this case. + return; + } + + SelectPrimaryBase(RD); + if (PrimaryBase == 0) { + int AS = 0; + UpdateAlignment(Ctx.Target.getPointerAlign(AS)); + Size += Ctx.Target.getPointerWidth(AS); + DataSize = Size; + } +} + +void +ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + if (!i->isVirtual()) { + const CXXRecordDecl *Base = + cast(i->getType()->getAs()->getDecl()); + // Skip the PrimaryBase here, as it is laid down first. + if (Base != PrimaryBase || PrimaryBaseWasVirtual) + LayoutBaseNonVirtually(Base, false); + } + } +} + +// Helper routines related to the abi definition from: +// http://www.codesourcery.com/public/cxx-abi/abi.html +// +/// IsNearlyEmpty - Indicates when a class has a vtable pointer, but +/// no other data. +bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const { + // FIXME: Audit the corners + if (!RD->isDynamicClass()) + return false; + const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); + if (BaseInfo.getNonVirtualSize() == Ctx.Target.getPointerWidth(0)) + return true; + return false; +} + +void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) { + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + + // If the record has a primary base class that is virtual, add it to the set + // of primary bases. + if (Layout.getPrimaryBaseWasVirtual()) + IndirectPrimaryBases.insert(Layout.getPrimaryBase()); + + // Now traverse all bases and find primary bases for them. + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast(i->getType()->getAs()->getDecl()); + + // Only bases with virtual bases participate in computing the + // indirect primary virtual base classes. + if (Base->getNumVBases()) + IdentifyPrimaryBases(Base); + } +} + +void +ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD, + const CXXRecordDecl *&FirstPrimary) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast(i->getType()->getAs()->getDecl()); + if (!i->isVirtual()) { + SelectPrimaryVBase(Base, FirstPrimary); + if (PrimaryBase) + return; + continue; + } + if (IsNearlyEmpty(Base)) { + if (FirstPrimary==0) + FirstPrimary = Base; + if (!IndirectPrimaryBases.count(Base)) { + setPrimaryBase(Base, true); + return; + } + } + } +} + +/// SelectPrimaryBase - Selects the primary base for the given class and +/// record that with setPrimaryBase. We also calculate the IndirectPrimaries. +void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) { + // Compute all the primary virtual bases for all of our direct and + // indirect bases, and record all their primary virtual base classes. + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast(i->getType()->getAs()->getDecl()); + IdentifyPrimaryBases(Base); + } + + // If the record has a dynamic base class, attempt to choose a primary base + // class. It is the first (in direct base class order) non-virtual dynamic + // base class, if one exists. + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + if (!i->isVirtual()) { + const CXXRecordDecl *Base = + cast(i->getType()->getAs()->getDecl()); + if (Base->isDynamicClass()) { + // We found it. + setPrimaryBase(Base, false); + return; + } + } + } + + // Otherwise, it is the first nearly empty virtual base that is not an + // indirect primary virtual base class, if one exists. + + // If we have no virtual bases at this point, bail out as the searching below + // is expensive. + if (RD->getNumVBases() == 0) + return; + + // Then we can search for the first nearly empty virtual base itself. + const CXXRecordDecl *FirstPrimary = 0; + SelectPrimaryVBase(RD, FirstPrimary); + + // Otherwise if is the first nearly empty virtual base, if one exists, + // otherwise there is no primary base class. + if (!PrimaryBase) + setPrimaryBase(FirstPrimary, true); +} + +void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) { + LayoutBaseNonVirtually(RD, true); +} + +void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, + const CXXRecordDecl *PB, + int64_t Offset, + llvm::SmallSet &mark, + llvm::SmallSet &IndirectPrimary) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast(i->getType()->getAs()->getDecl()); +#if 0 + const ASTRecordLayout &L = Ctx.getASTRecordLayout(Base); + const CXXRecordDecl *PB = L.getPrimaryBase(); + if (PB && L.getPrimaryBaseWasVirtual() + && IndirectPrimary.count(PB)) { + int64_t BaseOffset; + // FIXME: calculate this. + BaseOffset = (1<<63) | (1<<31); + VBases.push_back(PB); + VBaseOffsets.push_back(BaseOffset); + } +#endif + int64_t BaseOffset = Offset;; + // FIXME: Calculate BaseOffset. + if (i->isVirtual()) { + if (Base == PB) { + // Only lay things out once. + if (mark.count(Base)) + continue; + // Mark it so we don't lay it out twice. + mark.insert(Base); + assert (IndirectPrimary.count(Base) && "IndirectPrimary was wrong"); + VBases.push_back(std::make_pair(Base, Offset)); + } else if (IndirectPrimary.count(Base)) { + // Someone else will eventually lay this out. + ; + } else { + // Only lay things out once. + if (mark.count(Base)) + continue; + // Mark it so we don't lay it out twice. + mark.insert(Base); + LayoutVirtualBase(Base); + BaseOffset = VBases.back().second; + } + } + if (Base->getNumVBases()) { + const ASTRecordLayout &L = Ctx.getASTRecordLayout(Base); + const CXXRecordDecl *PB = L.getPrimaryBase(); + LayoutVirtualBases(Base, PB, BaseOffset, mark, IndirectPrimary); + } + } +} + +bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, + uint64_t Offset) const { + // Look for an empty class with the same type at the same offset. + for (EmptyClassOffsetsTy::const_iterator I = + EmptyClassOffsets.lower_bound(Offset), + E = EmptyClassOffsets.upper_bound(Offset); I != E; ++I) { + + if (I->second == RD) + return false; + } + + const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); + + // Check bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (I->isVirtual()) + continue; + + const CXXRecordDecl *Base = + cast(I->getType()->getAs()->getDecl()); + + uint64_t BaseClassOffset = Info.getBaseClassOffset(Base); + + if (!canPlaceRecordAtOffset(Base, Offset + BaseClassOffset)) + return false; + } + + // Check fields. + unsigned FieldNo = 0; + for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + I != E; ++I, ++FieldNo) { + const FieldDecl *FD = *I; + + uint64_t FieldOffset = Info.getFieldOffset(FieldNo); + + if (!canPlaceFieldAtOffset(FD, Offset + FieldOffset)) + return false; + } + + // FIXME: virtual bases. + return true; +} + +bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD, + uint64_t Offset) const { + QualType T = FD->getType(); + if (const RecordType *RT = T->getAs()) { + if (const CXXRecordDecl *RD = dyn_cast(RT->getDecl())) + return canPlaceRecordAtOffset(RD, Offset); + } + + if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) { + QualType ElemTy = Ctx.getBaseElementType(AT); + const RecordType *RT = ElemTy->getAs(); + if (!RT) + return true; + const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); + if (!RD) + return true; + + const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); + + uint64_t NumElements = Ctx.getConstantArrayElementCount(AT); + unsigned ElementOffset = Offset; + for (uint64_t I = 0; I != NumElements; ++I) { + if (!canPlaceRecordAtOffset(RD, ElementOffset)) + return false; + + ElementOffset += Info.getSize(); + } + } + + return true; +} + +void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD, + uint64_t Offset) { + if (RD->isEmpty()) + EmptyClassOffsets.insert(std::make_pair(Offset, RD)); + + const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); + + // Update bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (I->isVirtual()) + continue; + + const CXXRecordDecl *Base = + cast(I->getType()->getAs()->getDecl()); + + uint64_t BaseClassOffset = Info.getBaseClassOffset(Base); + UpdateEmptyClassOffsets(Base, Offset + BaseClassOffset); + } + + // Update fields. + unsigned FieldNo = 0; + for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + I != E; ++I, ++FieldNo) { + const FieldDecl *FD = *I; + + uint64_t FieldOffset = Info.getFieldOffset(FieldNo); + UpdateEmptyClassOffsets(FD, Offset + FieldOffset); + } + + // FIXME: Update virtual bases. +} + +void +ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD, + uint64_t Offset) { + QualType T = FD->getType(); + + if (const RecordType *RT = T->getAs()) { + if (const CXXRecordDecl *RD = dyn_cast(RT->getDecl())) { + UpdateEmptyClassOffsets(RD, Offset); + return; + } + } + + if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) { + QualType ElemTy = Ctx.getBaseElementType(AT); + const RecordType *RT = ElemTy->getAs(); + if (!RT) + return; + const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); + if (!RD) + return; + + const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); + + uint64_t NumElements = Ctx.getConstantArrayElementCount(AT); + unsigned ElementOffset = Offset; + + for (uint64_t I = 0; I != NumElements; ++I) { + UpdateEmptyClassOffsets(RD, ElementOffset); + ElementOffset += Info.getSize(); + } + } +} + +uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { + const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); + + // If we have an empty base class, try to place it at offset 0. + if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) { + // We were able to place the class at offset 0. + UpdateEmptyClassOffsets(RD, 0); + + Size = std::max(Size, BaseInfo.getSize()); + + return 0; + } + + unsigned BaseAlign = BaseInfo.getNonVirtualAlign(); + + // Round up the current record size to the base's alignment boundary. + uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign); + + // Try to place the base. + while (true) { + if (canPlaceRecordAtOffset(RD, Offset)) + break; + + Offset += BaseAlign; + } + + if (!RD->isEmpty()) { + // Update the data size. + DataSize = Offset + BaseInfo.getNonVirtualSize(); + + Size = std::max(Size, DataSize); + } else + Size = std::max(Size, Offset + BaseInfo.getSize()); + + // Remember max struct/class alignment. + UpdateAlignment(BaseAlign); + + UpdateEmptyClassOffsets(RD, Offset); + return Offset; +} + +void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD, + bool IsVirtualBase) { + // Layout the base. + unsigned Offset = LayoutBase(RD); + + // Add base class offsets. + if (IsVirtualBase) + VBases.push_back(std::make_pair(RD, Offset)); + else + Bases.push_back(std::make_pair(RD, Offset)); + +#if 0 + // And now add offsets for all our primary virtual bases as well, so + // they all have offsets. + const ASTRecordLayout *L = &BaseInfo; + const CXXRecordDecl *PB = L->getPrimaryBase(); + while (PB) { + if (L->getPrimaryBaseWasVirtual()) { + VBases.push_back(PB); + VBaseOffsets.push_back(Size); + } + PB = L->getPrimaryBase(); + if (PB) + L = &Ctx.getASTRecordLayout(PB); + } +#endif +} + +void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { + IsUnion = D->isUnion(); + + Packed = D->hasAttr(); + + // The #pragma pack attribute specifies the maximum field alignment. + if (const PragmaPackAttr *PPA = D->getAttr()) + MaxFieldAlignment = PPA->getAlignment(); + + if (const AlignedAttr *AA = D->getAttr()) + UpdateAlignment(AA->getAlignment()); + + // If this is a C++ class, lay out the vtable and the non-virtual bases. + const CXXRecordDecl *RD = dyn_cast(D); + if (RD) { + LayoutVtable(RD); + // PrimaryBase goes first. + if (PrimaryBase) { + if (PrimaryBaseWasVirtual) + IndirectPrimaryBases.insert(PrimaryBase); + LayoutBaseNonVirtually(PrimaryBase, PrimaryBaseWasVirtual); + } + LayoutNonVirtualBases(RD); + } + + LayoutFields(D); + + NonVirtualSize = Size; + NonVirtualAlignment = Alignment; + + if (RD) { + llvm::SmallSet mark; + LayoutVirtualBases(RD, PrimaryBase, 0, mark, IndirectPrimaryBases); + } + + // Finally, round the size of the total struct up to the alignment of the + // struct itself. + FinishLayout(); +} + +void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D, + const ObjCImplementationDecl *Impl) { + if (ObjCInterfaceDecl *SD = D->getSuperClass()) { + const ASTRecordLayout &SL = Ctx.getASTObjCInterfaceLayout(SD); + + UpdateAlignment(SL.getAlignment()); + + // We start laying out ivars not at the end of the superclass + // structure, but at the next byte following the last field. + Size = llvm::RoundUpToAlignment(SL.getDataSize(), 8); + DataSize = Size; + } + + Packed = D->hasAttr(); + + // The #pragma pack attribute specifies the maximum field alignment. + if (const PragmaPackAttr *PPA = D->getAttr()) + MaxFieldAlignment = PPA->getAlignment(); + + if (const AlignedAttr *AA = D->getAttr()) + UpdateAlignment(AA->getAlignment()); + + // Layout each ivar sequentially. + llvm::SmallVector Ivars; + Ctx.ShallowCollectObjCIvars(D, Ivars, Impl); + for (unsigned i = 0, e = Ivars.size(); i != e; ++i) + LayoutField(Ivars[i]); + + // Finally, round the size of the total struct up to the alignment of the + // struct itself. + FinishLayout(); +} + +void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { + // Layout each field, for now, just sequentially, respecting alignment. In + // the future, this will need to be tweakable by targets. + for (RecordDecl::field_iterator Field = D->field_begin(), + FieldEnd = D->field_end(); Field != FieldEnd; ++Field) + LayoutField(*Field); +} + +void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { + bool FieldPacked = Packed; + uint64_t FieldOffset = IsUnion ? 0 : DataSize; + uint64_t FieldSize; + unsigned FieldAlign; + + FieldPacked |= D->hasAttr(); + + if (const Expr *BitWidthExpr = D->getBitWidth()) { + // TODO: Need to check this algorithm on other targets! + // (tested on Linux-X86) + FieldSize = BitWidthExpr->EvaluateAsInt(Ctx).getZExtValue(); + + std::pair FieldInfo = Ctx.getTypeInfo(D->getType()); + uint64_t TypeSize = FieldInfo.first; + + FieldAlign = FieldInfo.second; + + if (FieldPacked) + FieldAlign = 1; + if (const AlignedAttr *AA = D->getAttr()) + FieldAlign = std::max(FieldAlign, AA->getAlignment()); + // The maximum field alignment overrides the aligned attribute. + if (MaxFieldAlignment) + FieldAlign = std::min(FieldAlign, MaxFieldAlignment); + + // Check if we need to add padding to give the field the correct + // alignment. + if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize) + FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); + + // Padding members don't affect overall alignment + if (!D->getIdentifier()) + FieldAlign = 1; + } else { + if (D->getType()->isIncompleteArrayType()) { + // This is a flexible array member; we can't directly + // query getTypeInfo about these, so we figure it out here. + // Flexible array members don't have any size, but they + // have to be aligned appropriately for their element type. + FieldSize = 0; + const ArrayType* ATy = Ctx.getAsArrayType(D->getType()); + FieldAlign = Ctx.getTypeAlign(ATy->getElementType()); + } else if (const ReferenceType *RT = D->getType()->getAs()) { + unsigned AS = RT->getPointeeType().getAddressSpace(); + FieldSize = Ctx.Target.getPointerWidth(AS); + FieldAlign = Ctx.Target.getPointerAlign(AS); + } else { + std::pair FieldInfo = Ctx.getTypeInfo(D->getType()); + FieldSize = FieldInfo.first; + FieldAlign = FieldInfo.second; + } + + if (FieldPacked) + FieldAlign = 8; + if (const AlignedAttr *AA = D->getAttr()) + FieldAlign = std::max(FieldAlign, AA->getAlignment()); + // The maximum field alignment overrides the aligned attribute. + if (MaxFieldAlignment) + FieldAlign = std::min(FieldAlign, MaxFieldAlignment); + + // Round up the current record size to the field's alignment boundary. + FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign); + + if (!IsUnion) { + while (true) { + // Check if we can place the field at this offset. + if (canPlaceFieldAtOffset(D, FieldOffset)) + break; + + // We couldn't place the field at the offset. Try again at a new offset. + FieldOffset += FieldAlign; + } + + UpdateEmptyClassOffsets(D, FieldOffset); + } + } + + // Place this field at the current location. + FieldOffsets.push_back(FieldOffset); + + // Reserve space for this field. + if (IsUnion) + Size = std::max(Size, FieldSize); + else + Size = FieldOffset + FieldSize; + + // Update the data size. + DataSize = Size; + + // Remember max struct/class alignment. + UpdateAlignment(FieldAlign); +} + +void ASTRecordLayoutBuilder::FinishLayout() { + // In C++, records cannot be of size 0. + if (Ctx.getLangOptions().CPlusPlus && Size == 0) + Size = 8; + // Finally, round the size of the record up to the alignment of the + // record itself. + Size = (Size + (Alignment-1)) & ~(Alignment-1); +} + +void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) { + if (NewAlignment <= Alignment) + return; + + assert(llvm::isPowerOf2_32(NewAlignment && "Alignment not a power of 2")); + + Alignment = NewAlignment; +} + +const ASTRecordLayout * +ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, + const RecordDecl *D) { + ASTRecordLayoutBuilder Builder(Ctx); + + Builder.Layout(D); + + if (!isa(D)) + return new ASTRecordLayout(Builder.Size, Builder.Alignment, Builder.Size, + Builder.FieldOffsets.data(), + Builder.FieldOffsets.size()); + + // FIXME: This is not always correct. See the part about bitfields at + // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info. + // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout. + bool IsPODForThePurposeOfLayout = cast(D)->isPOD(); + + // FIXME: This should be done in FinalizeLayout. + uint64_t DataSize = + IsPODForThePurposeOfLayout ? Builder.Size : Builder.DataSize; + uint64_t NonVirtualSize = + IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize; + + return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize, + Builder.FieldOffsets.data(), + Builder.FieldOffsets.size(), + NonVirtualSize, + Builder.NonVirtualAlignment, + Builder.PrimaryBase, + Builder.PrimaryBaseWasVirtual, + Builder.Bases.data(), + Builder.Bases.size(), + Builder.VBases.data(), + Builder.VBases.size()); +} + +const ASTRecordLayout * +ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, + const ObjCInterfaceDecl *D, + const ObjCImplementationDecl *Impl) { + ASTRecordLayoutBuilder Builder(Ctx); + + Builder.Layout(D, Impl); + + return new ASTRecordLayout(Builder.Size, Builder.Alignment, + Builder.DataSize, + Builder.FieldOffsets.data(), + Builder.FieldOffsets.size()); +} diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h new file mode 100644 index 000000000000..6e4cdd2fe2ee --- /dev/null +++ b/lib/AST/RecordLayoutBuilder.h @@ -0,0 +1,146 @@ +//===- ASTRecordLayoutBuilder.h - Helper class for building record layouts ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H +#define LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/Support/DataTypes.h" +#include + +namespace clang { + class ASTContext; + class ASTRecordLayout; + class CXXRecordDecl; + class FieldDecl; + class ObjCImplementationDecl; + class ObjCInterfaceDecl; + class RecordDecl; + +class ASTRecordLayoutBuilder { + ASTContext &Ctx; + + uint64_t Size; + unsigned Alignment; + llvm::SmallVector FieldOffsets; + + /// Packed - Whether the record is packed or not. + bool Packed; + + /// MaxFieldAlignment - The maximum allowed field alignment. This is set by + /// #pragma pack. + unsigned MaxFieldAlignment; + + /// DataSize - The data size of the record being laid out. + uint64_t DataSize; + + bool IsUnion; + + uint64_t NonVirtualSize; + unsigned NonVirtualAlignment; + const CXXRecordDecl *PrimaryBase; + bool PrimaryBaseWasVirtual; + + typedef llvm::SmallVector, 4> BaseOffsetsTy; + + /// Bases - base classes and their offsets from the record. + BaseOffsetsTy Bases; + + // VBases - virtual base classes and their offsets from the record. + BaseOffsetsTy VBases; + + /// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are + /// primary base classes for some other direct or indirect base class. + llvm::SmallSet IndirectPrimaryBases; + + /// EmptyClassOffsets - A map from offsets to empty record decls. + typedef std::multimap EmptyClassOffsetsTy; + EmptyClassOffsetsTy EmptyClassOffsets; + + ASTRecordLayoutBuilder(ASTContext &Ctx); + + void Layout(const RecordDecl *D); + void Layout(const CXXRecordDecl *D); + void Layout(const ObjCInterfaceDecl *D, + const ObjCImplementationDecl *Impl); + + void LayoutFields(const RecordDecl *D); + void LayoutField(const FieldDecl *D); + + void SelectPrimaryBase(const CXXRecordDecl *RD); + void SelectPrimaryVBase(const CXXRecordDecl *RD, + const CXXRecordDecl *&FirstPrimary); + + /// IdentifyPrimaryBases - Identify all virtual base classes, direct or + /// indirect, that are primary base classes for some other direct or indirect + /// base class. + void IdentifyPrimaryBases(const CXXRecordDecl *RD); + + void setPrimaryBase(const CXXRecordDecl *PB, bool Virtual) { + PrimaryBase = PB; + PrimaryBaseWasVirtual = Virtual; + } + + bool IsNearlyEmpty(const CXXRecordDecl *RD) const; + + /// LayoutBase - Will lay out a base and return the offset where it was + /// placed, in bits. + uint64_t LayoutBase(const CXXRecordDecl *RD); + + void LayoutVtable(const CXXRecordDecl *RD); + void LayoutNonVirtualBases(const CXXRecordDecl *RD); + void LayoutBaseNonVirtually(const CXXRecordDecl *RD, bool IsVBase); + void LayoutVirtualBase(const CXXRecordDecl *RD); + void LayoutVirtualBases(const CXXRecordDecl *RD, const CXXRecordDecl *PB, + int64_t Offset, + llvm::SmallSet &mark, + llvm::SmallSet &IndirectPrimary); + + /// canPlaceRecordAtOffset - Return whether a record (either a base class + /// or a field) can be placed at the given offset. + /// Returns false if placing the record will result in two components + /// (direct or indirect) of the same type having the same offset. + bool canPlaceRecordAtOffset(const CXXRecordDecl *RD, uint64_t Offset) const; + + /// canPlaceFieldAtOffset - Return whether a field can be placed at the given + /// offset. + bool canPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) const; + + /// UpdateEmptyClassOffsets - Called after a record (either a base class + /// or a field) has been placed at the given offset. Will update the + /// EmptyClassOffsets map if the class is empty or has any empty bases or + /// fields. + void UpdateEmptyClassOffsets(const CXXRecordDecl *RD, uint64_t Offset); + + /// UpdateEmptyClassOffsets - Called after a field has been placed at the + /// given offset. + void UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset); + + /// FinishLayout - Finalize record layout. Adjust record size based on the + /// alignment. + void FinishLayout(); + + void UpdateAlignment(unsigned NewAlignment); + + ASTRecordLayoutBuilder(const ASTRecordLayoutBuilder&); // DO NOT IMPLEMENT + void operator=(const ASTRecordLayoutBuilder&); // DO NOT IMPLEMENT +public: + static const ASTRecordLayout *ComputeLayout(ASTContext &Ctx, + const RecordDecl *RD); + static const ASTRecordLayout *ComputeLayout(ASTContext &Ctx, + const ObjCInterfaceDecl *D, + const ObjCImplementationDecl *Impl); +}; + +} // end namespace clang + +#endif + diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 17577910d2a3..3a838fadafa4 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -19,6 +19,7 @@ #include "clang/AST/Type.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" +#include using namespace clang; static struct StmtClassNameTable { @@ -43,7 +44,7 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) { } const char *Stmt::getStmtClassName() const { - return getStmtInfoTableEntry(sClass).Name; + return getStmtInfoTableEntry((StmtClass)sClass).Name; } void Stmt::DestroyChildren(ASTContext &C) { @@ -51,19 +52,12 @@ void Stmt::DestroyChildren(ASTContext &C) { if (Stmt* Child = *I++) Child->Destroy(C); } -void Stmt::Destroy(ASTContext &C) { +void Stmt::DoDestroy(ASTContext &C) { DestroyChildren(C); - // FIXME: Eventually all Stmts should be allocated with the allocator - // in ASTContext, just like with Decls. this->~Stmt(); C.Deallocate((void *)this); } -void DeclStmt::Destroy(ASTContext &C) { - this->~DeclStmt(); - C.Deallocate((void *)this); -} - void Stmt::PrintStats() { // Ensure the table is primed. getStmtInfoTableEntry(Stmt::NullStmtClass); @@ -99,16 +93,18 @@ bool Stmt::CollectingStats(bool enable) { return StatSwitch; } -NullStmt* NullStmt::Clone(ASTContext &C) const { - return new (C) NullStmt(SemiLoc); -} - -ContinueStmt* ContinueStmt::Clone(ASTContext &C) const { - return new (C) ContinueStmt(ContinueLoc); -} +void SwitchStmt::DoDestroy(ASTContext &Ctx) { + // Destroy the SwitchCase statements in this switch. In the normal + // case, this loop will merely decrement the reference counts from + // the Retain() calls in addSwitchCase(); + SwitchCase *SC = FirstCase; + while (SC) { + SwitchCase *Next = SC->getNextSwitchCase(); + SC->Destroy(Ctx); + SC = Next; + } -BreakStmt* BreakStmt::Clone(ASTContext &C) const { - return new (C) BreakStmt(BreakLoc); + Stmt::DoDestroy(Ctx); } void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) { @@ -191,7 +187,7 @@ std::string AsmStmt::getInputConstraint(unsigned i) const { void AsmStmt::setOutputsAndInputs(unsigned NumOutputs, - unsigned NumInputs, + unsigned NumInputs, const std::string *Names, StringLiteral **Constraints, Stmt **Exprs) { @@ -200,7 +196,7 @@ void AsmStmt::setOutputsAndInputs(unsigned NumOutputs, this->Names.clear(); this->Names.insert(this->Names.end(), Names, Names + NumOutputs + NumInputs); this->Constraints.clear(); - this->Constraints.insert(this->Constraints.end(), + this->Constraints.insert(this->Constraints.end(), Constraints, Constraints + NumOutputs + NumInputs); this->Exprs.clear(); this->Exprs.insert(this->Exprs.end(), Exprs, Exprs + NumOutputs + NumInputs); @@ -211,13 +207,13 @@ void AsmStmt::setOutputsAndInputs(unsigned NumOutputs, /// This returns -1 if the operand name is invalid. int AsmStmt::getNamedOperand(const std::string &SymbolicName) const { unsigned NumPlusOperands = 0; - + // Check if this is an output operand. for (unsigned i = 0, e = getNumOutputs(); i != e; ++i) { if (getOutputName(i) == SymbolicName) return i; } - + for (unsigned i = 0, e = getNumInputs(); i != e; ++i) if (getInputName(i) == SymbolicName) return getNumOutputs() + NumPlusOperands + i; @@ -239,7 +235,7 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl&Pieces, const char *StrStart = getAsmString()->getStrData(); const char *StrEnd = StrStart + getAsmString()->getByteLength(); const char *CurPtr = StrStart; - + // "Simple" inline asms have no constraints or operands, just convert the asm // string to escape $'s. if (isSimple()) { @@ -261,7 +257,7 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl&Pieces, // CurStringPiece - The current string that we are building up as we scan the // asm string. std::string CurStringPiece; - + while (1) { // Done with the string? if (CurPtr == StrEnd) { @@ -269,7 +265,7 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl&Pieces, Pieces.push_back(AsmStringPiece(CurStringPiece)); return 0; } - + char CurChar = *CurPtr++; if (CurChar == '$') { CurStringPiece += "$$"; @@ -278,48 +274,48 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl&Pieces, CurStringPiece += CurChar; continue; } - + // Escaped "%" character in asm string. if (CurPtr == StrEnd) { // % at end of string is invalid (no escape). DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_escape; } - + char EscapedChar = *CurPtr++; if (EscapedChar == '%') { // %% -> % // Escaped percentage sign. CurStringPiece += '%'; continue; } - + if (EscapedChar == '=') { // %= -> Generate an unique ID. CurStringPiece += "${:uid}"; continue; } - + // Otherwise, we have an operand. If we have accumulated a string so far, // add it to the Pieces list. if (!CurStringPiece.empty()) { Pieces.push_back(AsmStringPiece(CurStringPiece)); CurStringPiece.clear(); } - + // Handle %x4 and %x[foo] by capturing x as the modifier character. char Modifier = '\0'; if (isalpha(EscapedChar)) { Modifier = EscapedChar; EscapedChar = *CurPtr++; } - + if (isdigit(EscapedChar)) { // %n - Assembler operand n unsigned N = 0; - + --CurPtr; while (CurPtr != StrEnd && isdigit(*CurPtr)) N = N*10 + ((*CurPtr++)-'0'); - + unsigned NumOperands = getNumOutputs() + getNumPlusOperands() + getNumInputs(); if (N >= NumOperands) { @@ -330,20 +326,20 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl&Pieces, Pieces.push_back(AsmStringPiece(N, Modifier)); continue; } - + // Handle %[foo], a symbolic operand reference. if (EscapedChar == '[') { DiagOffs = CurPtr-StrStart-1; - + // Find the ']'. const char *NameEnd = (const char*)memchr(CurPtr, ']', StrEnd-CurPtr); if (NameEnd == 0) return diag::err_asm_unterminated_symbolic_operand_name; if (NameEnd == CurPtr) return diag::err_asm_empty_symbolic_operand_name; - + std::string SymbolicName(CurPtr, NameEnd); - + int N = getNamedOperand(SymbolicName); if (N == -1) { // Verify that an operand with that name exists. @@ -351,11 +347,11 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl&Pieces, return diag::err_asm_unknown_symbolic_operand_name; } Pieces.push_back(AsmStringPiece(N, Modifier)); - + CurPtr = NameEnd+1; continue; } - + DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_escape; } @@ -513,7 +509,7 @@ Stmt::child_iterator ReturnStmt::child_end() { } // AsmStmt -Stmt::child_iterator AsmStmt::child_begin() { +Stmt::child_iterator AsmStmt::child_begin() { return Exprs.empty() ? 0 : &Exprs[0]; } Stmt::child_iterator AsmStmt::child_end() { @@ -569,10 +565,10 @@ QualType CXXCatchStmt::getCaughtType() { return QualType(); } -void CXXCatchStmt::Destroy(ASTContext& C) { +void CXXCatchStmt::DoDestroy(ASTContext& C) { if (ExceptionDecl) ExceptionDecl->Destroy(C); - Stmt::Destroy(C); + Stmt::DoDestroy(C); } // CXXTryStmt diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index bc096bf0d9f3..0465999a94cc 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -30,12 +30,12 @@ namespace { SourceManager *SM; FILE *F; unsigned IndentLevel; - + /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump /// the first few levels of an AST. This keeps track of how many ast levels /// are left. unsigned MaxDepth; - + /// LastLocFilename/LastLocLine - Keep track of the last location we print /// out so that we can print out deltas from then on out. const char *LastLocFilename; @@ -47,18 +47,18 @@ namespace { LastLocFilename = ""; LastLocLine = ~0U; } - + void DumpSubTree(Stmt *S) { // Prune the recursion if not using dump all. if (MaxDepth == 0) return; - + ++IndentLevel; if (S) { if (DeclStmt* DS = dyn_cast(S)) VisitDeclStmt(DS); - else { + else { Visit(S); - + // Print out children. Stmt::child_iterator CI = S->child_begin(), CE = S->child_end(); if (CI != CE) { @@ -75,25 +75,22 @@ namespace { } --IndentLevel; } - + void DumpDeclarator(Decl *D); - + void Indent() const { for (int i = 0, e = IndentLevel; i < e; ++i) fprintf(F, " "); } - + void DumpType(QualType T) { fprintf(F, "'%s'", T.getAsString().c_str()); if (!T.isNull()) { - // If the type is directly a typedef, strip off typedefness to give at - // least one level of concreteness. - if (TypedefType *TDT = dyn_cast(T)) { - QualType Simplified = - TDT->LookThroughTypedefs().getQualifiedType(T.getCVRQualifiers()); + // If the type is sugared, also dump a (shallow) desugared type. + QualType Simplified = T.getDesugaredType(); + if (Simplified != T) fprintf(F, ":'%s'", Simplified.getAsString().c_str()); - } } } void DumpStmt(const Stmt *Node) { @@ -108,15 +105,16 @@ namespace { } void DumpSourceRange(const Stmt *Node); void DumpLocation(SourceLocation Loc); - + // Stmts. void VisitStmt(Stmt *Node); void VisitDeclStmt(DeclStmt *Node); void VisitLabelStmt(LabelStmt *Node); void VisitGotoStmt(GotoStmt *Node); - + // Exprs void VisitExpr(Expr *Node); + void VisitCastExpr(CastExpr *Node); void VisitDeclRefExpr(DeclRefExpr *Node); void VisitPredefinedExpr(PredefinedExpr *Node); void VisitCharacterLiteral(CharacterLiteral *Node); @@ -137,14 +135,19 @@ namespace { void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node); void VisitCXXThisExpr(CXXThisExpr *Node); void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node); - + void VisitCXXConstructExpr(CXXConstructExpr *Node); + void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node); + void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node); + void DumpCXXTemporary(CXXTemporary *Temporary); + // ObjC void VisitObjCEncodeExpr(ObjCEncodeExpr *Node); void VisitObjCMessageExpr(ObjCMessageExpr* Node); void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); void VisitObjCProtocolExpr(ObjCProtocolExpr *Node); void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node); - void VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node); + void VisitObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *Node); void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); void VisitObjCSuperExpr(ObjCSuperExpr *Node); }; @@ -156,7 +159,7 @@ namespace { void StmtDumper::DumpLocation(SourceLocation Loc) { SourceLocation SpellingLoc = SM->getSpellingLoc(Loc); - + if (SpellingLoc.isInvalid()) { fprintf(stderr, ""); return; @@ -182,11 +185,11 @@ void StmtDumper::DumpLocation(SourceLocation Loc) { void StmtDumper::DumpSourceRange(const Stmt *Node) { // Can't translate locations if a SourceManager isn't available. if (SM == 0) return; - + // TODO: If the parent expression is available, we can print a delta vs its // location. SourceRange R = Node->getSourceRange(); - + fprintf(stderr, " <"); DumpLocation(R.getBegin()); if (R.getBegin() != R.getEnd()) { @@ -194,7 +197,7 @@ void StmtDumper::DumpSourceRange(const Stmt *Node) { DumpLocation(R.getEnd()); } fprintf(stderr, ">"); - + // } @@ -220,15 +223,15 @@ void StmtDumper::DumpDeclarator(Decl *D) { // Emit storage class for vardecls. if (VarDecl *V = dyn_cast(VD)) { if (V->getStorageClass() != VarDecl::None) - fprintf(F, "%s ", + fprintf(F, "%s ", VarDecl::getStorageClassSpecifierString(V->getStorageClass())); } - + std::string Name = VD->getNameAsString(); - VD->getType().getAsStringInternal(Name, + VD->getType().getAsStringInternal(Name, PrintingPolicy(VD->getASTContext().getLangOptions())); fprintf(F, "%s", Name.c_str()); - + // If this is a vardecl with an initializer, emit it. if (VarDecl *V = dyn_cast(VD)) { if (V->getInit()) { @@ -293,32 +296,37 @@ void StmtDumper::VisitExpr(Expr *Node) { DumpExpr(Node); } +void StmtDumper::VisitCastExpr(CastExpr *Node) { + DumpExpr(Node); + fprintf(F, " <%s>", Node->getCastKindName()); +} + void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) { DumpExpr(Node); fprintf(F, " "); switch (Node->getDecl()->getKind()) { - case Decl::Function: fprintf(F,"FunctionDecl"); break; - case Decl::Var: fprintf(F,"Var"); break; - case Decl::ParmVar: fprintf(F,"ParmVar"); break; - case Decl::EnumConstant: fprintf(F,"EnumConstant"); break; - case Decl::Typedef: fprintf(F,"Typedef"); break; - case Decl::Record: fprintf(F,"Record"); break; - case Decl::Enum: fprintf(F,"Enum"); break; - case Decl::CXXRecord: fprintf(F,"CXXRecord"); break; - case Decl::ObjCInterface: fprintf(F,"ObjCInterface"); break; - case Decl::ObjCClass: fprintf(F,"ObjCClass"); break; - default: fprintf(F,"Decl"); break; + default: fprintf(F,"Decl"); break; + case Decl::Function: fprintf(F,"FunctionDecl"); break; + case Decl::Var: fprintf(F,"Var"); break; + case Decl::ParmVar: fprintf(F,"ParmVar"); break; + case Decl::EnumConstant: fprintf(F,"EnumConstant"); break; + case Decl::Typedef: fprintf(F,"Typedef"); break; + case Decl::Record: fprintf(F,"Record"); break; + case Decl::Enum: fprintf(F,"Enum"); break; + case Decl::CXXRecord: fprintf(F,"CXXRecord"); break; + case Decl::ObjCInterface: fprintf(F,"ObjCInterface"); break; + case Decl::ObjCClass: fprintf(F,"ObjCClass"); break; } - - fprintf(F, "='%s' %p", Node->getDecl()->getNameAsString().c_str(), + + fprintf(F, "='%s' %p", Node->getDecl()->getNameAsString().c_str(), (void*)Node->getDecl()); } void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { DumpExpr(Node); - fprintf(F, " %sDecl='%s' %p", Node->getDecl()->getDeclKindName(), + fprintf(F, " %sDecl='%s' %p", Node->getDecl()->getDeclKindName(), Node->getDecl()->getNameAsString().c_str(), (void*)Node->getDecl()); if (Node->isFreeIvar()) fprintf(F, " isFreeIvar"); @@ -359,7 +367,7 @@ void StmtDumper::VisitStringLiteral(StringLiteral *Str) { switch (char C = Str->getStrData()[i]) { default: if (isprint(C)) - fputc(C, F); + fputc(C, F); else fprintf(F, "\\%03o", C); break; @@ -390,7 +398,7 @@ void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { void StmtDumper::VisitMemberExpr(MemberExpr *Node) { DumpExpr(Node); fprintf(F, " %s%s %p", Node->isArrow() ? "->" : ".", - Node->getMemberDecl()->getNameAsString().c_str(), + Node->getMemberDecl()->getNameAsString().c_str(), (void*)Node->getMemberDecl()); } void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { @@ -431,8 +439,9 @@ void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { DumpExpr(Node); - fprintf(F, " %s<%s>", Node->getCastName(), - Node->getTypeAsWritten().getAsString().c_str()); + fprintf(F, " %s<%s> <%s>", Node->getCastName(), + Node->getTypeAsWritten().getAsString().c_str(), + Node->getCastKindName()); } void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { @@ -447,10 +456,37 @@ void StmtDumper::VisitCXXThisExpr(CXXThisExpr *Node) { void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { DumpExpr(Node); - fprintf(F, " functional cast to %s", + fprintf(F, " functional cast to %s", Node->getTypeAsWritten().getAsString().c_str()); } +void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) { + DumpExpr(Node); + if (Node->isElidable()) + fprintf(F, " elidable"); +} + +void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { + DumpExpr(Node); + fprintf(F, " "); + DumpCXXTemporary(Node->getTemporary()); +} + +void StmtDumper::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node) { + DumpExpr(Node); + ++IndentLevel; + for (unsigned i = 0, e = Node->getNumTemporaries(); i != e; ++i) { + fprintf(F, "\n"); + Indent(); + DumpCXXTemporary(Node->getTemporary(i)); + } + --IndentLevel; +} + +void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) { + fprintf(F, "(CXXTemporary %p)", (void *)Temporary); +} + //===----------------------------------------------------------------------===// // Obj-C Expressions //===----------------------------------------------------------------------===// @@ -464,21 +500,21 @@ void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) { void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { DumpExpr(Node); - + fprintf(F, " "); DumpType(Node->getEncodedType()); } void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { DumpExpr(Node); - + fprintf(F, " "); fprintf(F, "%s", Node->getSelector().getAsString().c_str()); } void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { DumpExpr(Node); - + fprintf(F, " "); fprintf(F, "%s", Node->getProtocol()->getNameAsString().c_str()); } @@ -486,16 +522,17 @@ void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { DumpExpr(Node); - fprintf(F, " Kind=PropertyRef Property=\"%s\"", + fprintf(F, " Kind=PropertyRef Property=\"%s\"", Node->getProperty()->getNameAsString().c_str()); } -void StmtDumper::VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node) { +void StmtDumper::VisitObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *Node) { DumpExpr(Node); - + ObjCMethodDecl *Getter = Node->getGetterMethod(); ObjCMethodDecl *Setter = Node->getSetterMethod(); - fprintf(F, " Kind=MethodRef Getter=\"%s\" Setter=\"%s\"", + fprintf(F, " Kind=MethodRef Getter=\"%s\" Setter=\"%s\"", Getter->getSelector().getAsString().c_str(), Setter ? Setter->getSelector().getAsString().c_str() : "(null)"); } diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp index 5c22e28894f9..4f62b66e257d 100644 --- a/lib/AST/StmtIterator.cpp +++ b/lib/AST/StmtIterator.cpp @@ -23,10 +23,10 @@ static inline VariableArrayType* FindVA(Type* t) { if (VariableArrayType* vat = dyn_cast(vt)) if (vat->getSizeExpr()) return vat; - + t = vt->getElementType().getTypePtr(); } - + return NULL; } @@ -39,20 +39,20 @@ void StmtIteratorBase::NextVA() { if (p) return; - + if (inDecl()) { - if (VarDecl* VD = dyn_cast(decl)) + if (VarDecl* VD = dyn_cast(decl)) if (VD->Init) return; - + NextDecl(); } else if (inDeclGroup()) { - if (VarDecl* VD = dyn_cast(*DGI)) + if (VarDecl* VD = dyn_cast(*DGI)) if (VD->Init) return; - - NextDecl(); + + NextDecl(); } else { assert (inSizeOfTypeVA()); @@ -63,10 +63,10 @@ void StmtIteratorBase::NextVA() { void StmtIteratorBase::NextDecl(bool ImmediateAdvance) { assert (getVAPtr() == NULL); - + if (inDecl()) { assert (decl); - + // FIXME: SIMPLIFY AWAY. if (ImmediateAdvance) decl = 0; @@ -75,10 +75,10 @@ void StmtIteratorBase::NextDecl(bool ImmediateAdvance) { } else { assert (inDeclGroup()); - + if (ImmediateAdvance) ++DGI; - + for ( ; DGI != DGE; ++DGI) if (HandleDecl(*DGI)) return; @@ -88,18 +88,18 @@ void StmtIteratorBase::NextDecl(bool ImmediateAdvance) { } bool StmtIteratorBase::HandleDecl(Decl* D) { - - if (VarDecl* VD = dyn_cast(D)) { + + if (VarDecl* VD = dyn_cast(D)) { if (VariableArrayType* VAPtr = FindVA(VD->getType().getTypePtr())) { setVAPtr(VAPtr); return true; } - + if (VD->getInit()) return true; } else if (TypedefDecl* TD = dyn_cast(D)) { - if (VariableArrayType* VAPtr = + if (VariableArrayType* VAPtr = FindVA(TD->getUnderlyingType().getTypePtr())) { setVAPtr(VAPtr); return true; @@ -110,7 +110,7 @@ bool StmtIteratorBase::HandleDecl(Decl* D) { return true; } - return false; + return false; } StmtIteratorBase::StmtIteratorBase(Decl* d) @@ -130,19 +130,19 @@ StmtIteratorBase::StmtIteratorBase(VariableArrayType* t) } Stmt*& StmtIteratorBase::GetDeclExpr() const { - + if (VariableArrayType* VAPtr = getVAPtr()) { assert (VAPtr->SizeExpr); return VAPtr->SizeExpr; } assert (inDecl() || inDeclGroup()); - + if (inDeclGroup()) { VarDecl* VD = cast(*DGI); return *VD->getInitAddress(); } - + assert (inDecl()); if (VarDecl* VD = dyn_cast(decl)) { diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index fec17fb22352..05d0c2683545 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -17,7 +17,6 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/Streams.h" #include "llvm/Support/Format.h" using namespace clang; @@ -34,12 +33,12 @@ namespace { PrintingPolicy Policy; public: - StmtPrinter(llvm::raw_ostream &os, ASTContext &C, PrinterHelper* helper, + StmtPrinter(llvm::raw_ostream &os, ASTContext &C, PrinterHelper* helper, const PrintingPolicy &Policy, unsigned Indentation = 0) : OS(os), Context(C), IndentLevel(Indentation), Helper(helper), Policy(Policy) {} - + void PrintStmt(Stmt *S) { PrintStmt(S, Policy.Indentation); } @@ -64,29 +63,29 @@ namespace { void PrintRawDeclStmt(DeclStmt *S); void PrintRawIfStmt(IfStmt *If); void PrintRawCXXCatchStmt(CXXCatchStmt *Catch); - + void PrintExpr(Expr *E) { if (E) Visit(E); else OS << ""; } - + llvm::raw_ostream &Indent(int Delta = 0) { for (int i = 0, e = IndentLevel+Delta; i < e; ++i) OS << " "; return OS; } - + bool PrintOffsetOfDesignator(Expr *E); void VisitUnaryOffsetOf(UnaryOperator *Node); - - void Visit(Stmt* S) { + + void Visit(Stmt* S) { if (Helper && Helper->handledStmt(S,OS)) return; else StmtVisitor::Visit(S); } - + void VisitStmt(Stmt *Node); #define STMT(CLASS, PARENT) \ void Visit##CLASS(CLASS *Node); @@ -109,7 +108,7 @@ void StmtPrinter::PrintRawCompoundStmt(CompoundStmt *Node) { for (CompoundStmt::body_iterator I = Node->body_begin(), E = Node->body_end(); I != E; ++I) PrintStmt(*I); - + Indent() << "}"; } @@ -120,7 +119,7 @@ void StmtPrinter::PrintRawDecl(Decl *D) { void StmtPrinter::PrintRawDeclStmt(DeclStmt *S) { DeclStmt::decl_iterator Begin = S->decl_begin(), End = S->decl_end(); llvm::SmallVector Decls; - for ( ; Begin != End; ++Begin) + for ( ; Begin != End; ++Begin) Decls.push_back(*Begin); Decl::printGroup(Decls.data(), Decls.size(), OS, Policy, IndentLevel); @@ -150,7 +149,7 @@ void StmtPrinter::VisitCaseStmt(CaseStmt *Node) { PrintExpr(Node->getRHS()); } OS << ":\n"; - + PrintStmt(Node->getSubStmt(), 0); } @@ -168,7 +167,7 @@ void StmtPrinter::PrintRawIfStmt(IfStmt *If) { OS << "if ("; PrintExpr(If->getCond()); OS << ')'; - + if (CompoundStmt *CS = dyn_cast(If->getThen())) { OS << ' '; PrintRawCompoundStmt(CS); @@ -178,10 +177,10 @@ void StmtPrinter::PrintRawIfStmt(IfStmt *If) { PrintStmt(If->getThen()); if (If->getElse()) Indent(); } - + if (Stmt *Else = If->getElse()) { OS << "else"; - + if (CompoundStmt *CS = dyn_cast(Else)) { OS << ' '; PrintRawCompoundStmt(CS); @@ -205,7 +204,7 @@ void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) { Indent() << "switch ("; PrintExpr(Node->getCond()); OS << ")"; - + // Pretty print compoundstmt bodies (very common). if (CompoundStmt *CS = dyn_cast(Node->getBody())) { OS << " "; @@ -238,7 +237,7 @@ void StmtPrinter::VisitDoStmt(DoStmt *Node) { PrintStmt(Node->getBody()); Indent(); } - + OS << "while ("; PrintExpr(Node->getCond()); OS << ");\n"; @@ -263,7 +262,7 @@ void StmtPrinter::VisitForStmt(ForStmt *Node) { PrintExpr(Node->getInc()); } OS << ") "; - + if (CompoundStmt *CS = dyn_cast(Node->getBody())) { PrintRawCompoundStmt(CS); OS << "\n"; @@ -282,7 +281,7 @@ void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) { OS << " in "; PrintExpr(Node->getCollection()); OS << ") "; - + if (CompoundStmt *CS = dyn_cast(Node->getBody())) { PrintRawCompoundStmt(CS); OS << "\n"; @@ -323,63 +322,63 @@ void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) { void StmtPrinter::VisitAsmStmt(AsmStmt *Node) { Indent() << "asm "; - + if (Node->isVolatile()) OS << "volatile "; - + OS << "("; VisitStringLiteral(Node->getAsmString()); - + // Outputs if (Node->getNumOutputs() != 0 || Node->getNumInputs() != 0 || Node->getNumClobbers() != 0) OS << " : "; - + for (unsigned i = 0, e = Node->getNumOutputs(); i != e; ++i) { if (i != 0) OS << ", "; - + if (!Node->getOutputName(i).empty()) { OS << '['; OS << Node->getOutputName(i); OS << "] "; } - + VisitStringLiteral(Node->getOutputConstraintLiteral(i)); OS << " "; Visit(Node->getOutputExpr(i)); } - + // Inputs if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0) OS << " : "; - + for (unsigned i = 0, e = Node->getNumInputs(); i != e; ++i) { if (i != 0) OS << ", "; - + if (!Node->getInputName(i).empty()) { OS << '['; OS << Node->getInputName(i); OS << "] "; } - + VisitStringLiteral(Node->getInputConstraintLiteral(i)); OS << " "; Visit(Node->getInputExpr(i)); } - + // Clobbers if (Node->getNumClobbers() != 0) OS << " : "; - + for (unsigned i = 0, e = Node->getNumClobbers(); i != e; ++i) { if (i != 0) OS << ", "; - + VisitStringLiteral(Node->getClobber(i)); } - + OS << ");\n"; } @@ -389,11 +388,11 @@ void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { PrintRawCompoundStmt(TS); OS << "\n"; } - - for (ObjCAtCatchStmt *catchStmt = + + for (ObjCAtCatchStmt *catchStmt = static_cast(Node->getCatchStmts()); - catchStmt; - catchStmt = + catchStmt; + catchStmt = static_cast(catchStmt->getNextCatchStmt())) { Indent() << "@catch("; if (catchStmt->getCatchParamDecl()) { @@ -401,19 +400,18 @@ void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { PrintRawDecl(DS); } OS << ")"; - if (CompoundStmt *CS = dyn_cast(catchStmt->getCatchBody())) - { - PrintRawCompoundStmt(CS); - OS << "\n"; - } + if (CompoundStmt *CS = dyn_cast(catchStmt->getCatchBody())) { + PrintRawCompoundStmt(CS); + OS << "\n"; + } } - - if (ObjCAtFinallyStmt *FS =static_cast( - Node->getFinallyStmt())) { + + if (ObjCAtFinallyStmt *FS = static_cast( + Node->getFinallyStmt())) { Indent() << "@finally"; PrintRawCompoundStmt(dyn_cast(FS->getFinallyBody())); OS << "\n"; - } + } } void StmtPrinter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *Node) { @@ -459,7 +457,7 @@ void StmtPrinter::VisitCXXCatchStmt(CXXCatchStmt *Node) { void StmtPrinter::VisitCXXTryStmt(CXXTryStmt *Node) { Indent() << "try "; PrintRawCompoundStmt(Node->getTryBlock()); - for(unsigned i = 0, e = Node->getNumHandlers(); i < e; ++i) { + for (unsigned i = 0, e = Node->getNumHandlers(); i < e; ++i) { OS << " "; PrintRawCXXCatchStmt(Node->getHandler(i)); } @@ -478,14 +476,14 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { OS << Node->getDecl()->getNameAsString(); } -void StmtPrinter::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *Node) { +void StmtPrinter::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *Node) { NamedDecl *D = Node->getDecl(); Node->getQualifier()->print(OS, Policy); OS << D->getNameAsString(); } -void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) { +void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) { Node->getQualifier()->print(OS, Policy); OS << Node->getDeclName().getAsString(); } @@ -494,12 +492,10 @@ void StmtPrinter::VisitTemplateIdRefExpr(TemplateIdRefExpr *Node) { if (Node->getQualifier()) Node->getQualifier()->print(OS, Policy); Node->getTemplateName().print(OS, Policy, true); - OS << '<'; OS << TemplateSpecializationType::PrintTemplateArgumentList( Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy); - OS << '>'; } void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { @@ -518,12 +514,15 @@ void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { OS << Node->getProperty()->getNameAsCString(); } -void StmtPrinter::VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node) { +void StmtPrinter::VisitObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *Node) { if (Node->getBase()) { PrintExpr(Node->getBase()); OS << "."; } - // FIXME: Setter/Getter names + if (Node->getGetterMethod()) + OS << Node->getGetterMethod()->getNameAsString(); + } void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) { @@ -594,9 +593,9 @@ void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) { void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) { bool isSigned = Node->getType()->isSignedIntegerType(); OS << Node->getValue().toString(10, isSigned); - + // Emit suffixes. Integer literals are always a builtin integer type. - switch (Node->getType()->getAsBuiltinType()->getKind()) { + switch (Node->getType()->getAs()->getKind()) { default: assert(0 && "Unexpected type for integer literal!"); case BuiltinType::Int: break; // no suffix. case BuiltinType::UInt: OS << 'U'; break; @@ -623,7 +622,7 @@ void StmtPrinter::VisitStringLiteral(StringLiteral *Str) { // FIXME: this doesn't print wstrings right. for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) { unsigned char Char = Str->getStrData()[i]; - + switch (Char) { default: if (isprint(Char)) @@ -653,7 +652,7 @@ void StmtPrinter::VisitParenExpr(ParenExpr *Node) { void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) { if (!Node->isPostfix()) { OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); - + // Print a space if this is an "identifier operator" like __real, or if // it might be concatenated incorrectly like '+'. switch (Node->getOpcode()) { @@ -671,7 +670,7 @@ void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) { } } PrintExpr(Node->getSubExpr()); - + if (Node->isPostfix()) OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); } @@ -737,8 +736,22 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { OS << (Node->isArrow() ? "->" : "."); // FIXME: Suppress printing references to unnamed objects // representing anonymous unions/structs + if (NestedNameSpecifier *Qualifier = Node->getQualifier()) + Qualifier->print(OS, Policy); + OS << Node->getMemberDecl()->getNameAsString(); + + if (Node->hasExplicitTemplateArgumentList()) + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); } +void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->isa" : ".isa"); +} + void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { PrintExpr(Node->getBase()); OS << "."; @@ -774,7 +787,7 @@ void StmtPrinter::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { } void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) { PrintExpr(Node->getCond()); - + if (Node->getLHS()) { OS << " ? "; PrintExpr(Node->getLHS()); @@ -783,7 +796,7 @@ void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) { else { // Handle GCC extension where LHS can be NULL. OS << " ?: "; } - + PrintExpr(Node->getRHS()); } @@ -845,6 +858,15 @@ void StmtPrinter::VisitInitListExpr(InitListExpr* Node) { OS << " }"; } +void StmtPrinter::VisitParenListExpr(ParenListExpr* Node) { + OS << "( "; + for (unsigned i = 0, e = Node->getNumExprs(); i != e; ++i) { + if (i) OS << ", "; + PrintExpr(Node->getExpr(i)); + } + OS << " )"; +} + void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) { for (DesignatedInitExpr::designators_iterator D = Node->designators_begin(), DEnd = Node->designators_end(); @@ -861,7 +883,7 @@ void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) { } else { PrintExpr(Node->getArrayRangeStart(*D)); OS << " ... "; - PrintExpr(Node->getArrayRangeEnd(*D)); + PrintExpr(Node->getArrayRangeEnd(*D)); } OS << "]"; } @@ -1013,7 +1035,7 @@ void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) { OS << Node->getType().getAsString(); OS << "("; for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(), - ArgEnd = Node->arg_end(); + ArgEnd = Node->arg_end(); Arg != ArgEnd; ++Arg) { if (Arg != Node->arg_begin()) OS << ", "; @@ -1082,6 +1104,20 @@ void StmtPrinter::VisitCXXDeleteExpr(CXXDeleteExpr *E) { PrintExpr(E->getArgument()); } +void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { + PrintExpr(E->getBase()); + if (E->isArrow()) + OS << "->"; + else + OS << '.'; + if (E->getQualifier()) + E->getQualifier()->print(OS, Policy); + + std::string TypeS; + E->getDestroyedType().getAsStringInternal(TypeS, Policy); + OS << TypeS; +} + void StmtPrinter::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *E) { OS << E->getName().getAsString(); } @@ -1095,13 +1131,13 @@ void StmtPrinter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { PrintExpr(E->getSubExpr()); } -void +void StmtPrinter::VisitCXXUnresolvedConstructExpr( CXXUnresolvedConstructExpr *Node) { OS << Node->getTypeAsWritten().getAsString(); OS << "("; for (CXXUnresolvedConstructExpr::arg_iterator Arg = Node->arg_begin(), - ArgEnd = Node->arg_end(); + ArgEnd = Node->arg_end(); Arg != ArgEnd; ++Arg) { if (Arg != Node->arg_begin()) OS << ", "; @@ -1113,7 +1149,20 @@ StmtPrinter::VisitCXXUnresolvedConstructExpr( void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) { PrintExpr(Node->getBase()); OS << (Node->isArrow() ? "->" : "."); + if (NestedNameSpecifier *Qualifier = Node->getQualifier()) + Qualifier->print(OS, Policy); + else if (Node->hasExplicitTemplateArgumentList()) + // FIXME: Track use of "template" keyword explicitly? + OS << "template "; + OS << Node->getMember().getAsString(); + + if (Node->hasExplicitTemplateArgumentList()) { + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); + } } static const char *getTypeTraitName(UnaryTypeTrait UTT) { @@ -1142,7 +1191,7 @@ void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { << E->getQueriedType().getAsString() << ")"; } -// Obj-C +// Obj-C void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) { OS << "@"; @@ -1180,7 +1229,7 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { OS << ":"; } else OS << ", "; // Handle variadic methods. - + PrintExpr(Mess->getArg(i)); } } @@ -1194,9 +1243,9 @@ void StmtPrinter::VisitObjCSuperExpr(ObjCSuperExpr *) { void StmtPrinter::VisitBlockExpr(BlockExpr *Node) { BlockDecl *BD = Node->getBlockDecl(); OS << "^"; - + const FunctionType *AFT = Node->getFunctionType(); - + if (isa(AFT)) { OS << "()"; } else if (!BD->param_empty() || cast(AFT)->isVariadic()) { @@ -1209,7 +1258,7 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) { (*AI)->getType().getAsStringInternal(ParamStr, Policy); OS << ParamStr; } - + const FunctionProtoType *FT = cast(AFT); if (FT->isVariadic()) { if (!BD->param_empty()) OS << ", "; @@ -1241,10 +1290,10 @@ void Stmt::printPretty(llvm::raw_ostream &OS, ASTContext& Context, } if (Policy.Dump) { - dump(); + dump(Context.getSourceManager()); return; } - + StmtPrinter P(OS, Context, Helper, Policy, Indentation); P.Visit(const_cast(this)); } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp new file mode 100644 index 000000000000..c4d42f6be228 --- /dev/null +++ b/lib/AST/StmtProfile.cpp @@ -0,0 +1,720 @@ +//===---- StmtProfile.cpp - Profile implementation for Stmt ASTs ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Stmt::Profile method, which builds a unique bit +// representation that identifies a statement/expression. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/StmtVisitor.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Compiler.h" +using namespace clang; + +namespace { + class VISIBILITY_HIDDEN StmtProfiler : public StmtVisitor { + llvm::FoldingSetNodeID &ID; + ASTContext &Context; + bool Canonical; + + public: + StmtProfiler(llvm::FoldingSetNodeID &ID, ASTContext &Context, + bool Canonical) + : ID(ID), Context(Context), Canonical(Canonical) { } + + void VisitStmt(Stmt *S); + +#define STMT(Node, Base) void Visit##Node(Node *S); +#include "clang/AST/StmtNodes.def" + + /// \brief Visit a declaration that is referenced within an expression + /// or statement. + void VisitDecl(Decl *D); + + /// \brief Visit a type that is referenced within an expression or + /// statement. + void VisitType(QualType T); + + /// \brief Visit a name that occurs within an expression or statement. + void VisitName(DeclarationName Name); + + /// \brief Visit a nested-name-specifier that occurs within an expression + /// or statement. + void VisitNestedNameSpecifier(NestedNameSpecifier *NNS); + + /// \brief Visit a template name that occurs within an expression or + /// statement. + void VisitTemplateName(TemplateName Name); + + /// \brief Visit template arguments that occur within an expression or + /// statement. + void VisitTemplateArguments(const TemplateArgument *Args, unsigned NumArgs); + }; +} + +void StmtProfiler::VisitStmt(Stmt *S) { + ID.AddInteger(S->getStmtClass()); + for (Stmt::child_iterator C = S->child_begin(), CEnd = S->child_end(); + C != CEnd; ++C) + Visit(*C); +} + +void StmtProfiler::VisitDeclStmt(DeclStmt *S) { + VisitStmt(S); + for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); + D != DEnd; ++D) + VisitDecl(*D); +} + +void StmtProfiler::VisitNullStmt(NullStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitCompoundStmt(CompoundStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitSwitchCase(SwitchCase *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitCaseStmt(CaseStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitDefaultStmt(DefaultStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitLabelStmt(LabelStmt *S) { + VisitStmt(S); + VisitName(S->getID()); +} + +void StmtProfiler::VisitIfStmt(IfStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitSwitchStmt(SwitchStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitWhileStmt(WhileStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitDoStmt(DoStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitForStmt(ForStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitGotoStmt(GotoStmt *S) { + VisitStmt(S); + VisitName(S->getLabel()->getID()); +} + +void StmtProfiler::VisitIndirectGotoStmt(IndirectGotoStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitContinueStmt(ContinueStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitBreakStmt(BreakStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitReturnStmt(ReturnStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitAsmStmt(AsmStmt *S) { + VisitStmt(S); + ID.AddBoolean(S->isVolatile()); + ID.AddBoolean(S->isSimple()); + VisitStringLiteral(S->getAsmString()); + ID.AddInteger(S->getNumOutputs()); + for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) { + ID.AddString(S->getOutputName(I)); + VisitStringLiteral(S->getOutputConstraintLiteral(I)); + } + ID.AddInteger(S->getNumInputs()); + for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) { + ID.AddString(S->getInputName(I)); + VisitStringLiteral(S->getInputConstraintLiteral(I)); + } + ID.AddInteger(S->getNumClobbers()); + for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I) + VisitStringLiteral(S->getClobber(I)); +} + +void StmtProfiler::VisitCXXCatchStmt(CXXCatchStmt *S) { + VisitStmt(S); + VisitType(S->getCaughtType()); +} + +void StmtProfiler::VisitCXXTryStmt(CXXTryStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { + VisitStmt(S); + ID.AddBoolean(S->hasEllipsis()); + if (S->getCatchParamDecl()) + VisitType(S->getCatchParamDecl()->getType()); +} + +void StmtProfiler::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitExpr(Expr *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitDeclRefExpr(DeclRefExpr *S) { + VisitExpr(S); + VisitDecl(S->getDecl()); +} + +void StmtProfiler::VisitPredefinedExpr(PredefinedExpr *S) { + VisitExpr(S); + ID.AddInteger(S->getIdentType()); +} + +void StmtProfiler::VisitIntegerLiteral(IntegerLiteral *S) { + VisitExpr(S); + S->getValue().Profile(ID); +} + +void StmtProfiler::VisitCharacterLiteral(CharacterLiteral *S) { + VisitExpr(S); + ID.AddBoolean(S->isWide()); + ID.AddInteger(S->getValue()); +} + +void StmtProfiler::VisitFloatingLiteral(FloatingLiteral *S) { + VisitExpr(S); + S->getValue().Profile(ID); + ID.AddBoolean(S->isExact()); +} + +void StmtProfiler::VisitImaginaryLiteral(ImaginaryLiteral *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitStringLiteral(StringLiteral *S) { + VisitExpr(S); + ID.AddString(S->getString()); + ID.AddBoolean(S->isWide()); +} + +void StmtProfiler::VisitParenExpr(ParenExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitParenListExpr(ParenListExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitUnaryOperator(UnaryOperator *S) { + VisitExpr(S); + ID.AddInteger(S->getOpcode()); +} + +void StmtProfiler::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isSizeOf()); + if (S->isArgumentType()) + VisitType(S->getArgumentType()); +} + +void StmtProfiler::VisitArraySubscriptExpr(ArraySubscriptExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitCallExpr(CallExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitMemberExpr(MemberExpr *S) { + VisitExpr(S); + VisitDecl(S->getMemberDecl()); + VisitNestedNameSpecifier(S->getQualifier()); + ID.AddBoolean(S->isArrow()); +} + +void StmtProfiler::VisitCompoundLiteralExpr(CompoundLiteralExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isFileScope()); +} + +void StmtProfiler::VisitCastExpr(CastExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitImplicitCastExpr(ImplicitCastExpr *S) { + VisitCastExpr(S); + ID.AddBoolean(S->isLvalueCast()); +} + +void StmtProfiler::VisitExplicitCastExpr(ExplicitCastExpr *S) { + VisitCastExpr(S); + VisitType(S->getTypeAsWritten()); +} + +void StmtProfiler::VisitCStyleCastExpr(CStyleCastExpr *S) { + VisitExplicitCastExpr(S); +} + +void StmtProfiler::VisitBinaryOperator(BinaryOperator *S) { + VisitExpr(S); + ID.AddInteger(S->getOpcode()); +} + +void StmtProfiler::VisitCompoundAssignOperator(CompoundAssignOperator *S) { + VisitBinaryOperator(S); +} + +void StmtProfiler::VisitConditionalOperator(ConditionalOperator *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitAddrLabelExpr(AddrLabelExpr *S) { + VisitExpr(S); + VisitName(S->getLabel()->getID()); +} + +void StmtProfiler::VisitStmtExpr(StmtExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitTypesCompatibleExpr(TypesCompatibleExpr *S) { + VisitExpr(S); + VisitType(S->getArgType1()); + VisitType(S->getArgType2()); +} + +void StmtProfiler::VisitShuffleVectorExpr(ShuffleVectorExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitChooseExpr(ChooseExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitGNUNullExpr(GNUNullExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitVAArgExpr(VAArgExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitInitListExpr(InitListExpr *S) { + if (S->getSyntacticForm()) { + VisitInitListExpr(S->getSyntacticForm()); + return; + } + + VisitExpr(S); +} + +void StmtProfiler::VisitDesignatedInitExpr(DesignatedInitExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->usesGNUSyntax()); + for (DesignatedInitExpr::designators_iterator D = S->designators_begin(), + DEnd = S->designators_end(); + D != DEnd; ++D) { + if (D->isFieldDesignator()) { + ID.AddInteger(0); + VisitName(D->getFieldName()); + continue; + } + + if (D->isArrayDesignator()) { + ID.AddInteger(1); + } else { + assert(D->isArrayRangeDesignator()); + ID.AddInteger(2); + } + ID.AddInteger(D->getFirstExprIndex()); + } +} + +void StmtProfiler::VisitImplicitValueInitExpr(ImplicitValueInitExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitExtVectorElementExpr(ExtVectorElementExpr *S) { + VisitExpr(S); + VisitName(&S->getAccessor()); +} + +void StmtProfiler::VisitBlockExpr(BlockExpr *S) { + VisitExpr(S); + VisitDecl(S->getBlockDecl()); +} + +void StmtProfiler::VisitBlockDeclRefExpr(BlockDeclRefExpr *S) { + VisitExpr(S); + VisitDecl(S->getDecl()); + ID.AddBoolean(S->isByRef()); + ID.AddBoolean(S->isConstQualAdded()); +} + +void StmtProfiler::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *S) { + VisitCallExpr(S); + ID.AddInteger(S->getOperator()); +} + +void StmtProfiler::VisitCXXMemberCallExpr(CXXMemberCallExpr *S) { + VisitCallExpr(S); +} + +void StmtProfiler::VisitCXXNamedCastExpr(CXXNamedCastExpr *S) { + VisitExplicitCastExpr(S); +} + +void StmtProfiler::VisitCXXStaticCastExpr(CXXStaticCastExpr *S) { + VisitCXXNamedCastExpr(S); +} + +void StmtProfiler::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *S) { + VisitCXXNamedCastExpr(S); +} + +void StmtProfiler::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *S) { + VisitCXXNamedCastExpr(S); +} + +void StmtProfiler::VisitCXXConstCastExpr(CXXConstCastExpr *S) { + VisitCXXNamedCastExpr(S); +} + +void StmtProfiler::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->getValue()); +} + +void StmtProfiler::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitCXXTypeidExpr(CXXTypeidExpr *S) { + VisitExpr(S); + if (S->isTypeOperand()) + VisitType(S->getTypeOperand()); +} + +void StmtProfiler::VisitCXXThisExpr(CXXThisExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitCXXThrowExpr(CXXThrowExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *S) { + VisitExpr(S); + VisitDecl(S->getParam()); +} + +void StmtProfiler::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *S) { + VisitExpr(S); + VisitDecl( + const_cast(S->getTemporary()->getDestructor())); +} + +void StmtProfiler::VisitCXXConstructExpr(CXXConstructExpr *S) { + VisitExpr(S); + VisitDecl(S->getConstructor()); + ID.AddBoolean(S->isElidable()); +} + +void StmtProfiler::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *S) { + VisitExplicitCastExpr(S); +} + +void StmtProfiler::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *S) { + VisitCXXConstructExpr(S); +} + +void StmtProfiler::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *S) { + VisitDeclRefExpr(S); +} + +void StmtProfiler::VisitCXXDeleteExpr(CXXDeleteExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isGlobalDelete()); + ID.AddBoolean(S->isArrayForm()); + VisitDecl(S->getOperatorDelete()); +} + + +void StmtProfiler::VisitCXXNewExpr(CXXNewExpr *S) { + VisitExpr(S); + VisitType(S->getAllocatedType()); + VisitDecl(S->getOperatorNew()); + VisitDecl(S->getOperatorDelete()); + VisitDecl(S->getConstructor()); + ID.AddBoolean(S->isArray()); + ID.AddInteger(S->getNumPlacementArgs()); + ID.AddBoolean(S->isGlobalNew()); + ID.AddBoolean(S->isParenTypeId()); + ID.AddBoolean(S->hasInitializer()); + ID.AddInteger(S->getNumConstructorArgs()); +} + +void StmtProfiler::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); + VisitNestedNameSpecifier(S->getQualifier()); + VisitType(S->getDestroyedType()); +} + +void +StmtProfiler::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *S) { + VisitExpr(S); + VisitName(S->getName()); +} + +void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) { + VisitExpr(S); + ID.AddInteger(S->getTrait()); + VisitType(S->getQueriedType()); +} + +void StmtProfiler::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *S) { + VisitDeclRefExpr(S); + VisitNestedNameSpecifier(S->getQualifier()); +} + +void StmtProfiler::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *S) { + VisitExpr(S); + VisitName(S->getDeclName()); + VisitNestedNameSpecifier(S->getQualifier()); + ID.AddBoolean(S->isAddressOfOperand()); +} + +void StmtProfiler::VisitTemplateIdRefExpr(TemplateIdRefExpr *S) { + VisitExpr(S); + VisitNestedNameSpecifier(S->getQualifier()); + VisitTemplateName(S->getTemplateName()); + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); +} + +void StmtProfiler::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *S) { + VisitExpr(S); + ID.AddBoolean(S->shouldDestroyTemporaries()); + for (unsigned I = 0, N = S->getNumTemporaries(); I != N; ++I) + VisitDecl( + const_cast(S->getTemporary(I)->getDestructor())); +} + +void +StmtProfiler::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *S) { + VisitExpr(S); + VisitType(S->getTypeAsWritten()); +} + +void StmtProfiler::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); + VisitNestedNameSpecifier(S->getQualifier()); + VisitName(S->getMember()); +} + +void StmtProfiler::VisitObjCStringLiteral(ObjCStringLiteral *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitObjCEncodeExpr(ObjCEncodeExpr *S) { + VisitExpr(S); + VisitType(S->getEncodedType()); +} + +void StmtProfiler::VisitObjCSelectorExpr(ObjCSelectorExpr *S) { + VisitExpr(S); + VisitName(S->getSelector()); +} + +void StmtProfiler::VisitObjCProtocolExpr(ObjCProtocolExpr *S) { + VisitExpr(S); + VisitDecl(S->getProtocol()); +} + +void StmtProfiler::VisitObjCIvarRefExpr(ObjCIvarRefExpr *S) { + VisitExpr(S); + VisitDecl(S->getDecl()); + ID.AddBoolean(S->isArrow()); + ID.AddBoolean(S->isFreeIvar()); +} + +void StmtProfiler::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *S) { + VisitExpr(S); + VisitDecl(S->getProperty()); +} + +void StmtProfiler::VisitObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *S) { + VisitExpr(S); + VisitDecl(S->getGetterMethod()); + VisitDecl(S->getSetterMethod()); + VisitDecl(S->getInterfaceDecl()); +} + +void StmtProfiler::VisitObjCMessageExpr(ObjCMessageExpr *S) { + VisitExpr(S); + VisitName(S->getSelector()); + VisitDecl(S->getMethodDecl()); +} + +void StmtProfiler::VisitObjCSuperExpr(ObjCSuperExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitObjCIsaExpr(ObjCIsaExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); +} + +void StmtProfiler::VisitDecl(Decl *D) { + ID.AddInteger(D? D->getKind() : 0); + + if (Canonical && D) { + if (NonTypeTemplateParmDecl *NTTP = dyn_cast(D)) { + ID.AddInteger(NTTP->getDepth()); + ID.AddInteger(NTTP->getIndex()); + VisitType(NTTP->getType()); + return; + } + + if (ParmVarDecl *Parm = dyn_cast(D)) { + // The Itanium C++ ABI uses the type of a parameter when mangling + // expressions that involve function parameters, so we will use the + // parameter's type for establishing function parameter identity. That + // way, our definition of "equivalent" (per C++ [temp.over.link]) + // matches the definition of "equivalent" used for name mangling. + VisitType(Parm->getType()); + return; + } + + if (TemplateTemplateParmDecl *TTP = dyn_cast(D)) { + ID.AddInteger(TTP->getDepth()); + ID.AddInteger(TTP->getIndex()); + return; + } + + if (OverloadedFunctionDecl *Ovl = dyn_cast(D)) { + // The Itanium C++ ABI mangles references to a set of overloaded + // functions using just the function name, so we do the same here. + VisitName(Ovl->getDeclName()); + return; + } + } + + ID.AddPointer(D? D->getCanonicalDecl() : 0); +} + +void StmtProfiler::VisitType(QualType T) { + if (Canonical) + T = Context.getCanonicalType(T); + + ID.AddPointer(T.getAsOpaquePtr()); +} + +void StmtProfiler::VisitName(DeclarationName Name) { + ID.AddPointer(Name.getAsOpaquePtr()); +} + +void StmtProfiler::VisitNestedNameSpecifier(NestedNameSpecifier *NNS) { + if (Canonical) + NNS = Context.getCanonicalNestedNameSpecifier(NNS); + ID.AddPointer(NNS); +} + +void StmtProfiler::VisitTemplateName(TemplateName Name) { + if (Canonical) + Name = Context.getCanonicalTemplateName(Name); + + Name.Profile(ID); +} + +void StmtProfiler::VisitTemplateArguments(const TemplateArgument *Args, + unsigned NumArgs) { + ID.AddInteger(NumArgs); + for (unsigned I = 0; I != NumArgs; ++I) { + const TemplateArgument &Arg = Args[I]; + + // Mostly repetitive with TemplateArgument::Profile! + ID.AddInteger(Arg.getKind()); + switch (Arg.getKind()) { + case TemplateArgument::Null: + break; + + case TemplateArgument::Type: + VisitType(Arg.getAsType()); + break; + + case TemplateArgument::Declaration: + VisitDecl(Arg.getAsDecl()); + break; + + case TemplateArgument::Integral: + Arg.getAsIntegral()->Profile(ID); + VisitType(Arg.getIntegralType()); + break; + + case TemplateArgument::Expression: + Visit(Arg.getAsExpr()); + break; + + case TemplateArgument::Pack: + VisitTemplateArguments(Arg.pack_begin(), Arg.pack_size()); + break; + } + } +} + +void Stmt::Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, + bool Canonical) { + StmtProfiler Profiler(ID, Context, Canonical); + Profiler.Visit(this); +} diff --git a/lib/AST/StmtViz.cpp b/lib/AST/StmtViz.cpp index 96b5218ba2f0..61fd750ccc83 100644 --- a/lib/AST/StmtViz.cpp +++ b/lib/AST/StmtViz.cpp @@ -15,7 +15,6 @@ #include "clang/AST/StmtGraphTraits.h" #include "clang/AST/Decl.h" #include "llvm/Support/GraphWriter.h" -#include using namespace clang; @@ -23,8 +22,8 @@ void Stmt::viewAST() const { #ifndef NDEBUG llvm::ViewGraph(this,"AST"); #else - llvm::cerr << "Stmt::viewAST is only available in debug builds on " - << "systems with Graphviz or gv!\n"; + llvm::errs() << "Stmt::viewAST is only available in debug builds on " + << "systems with Graphviz or gv!\n"; #endif } @@ -33,26 +32,26 @@ template<> struct DOTGraphTraits : public DefaultDOTGraphTraits { static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph, bool ShortNames) { - + #ifndef NDEBUG std::string OutSStr; llvm::raw_string_ostream Out(OutSStr); - + if (Node) Out << Node->getStmtClassName(); else Out << ""; - - std::string OutStr = Out.str(); + + std::string OutStr = Out.str(); if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); - + // Process string output to make it nicer... for (unsigned i = 0; i != OutStr.length(); ++i) if (OutStr[i] == '\n') { // Left justify OutStr[i] = '\\'; OutStr.insert(OutStr.begin()+i+1, 'l'); } - + return OutStr; #else return ""; diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index 5b671c111fbf..24588bc5f11f 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -22,39 +22,55 @@ using namespace clang; TemplateDecl *TemplateName::getAsTemplateDecl() const { if (TemplateDecl *Template = Storage.dyn_cast()) return Template; - + if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) return QTN->getTemplateDecl(); return 0; } +OverloadedFunctionDecl *TemplateName::getAsOverloadedFunctionDecl() const { + if (OverloadedFunctionDecl *Ovl + = Storage.dyn_cast()) + return Ovl; + + if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) + return QTN->getOverloadedFunctionDecl(); + + return 0; +} + bool TemplateName::isDependent() const { if (TemplateDecl *Template = getAsTemplateDecl()) { - // FIXME: We don't yet have a notion of dependent - // declarations. When we do, check that. This hack won't last - // long!. - return isa(Template); + return isa(Template) || + Template->getDeclContext()->isDependentContext(); } + if (OverloadedFunctionDecl *Ovl = getAsOverloadedFunctionDecl()) + return Ovl->getDeclContext()->isDependentContext(); + return true; } -void +void TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, bool SuppressNNS) const { if (TemplateDecl *Template = Storage.dyn_cast()) OS << Template->getIdentifier()->getName(); + else if (OverloadedFunctionDecl *Ovl + = Storage.dyn_cast()) + OS << Ovl->getNameAsString(); else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { if (!SuppressNNS) QTN->getQualifier()->print(OS, Policy); if (QTN->hasTemplateKeyword()) OS << "template "; - OS << QTN->getTemplateDecl()->getIdentifier()->getName(); + OS << QTN->getDecl()->getNameAsString(); } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) { - if (!SuppressNNS) + if (!SuppressNNS && DTN->getQualifier()) DTN->getQualifier()->print(OS, Policy); OS << "template "; + // FIXME: Shouldn't we have a more general kind of name? OS << DTN->getName()->getName(); } } @@ -65,3 +81,13 @@ void TemplateName::dump() const { LO.Bool = true; print(llvm::errs(), PrintingPolicy(LO)); } + +TemplateDecl *QualifiedTemplateName::getTemplateDecl() const { + return dyn_cast(Template); +} + +OverloadedFunctionDecl * +QualifiedTemplateName::getOverloadedFunctionDecl() const { + return dyn_cast(Template); +} + diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 4e061a9fbe62..0293862baedb 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -22,12 +22,12 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; -bool QualType::isConstant(ASTContext &Ctx) const { - if (isConstQualified()) +bool QualType::isConstant(QualType T, ASTContext &Ctx) { + if (T.isConstQualified()) return true; - if (getTypePtr()->isArrayType()) - return Ctx.getAsArrayType(*this)->getElementType().isConstant(Ctx); + if (const ArrayType *AT = Ctx.getAsArrayType(T)) + return AT->getElementType().isConstant(Ctx); return false; } @@ -37,6 +37,18 @@ void Type::Destroy(ASTContext& C) { C.Deallocate(this); } +void ConstantArrayWithExprType::Destroy(ASTContext& C) { + // FIXME: destruction of SizeExpr commented out due to resource contention. + // SizeExpr->Destroy(C); + // See FIXME in SemaDecl.cpp:1536: if we were able to either steal + // or clone the SizeExpr there, then here we could freely delete it. + // Since we do not know how to steal or clone, we keep a pointer to + // a shared resource, but we cannot free it. + // (There probably is a trivial solution ... for people knowing clang!). + this->~ConstantArrayWithExprType(); + C.Deallocate(this); +} + void VariableArrayType::Destroy(ASTContext& C) { if (SizeExpr) SizeExpr->Destroy(C); @@ -45,14 +57,37 @@ void VariableArrayType::Destroy(ASTContext& C) { } void DependentSizedArrayType::Destroy(ASTContext& C) { - SizeExpr->Destroy(C); + // FIXME: Resource contention like in ConstantArrayWithExprType ? + // May crash, depending on platform or a particular build. + // SizeExpr->Destroy(C); this->~DependentSizedArrayType(); C.Deallocate(this); } +void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context, + QualType ET, + ArraySizeModifier SizeMod, + unsigned TypeQuals, + Expr *E) { + ID.AddPointer(ET.getAsOpaquePtr()); + ID.AddInteger(SizeMod); + ID.AddInteger(TypeQuals); + E->Profile(ID, Context, true); +} + +void +DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context, + QualType ElementType, Expr *SizeExpr) { + ID.AddPointer(ElementType.getAsOpaquePtr()); + SizeExpr->Profile(ID, Context, true); +} + void DependentSizedExtVectorType::Destroy(ASTContext& C) { - if (SizeExpr) - SizeExpr->Destroy(C); + // FIXME: Deallocate size expression, once we're cloning properly. +// if (SizeExpr) +// SizeExpr->Destroy(C); this->~DependentSizedExtVectorType(); C.Deallocate(this); } @@ -64,18 +99,15 @@ const Type *Type::getArrayElementTypeNoTypeQual() const { // If this is directly an array type, return it. if (const ArrayType *ATy = dyn_cast(this)) return ATy->getElementType().getTypePtr(); - + // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (ArrayType *AT = dyn_cast(CanonicalType.getUnqualifiedType())) - return AT->getElementType().getTypePtr(); + if (!isa(CanonicalType)) return 0; - } - + // If this is a typedef for an array type, strip the typedef off without // losing all typedef information. - return cast(getDesugaredType())->getElementType().getTypePtr(); + return cast(getUnqualifiedDesugaredType()) + ->getElementType().getTypePtr(); } /// getDesugaredType - Return the specified type with any "sugar" removed from @@ -84,66 +116,52 @@ const Type *Type::getArrayElementTypeNoTypeQual() const { /// to getting the canonical type, but it doesn't remove *all* typedefs. For /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is /// concrete. -/// -/// \param ForDisplay When true, the desugaring is provided for -/// display purposes only. In this case, we apply more heuristics to -/// decide whether it is worth providing a desugared form of the type -/// or not. -QualType QualType::getDesugaredType(bool ForDisplay) const { - return getTypePtr()->getDesugaredType(ForDisplay) - .getWithAdditionalQualifiers(getCVRQualifiers()); +QualType QualType::getDesugaredType(QualType T) { + QualifierCollector Qs; + + QualType Cur = T; + while (true) { + const Type *CurTy = Qs.strip(Cur); + switch (CurTy->getTypeClass()) { +#define ABSTRACT_TYPE(Class, Parent) +#define TYPE(Class, Parent) \ + case Type::Class: { \ + const Class##Type *Ty = cast(CurTy); \ + if (!Ty->isSugared()) \ + return Qs.apply(Cur); \ + Cur = Ty->desugar(); \ + break; \ + } +#include "clang/AST/TypeNodes.def" + } + } } -/// getDesugaredType - Return the specified type with any "sugar" removed from -/// type type. This takes off typedefs, typeof's etc. If the outer level of -/// the type is already concrete, it returns it unmodified. This is similar -/// to getting the canonical type, but it doesn't remove *all* typedefs. For -/// example, it return "T*" as "T*", (not as "int*"), because the pointer is -/// concrete. -/// -/// \param ForDisplay When true, the desugaring is provided for -/// display purposes only. In this case, we apply more heuristics to -/// decide whether it is worth providing a desugared form of the type -/// or not. -QualType Type::getDesugaredType(bool ForDisplay) const { - if (const TypedefType *TDT = dyn_cast(this)) - return TDT->LookThroughTypedefs().getDesugaredType(); - if (const TypeOfExprType *TOE = dyn_cast(this)) - return TOE->getUnderlyingExpr()->getType().getDesugaredType(); - if (const TypeOfType *TOT = dyn_cast(this)) - return TOT->getUnderlyingType().getDesugaredType(); - if (const DecltypeType *DTT = dyn_cast(this)) - return DTT->getUnderlyingExpr()->getType().getDesugaredType(); - if (const TemplateSpecializationType *Spec - = dyn_cast(this)) { - if (ForDisplay) - return QualType(this, 0); - - QualType Canon = Spec->getCanonicalTypeInternal(); - if (Canon->getAsTemplateSpecializationType()) - return QualType(this, 0); - return Canon->getDesugaredType(); - } - if (const QualifiedNameType *QualName = dyn_cast(this)) { - if (ForDisplay) { - // If desugaring the type that the qualified name is referring to - // produces something interesting, that's our desugared type. - QualType NamedType = QualName->getNamedType().getDesugaredType(); - if (NamedType != QualName->getNamedType()) - return NamedType; - } else - return QualName->getNamedType().getDesugaredType(); +/// getUnqualifiedDesugaredType - Pull any qualifiers and syntactic +/// sugar off the given type. This should produce an object of the +/// same dynamic type as the canonical type. +const Type *Type::getUnqualifiedDesugaredType() const { + const Type *Cur = this; + + while (true) { + switch (Cur->getTypeClass()) { +#define ABSTRACT_TYPE(Class, Parent) +#define TYPE(Class, Parent) \ + case Class: { \ + const Class##Type *Ty = cast(Cur); \ + if (!Ty->isSugared()) return Cur; \ + Cur = Ty->desugar().getTypePtr(); \ + break; \ + } +#include "clang/AST/TypeNodes.def" + } } - - return QualType(this, 0); } /// isVoidType - Helper method to determine if this is the 'void' type. bool Type::isVoidType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Void; - if (const ExtQualType *AS = dyn_cast(CanonicalType)) - return AS->getBaseType()->isVoidType(); return false; } @@ -151,18 +169,16 @@ bool Type::isObjectType() const { if (isa(CanonicalType) || isa(CanonicalType) || isa(CanonicalType) || isVoidType()) return false; - if (const ExtQualType *AS = dyn_cast(CanonicalType)) - return AS->getBaseType()->isObjectType(); return true; } bool Type::isDerivedType() const { switch (CanonicalType->getTypeClass()) { - case ExtQual: - return cast(CanonicalType)->getBaseType()->isDerivedType(); case Pointer: case VariableArray: case ConstantArray: + case ConstantArrayWithExpr: + case ConstantArrayWithoutExpr: case IncompleteArray: case FunctionProto: case FunctionNoProto: @@ -176,23 +192,23 @@ bool Type::isDerivedType() const { } bool Type::isClassType() const { - if (const RecordType *RT = getAsRecordType()) + if (const RecordType *RT = getAs()) return RT->getDecl()->isClass(); return false; } bool Type::isStructureType() const { - if (const RecordType *RT = getAsRecordType()) + if (const RecordType *RT = getAs()) return RT->getDecl()->isStruct(); return false; } bool Type::isVoidPointerType() const { - if (const PointerType *PT = getAsPointerType()) + if (const PointerType *PT = getAs()) return PT->getPointeeType()->isVoidType(); return false; } bool Type::isUnionType() const { - if (const RecordType *RT = getAsRecordType()) + if (const RecordType *RT = getAs()) return RT->getDecl()->isUnion(); return false; } @@ -200,192 +216,29 @@ bool Type::isUnionType() const { bool Type::isComplexType() const { if (const ComplexType *CT = dyn_cast(CanonicalType)) return CT->getElementType()->isFloatingType(); - if (const ExtQualType *AS = dyn_cast(CanonicalType)) - return AS->getBaseType()->isComplexType(); return false; } bool Type::isComplexIntegerType() const { // Check for GCC complex integer extension. - if (const ComplexType *CT = dyn_cast(CanonicalType)) - return CT->getElementType()->isIntegerType(); - if (const ExtQualType *AS = dyn_cast(CanonicalType)) - return AS->getBaseType()->isComplexIntegerType(); - return false; + return getAsComplexIntegerType(); } const ComplexType *Type::getAsComplexIntegerType() const { - // Are we directly a complex type? - if (const ComplexType *CTy = dyn_cast(this)) { - if (CTy->getElementType()->isIntegerType()) - return CTy; - return 0; - } - - // If the canonical form of this type isn't what we want, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers (e.g. ExtQualType's). - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsComplexIntegerType(); - return 0; - } - - // If this is a typedef for a complex type, strip the typedef off without - // losing all typedef information. - return cast(getDesugaredType()); -} - -const BuiltinType *Type::getAsBuiltinType() const { - // If this is directly a builtin type, return it. - if (const BuiltinType *BTy = dyn_cast(this)) - return BTy; - - // If the canonical form of this type isn't a builtin type, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers (e.g. ExtQualType's). - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsBuiltinType(); - return 0; - } - - // If this is a typedef for a builtin type, strip the typedef off without - // losing all typedef information. - return cast(getDesugaredType()); -} - -const FunctionType *Type::getAsFunctionType() const { - // If this is directly a function type, return it. - if (const FunctionType *FTy = dyn_cast(this)) - return FTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsFunctionType(); - return 0; - } - - // If this is a typedef for a function type, strip the typedef off without - // losing all typedef information. - return cast(getDesugaredType()); -} - -const FunctionNoProtoType *Type::getAsFunctionNoProtoType() const { - return dyn_cast_or_null(getAsFunctionType()); -} - -const FunctionProtoType *Type::getAsFunctionProtoType() const { - return dyn_cast_or_null(getAsFunctionType()); -} - - -const PointerType *Type::getAsPointerType() const { - // If this is directly a pointer type, return it. - if (const PointerType *PTy = dyn_cast(this)) - return PTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsPointerType(); - return 0; - } - - // If this is a typedef for a pointer type, strip the typedef off without - // losing all typedef information. - return cast(getDesugaredType()); -} - -const BlockPointerType *Type::getAsBlockPointerType() const { - // If this is directly a block pointer type, return it. - if (const BlockPointerType *PTy = dyn_cast(this)) - return PTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsBlockPointerType(); - return 0; - } - - // If this is a typedef for a block pointer type, strip the typedef off - // without losing all typedef information. - return cast(getDesugaredType()); -} - -const ReferenceType *Type::getAsReferenceType() const { - // If this is directly a reference type, return it. - if (const ReferenceType *RTy = dyn_cast(this)) - return RTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsReferenceType(); - return 0; - } - - // If this is a typedef for a reference type, strip the typedef off without - // losing all typedef information. - return cast(getDesugaredType()); -} - -const LValueReferenceType *Type::getAsLValueReferenceType() const { - // If this is directly an lvalue reference type, return it. - if (const LValueReferenceType *RTy = dyn_cast(this)) - return RTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsLValueReferenceType(); - return 0; - } - - // If this is a typedef for an lvalue reference type, strip the typedef off - // without losing all typedef information. - return cast(getDesugaredType()); -} - -const RValueReferenceType *Type::getAsRValueReferenceType() const { - // If this is directly an rvalue reference type, return it. - if (const RValueReferenceType *RTy = dyn_cast(this)) - return RTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsRValueReferenceType(); - return 0; - } - - // If this is a typedef for an rvalue reference type, strip the typedef off - // without losing all typedef information. - return cast(getDesugaredType()); + if (const ComplexType *Complex = getAs()) + if (Complex->getElementType()->isIntegerType()) + return Complex; + return 0; } -const MemberPointerType *Type::getAsMemberPointerType() const { - // If this is directly a member pointer type, return it. - if (const MemberPointerType *MTy = dyn_cast(this)) - return MTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsMemberPointerType(); - return 0; - } - - // If this is a typedef for a member pointer type, strip the typedef off - // without losing all typedef information. - return cast(getDesugaredType()); +QualType Type::getPointeeType() const { + if (const PointerType *PT = getAs()) + return PT->getPointeeType(); + if (const ObjCObjectPointerType *OPT = getAs()) + return OPT->getPointeeType(); + if (const BlockPointerType *BPT = getAs()) + return BPT->getPointeeType(); + return QualType(); } /// isVariablyModifiedType (C99 6.7.5p3) - Return true for variable length @@ -404,59 +257,23 @@ bool Type::isVariablyModifiedType() const { // Also, C++ references and member pointers can point to a variably modified // type, where VLAs appear as an extension to C++, and should be treated // correctly. - if (const PointerType *PT = getAsPointerType()) + if (const PointerType *PT = getAs()) return PT->getPointeeType()->isVariablyModifiedType(); - if (const ReferenceType *RT = getAsReferenceType()) + if (const ReferenceType *RT = getAs()) return RT->getPointeeType()->isVariablyModifiedType(); - if (const MemberPointerType *PT = getAsMemberPointerType()) + if (const MemberPointerType *PT = getAs()) return PT->getPointeeType()->isVariablyModifiedType(); // A function can return a variably modified type // This one isn't completely obvious, but it follows from the // definition in C99 6.7.5p3. Because of this rule, it's // illegal to declare a function returning a variably modified type. - if (const FunctionType *FT = getAsFunctionType()) + if (const FunctionType *FT = getAs()) return FT->getResultType()->isVariablyModifiedType(); return false; } -const RecordType *Type::getAsRecordType() const { - // If this is directly a record type, return it. - if (const RecordType *RTy = dyn_cast(this)) - return RTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsRecordType(); - return 0; - } - - // If this is a typedef for a record type, strip the typedef off without - // losing all typedef information. - return cast(getDesugaredType()); -} - -const TagType *Type::getAsTagType() const { - // If this is directly a tag type, return it. - if (const TagType *TagTy = dyn_cast(this)) - return TagTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsTagType(); - return 0; - } - - // If this is a typedef for a tag type, strip the typedef off without - // losing all typedef information. - return cast(getDesugaredType()); -} - const RecordType *Type::getAsStructureType() const { // If this is directly a structure type, return it. if (const RecordType *RT = dyn_cast(this)) { @@ -468,24 +285,21 @@ const RecordType *Type::getAsStructureType() const { if (const RecordType *RT = dyn_cast(CanonicalType)) { if (!RT->getDecl()->isStruct()) return 0; - + // If this is a typedef for a structure type, strip the typedef off without // losing all typedef information. - return cast(getDesugaredType()); + return cast(getUnqualifiedDesugaredType()); } - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsStructureType(); return 0; } -const RecordType *Type::getAsUnionType() const { +const RecordType *Type::getAsUnionType() const { // If this is directly a union type, return it. if (const RecordType *RT = dyn_cast(this)) { if (RT->getDecl()->isUnion()) return RT; } - + // If the canonical form of this type isn't the right kind, reject it. if (const RecordType *RT = dyn_cast(CanonicalType)) { if (!RT->getDecl()->isUnion()) @@ -493,118 +307,49 @@ const RecordType *Type::getAsUnionType() const { // If this is a typedef for a union type, strip the typedef off without // losing all typedef information. - return cast(getDesugaredType()); - } - - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsUnionType(); - return 0; -} - -const EnumType *Type::getAsEnumType() const { - // Check the canonicalized unqualified type directly; the more complex - // version is unnecessary because there isn't any typedef information - // to preserve. - return dyn_cast(CanonicalType.getUnqualifiedType()); -} - -const ComplexType *Type::getAsComplexType() const { - // Are we directly a complex type? - if (const ComplexType *CTy = dyn_cast(this)) - return CTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsComplexType(); - return 0; - } - - // If this is a typedef for a complex type, strip the typedef off without - // losing all typedef information. - return cast(getDesugaredType()); -} - -const VectorType *Type::getAsVectorType() const { - // Are we directly a vector type? - if (const VectorType *VTy = dyn_cast(this)) - return VTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsVectorType(); - return 0; + return cast(getUnqualifiedDesugaredType()); } - // If this is a typedef for a vector type, strip the typedef off without - // losing all typedef information. - return cast(getDesugaredType()); -} - -const ExtVectorType *Type::getAsExtVectorType() const { - // Are we directly an OpenCU vector type? - if (const ExtVectorType *VTy = dyn_cast(this)) - return VTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsExtVectorType(); - return 0; - } - - // If this is a typedef for an extended vector type, strip the typedef off - // without losing all typedef information. - return cast(getDesugaredType()); + return 0; } -const ObjCInterfaceType *Type::getAsObjCInterfaceType() const { +const ObjCInterfaceType *Type::getAsObjCQualifiedInterfaceType() const { // There is no sugar for ObjCInterfaceType's, just return the canonical // type pointer if it is the right class. There is no typedef information to // return and these cannot be Address-space qualified. - return dyn_cast(CanonicalType.getUnqualifiedType()); -} - -const ObjCObjectPointerType *Type::getAsObjCObjectPointerType() const { - // There is no sugar for ObjCObjectPointerType's, just return the - // canonical type pointer if it is the right class. - return dyn_cast(CanonicalType.getUnqualifiedType()); + if (const ObjCInterfaceType *OIT = getAs()) + if (OIT->getNumProtocols()) + return OIT; + return 0; } -const ObjCQualifiedInterfaceType * -Type::getAsObjCQualifiedInterfaceType() const { - // There is no sugar for ObjCQualifiedInterfaceType's, just return the - // canonical type pointer if it is the right class. - return dyn_cast(CanonicalType.getUnqualifiedType()); +bool Type::isObjCQualifiedInterfaceType() const { + return getAsObjCQualifiedInterfaceType() != 0; } const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const { // There is no sugar for ObjCQualifiedIdType's, just return the canonical // type pointer if it is the right class. - if (const ObjCObjectPointerType *OPT = getAsObjCObjectPointerType()) { + if (const ObjCObjectPointerType *OPT = getAs()) { if (OPT->isObjCQualifiedIdType()) return OPT; } return 0; } -const TemplateTypeParmType *Type::getAsTemplateTypeParmType() const { - // There is no sugar for template type parameters, so just return - // the canonical type pointer if it is the right class. - // FIXME: can these be address-space qualified? - return dyn_cast(CanonicalType); +const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { + if (const ObjCObjectPointerType *OPT = getAs()) { + if (OPT->getInterfaceType()) + return OPT; + } + return 0; } -const TemplateSpecializationType * -Type::getAsTemplateSpecializationType() const { - // There is no sugar for class template specialization types, so - // just return the canonical type pointer if it is the right class. - return dyn_cast(CanonicalType); +const CXXRecordDecl *Type::getCXXRecordDeclForPointerType() const { + if (const PointerType *PT = getAs()) + if (const RecordType *RT = PT->getPointeeType()->getAs()) + return dyn_cast(RT->getDecl()); + return 0; } bool Type::isIntegerType() const { @@ -620,8 +365,6 @@ bool Type::isIntegerType() const { return true; if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isIntegerType(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isIntegerType(); return false; } @@ -635,24 +378,18 @@ bool Type::isIntegralType() const { // FIXME: In C++, enum types are never integral. if (isa(CanonicalType)) return true; - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isIntegralType(); return false; } bool Type::isEnumeralType() const { if (const TagType *TT = dyn_cast(CanonicalType)) return TT->getDecl()->isEnum(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isEnumeralType(); return false; } bool Type::isBooleanType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Bool; - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isBooleanType(); return false; } @@ -662,16 +399,12 @@ bool Type::isCharType() const { BT->getKind() == BuiltinType::UChar || BT->getKind() == BuiltinType::Char_S || BT->getKind() == BuiltinType::SChar; - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isCharType(); return false; } bool Type::isWideCharType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::WChar; - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isWideCharType(); return false; } @@ -684,18 +417,16 @@ bool Type::isSignedIntegerType() const { return BT->getKind() >= BuiltinType::Char_S && BT->getKind() <= BuiltinType::LongLong; } - + if (const EnumType *ET = dyn_cast(CanonicalType)) return ET->getDecl()->getIntegerType()->isSignedIntegerType(); - + if (const FixedWidthIntType *FWIT = dyn_cast(CanonicalType)) return FWIT->isSigned(); - + if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isSignedIntegerType(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isSignedIntegerType(); return false; } @@ -718,8 +449,6 @@ bool Type::isUnsignedIntegerType() const { if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isUnsignedIntegerType(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isUnsignedIntegerType(); return false; } @@ -731,8 +460,6 @@ bool Type::isFloatingType() const { return CT->getElementType()->isFloatingType(); if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isFloatingType(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isFloatingType(); return false; } @@ -742,8 +469,6 @@ bool Type::isRealFloatingType() const { BT->getKind() <= BuiltinType::LongDouble; if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isRealFloatingType(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isRealFloatingType(); return false; } @@ -757,8 +482,6 @@ bool Type::isRealType() const { return true; if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isRealType(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isRealType(); return false; } @@ -772,8 +495,6 @@ bool Type::isArithmeticType() const { return ET->getDecl()->isDefinition(); if (isa(CanonicalType)) return true; - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isArithmeticType(); return isa(CanonicalType) || isa(CanonicalType); } @@ -787,8 +508,6 @@ bool Type::isScalarType() const { return true; return false; } - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isScalarType(); if (isa(CanonicalType)) return true; return isa(CanonicalType) || @@ -815,8 +534,6 @@ bool Type::isAggregateType() const { return true; } - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isAggregateType(); return isa(CanonicalType); } @@ -824,8 +541,6 @@ bool Type::isAggregateType() const { /// according to the rules of C99 6.7.5p3. It is not legal to call this on /// incomplete types or dependent types. bool Type::isConstantSizeType() const { - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isConstantSizeType(); assert(!isIncompleteType() && "This doesn't make sense for incomplete types"); assert(!isDependentType() && "This doesn't make sense for dependent types"); // The VAT must have a size, as it is known to be complete. @@ -835,11 +550,9 @@ bool Type::isConstantSizeType() const { /// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1) /// - a type that can describe objects, but which lacks information needed to /// determine its size. -bool Type::isIncompleteType() const { - switch (CanonicalType->getTypeClass()) { +bool Type::isIncompleteType() const { + switch (CanonicalType->getTypeClass()) { default: return false; - case ExtQual: - return cast(CanonicalType)->getBaseType()->isIncompleteType(); case Builtin: // Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never // be completed. @@ -853,7 +566,6 @@ bool Type::isIncompleteType() const { // An array of unknown size is an incomplete type (C99 6.2.5p22). return true; case ObjCInterface: - case ObjCQualifiedInterface: // ObjC interfaces are incomplete if they are @class, not @interface. return cast(this)->getDecl()->isForwardDecl(); } @@ -869,8 +581,6 @@ bool Type::isPODType() const { switch (CanonicalType->getTypeClass()) { // Everything not explicitly mentioned is not POD. default: return false; - case ExtQual: - return cast(CanonicalType)->getBaseType()->isPODType(); case VariableArray: case ConstantArray: // IncompleteArray is caught by isIncompleteType() above. @@ -889,7 +599,7 @@ bool Type::isPODType() const { return true; case Record: - if (CXXRecordDecl *ClassDecl + if (CXXRecordDecl *ClassDecl = dyn_cast(cast(CanonicalType)->getDecl())) return ClassDecl->isPOD(); @@ -899,7 +609,7 @@ bool Type::isPODType() const { } bool Type::isPromotableIntegerType() const { - if (const BuiltinType *BT = getAsBuiltinType()) + if (const BuiltinType *BT = getAs()) switch (BT->getKind()) { case BuiltinType::Bool: case BuiltinType::Char_S: @@ -909,14 +619,14 @@ bool Type::isPromotableIntegerType() const { case BuiltinType::Short: case BuiltinType::UShort: return true; - default: + default: return false; } return false; } bool Type::isNullPtrType() const { - if (const BuiltinType *BT = getAsBuiltinType()) + if (const BuiltinType *BT = getAs()) return BT->getKind() == BuiltinType::NullPtr; return false; } @@ -936,7 +646,6 @@ bool Type::isSpecifierType() const { case QualifiedName: case Typename: case ObjCInterface: - case ObjCQualifiedInterface: case ObjCObjectPointer: return true; default: @@ -944,6 +653,15 @@ bool Type::isSpecifierType() const { } } +const char *Type::getTypeClassName() const { + switch (TC) { + default: assert(0 && "Type class not in TypeNodes.def!"); +#define ABSTRACT_TYPE(Derived, Base) +#define TYPE(Derived, Base) case Derived: return #Derived; +#include "clang/AST/TypeNodes.def" + } +} + const char *BuiltinType::getName(const LangOptions &LO) const { switch (getKind()) { default: assert(0 && "Unknown builtin type!"); @@ -967,10 +685,14 @@ const char *BuiltinType::getName(const LangOptions &LO) const { case Double: return "double"; case LongDouble: return "long double"; case WChar: return "wchar_t"; + case Char16: return "char16_t"; + case Char32: return "char32_t"; case NullPtr: return "nullptr_t"; case Overload: return ""; case Dependent: return ""; - case UndeducedAuto: return ""; + case UndeducedAuto: return "auto"; + case ObjCId: return "id"; + case ObjCClass: return "Class"; } } @@ -979,7 +701,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, unsigned NumArgs, bool isVariadic, unsigned TypeQuals, bool hasExceptionSpec, bool anyExceptionSpec, unsigned NumExceptions, - exception_iterator Exs) { + exception_iterator Exs, bool NoReturn) { ID.AddPointer(Result.getAsOpaquePtr()); for (unsigned i = 0; i != NumArgs; ++i) ID.AddPointer(ArgTys[i].getAsOpaquePtr()); @@ -988,41 +710,43 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, ID.AddInteger(hasExceptionSpec); if (hasExceptionSpec) { ID.AddInteger(anyExceptionSpec); - for(unsigned i = 0; i != NumExceptions; ++i) + for (unsigned i = 0; i != NumExceptions; ++i) ID.AddPointer(Exs[i].getAsOpaquePtr()); } + ID.AddInteger(NoReturn); } void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(), getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(), - getNumExceptions(), exception_begin()); + getNumExceptions(), exception_begin(), getNoReturnAttr()); } void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID, - const ObjCInterfaceDecl *Decl, - ObjCProtocolDecl **protocols, + QualType OIT, ObjCProtocolDecl **protocols, unsigned NumProtocols) { - ID.AddPointer(Decl); + ID.AddPointer(OIT.getAsOpaquePtr()); for (unsigned i = 0; i != NumProtocols; i++) ID.AddPointer(protocols[i]); } void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getDecl(), &Protocols[0], getNumProtocols()); + if (getNumProtocols()) + Profile(ID, getPointeeType(), &Protocols[0], getNumProtocols()); + else + Profile(ID, getPointeeType(), 0, 0); } -void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID, - const ObjCInterfaceDecl *Decl, - ObjCProtocolDecl **protocols, - unsigned NumProtocols) { - ID.AddPointer(Decl); +void ObjCProtocolListType::Profile(llvm::FoldingSetNodeID &ID, + QualType OIT, ObjCProtocolDecl **protocols, + unsigned NumProtocols) { + ID.AddPointer(OIT.getAsOpaquePtr()); for (unsigned i = 0; i != NumProtocols; i++) ID.AddPointer(protocols[i]); } -void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getDecl(), &Protocols[0], getNumProtocols()); +void ObjCProtocolListType::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getBaseType(), &Protocols[0], getNumProtocols()); } /// LookThroughTypedefs - Return the ultimate type this typedef corresponds to @@ -1037,38 +761,51 @@ QualType TypedefType::LookThroughTypedefs() const { QualType FirstType = getDecl()->getUnderlyingType(); if (!isa(FirstType)) return FirstType; - + // Otherwise, do the fully general loop. - unsigned TypeQuals = 0; + QualifierCollector Qs; + + QualType CurType; const TypedefType *TDT = this; - while (1) { - QualType CurType = TDT->getDecl()->getUnderlyingType(); - - - /// FIXME: - /// FIXME: This is incorrect for ExtQuals! - /// FIXME: - TypeQuals |= CurType.getCVRQualifiers(); - - TDT = dyn_cast(CurType); - if (TDT == 0) - return QualType(CurType.getTypePtr(), TypeQuals); - } + do { + CurType = TDT->getDecl()->getUnderlyingType(); + TDT = dyn_cast(Qs.strip(CurType)); + } while (TDT); + + return Qs.apply(CurType); +} + +QualType TypedefType::desugar() const { + return getDecl()->getUnderlyingType(); } TypeOfExprType::TypeOfExprType(Expr *E, QualType can) : Type(TypeOfExpr, can, E->isTypeDependent()), TOExpr(E) { - assert(!isa(can) && "Invalid canonical type"); } -DecltypeType::DecltypeType(Expr *E, QualType can) - : Type(Decltype, can, E->isTypeDependent()), E(E) { - assert(can->isDependentType() == E->isTypeDependent() && - "type dependency mismatch!"); - assert(!isa(can) && "Invalid canonical type"); +QualType TypeOfExprType::desugar() const { + return getUnderlyingExpr()->getType(); +} + +void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context, Expr *E) { + E->Profile(ID, Context, true); } -TagType::TagType(TypeClass TC, TagDecl *D, QualType can) +DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can) + : Type(Decltype, can, E->isTypeDependent()), E(E), + UnderlyingType(underlyingType) { +} + +DependentDecltypeType::DependentDecltypeType(ASTContext &Context, Expr *E) + : DecltypeType(E, Context.DependentTy), Context(Context) { } + +void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context, Expr *E) { + E->Profile(ID, Context, true); +} + +TagType::TagType(TypeClass TC, TagDecl *D, QualType can) : Type(TC, can, D->isDependentType()), decl(D, 0) {} bool RecordType::classof(const TagType *TT) { @@ -1079,7 +816,7 @@ bool EnumType::classof(const TagType *TT) { return isa(TT->getDecl()); } -bool +bool TemplateSpecializationType:: anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) { for (unsigned Idx = 0; Idx < NumArgs; ++Idx) { @@ -1087,12 +824,12 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) { case TemplateArgument::Null: assert(false && "Should not have a NULL template argument"); break; - + case TemplateArgument::Type: if (Args[Idx].getAsType()->isDependentType()) return true; break; - + case TemplateArgument::Declaration: case TemplateArgument::Integral: // Never dependent @@ -1103,7 +840,7 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) { Args[Idx].getAsExpr()->isValueDependent()) return true; break; - + case TemplateArgument::Pack: assert(0 && "FIXME: Implement!"); break; @@ -1114,18 +851,19 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) { } TemplateSpecializationType:: -TemplateSpecializationType(TemplateName T, const TemplateArgument *Args, +TemplateSpecializationType(ASTContext &Context, TemplateName T, + const TemplateArgument *Args, unsigned NumArgs, QualType Canon) - : Type(TemplateSpecialization, + : Type(TemplateSpecialization, Canon.isNull()? QualType(this, 0) : Canon, T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)), - Template(T), NumArgs(NumArgs) -{ - assert((!Canon.isNull() || + Context(Context), + Template(T), NumArgs(NumArgs) { + assert((!Canon.isNull() || T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) && "No canonical type for non-dependent class template specialization"); - TemplateArgument *TemplateArgs + TemplateArgument *TemplateArgs = reinterpret_cast(this + 1); for (unsigned Arg = 0; Arg < NumArgs; ++Arg) new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]); @@ -1151,16 +889,34 @@ TemplateSpecializationType::getArg(unsigned Idx) const { return getArgs()[Idx]; } -void -TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, - TemplateName T, - const TemplateArgument *Args, - unsigned NumArgs) { +void +TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, + TemplateName T, + const TemplateArgument *Args, + unsigned NumArgs, + ASTContext &Context) { T.Profile(ID); for (unsigned Idx = 0; Idx < NumArgs; ++Idx) - Args[Idx].Profile(ID); + Args[Idx].Profile(ID, Context); +} + +QualType QualifierCollector::apply(QualType QT) const { + if (!hasNonFastQualifiers()) + return QT.withFastQualifiers(getFastQualifiers()); + + assert(Context && "extended qualifiers but no context!"); + return Context->getQualifiedType(QT, *this); +} + +QualType QualifierCollector::apply(const Type *T) const { + if (!hasNonFastQualifiers()) + return QualType(T, getFastQualifiers()); + + assert(Context && "extended qualifiers but no context!"); + return Context->getQualifiedType(T, *this); } + //===----------------------------------------------------------------------===// // Type Printing //===----------------------------------------------------------------------===// @@ -1188,14 +944,46 @@ void Type::dump() const { static void AppendTypeQualList(std::string &S, unsigned TypeQuals) { - // Note: funkiness to ensure we get a space only between quals. - bool NonePrinted = true; - if (TypeQuals & QualType::Const) - S += "const", NonePrinted = false; - if (TypeQuals & QualType::Volatile) - S += (NonePrinted+" volatile"), NonePrinted = false; - if (TypeQuals & QualType::Restrict) - S += (NonePrinted+" restrict"), NonePrinted = false; + if (TypeQuals & Qualifiers::Const) { + if (!S.empty()) S += ' '; + S += "const"; + } + if (TypeQuals & Qualifiers::Volatile) { + if (!S.empty()) S += ' '; + S += "volatile"; + } + if (TypeQuals & Qualifiers::Restrict) { + if (!S.empty()) S += ' '; + S += "restrict"; + } +} + +std::string Qualifiers::getAsString() const { + LangOptions LO; + return getAsString(PrintingPolicy(LO)); +} + +// Appends qualifiers to the given string, separated by spaces. Will +// prefix a space if the string is non-empty. Will not append a final +// space. +void Qualifiers::getAsStringInternal(std::string &S, + const PrintingPolicy&) const { + AppendTypeQualList(S, getCVRQualifiers()); + if (unsigned AddressSpace = getAddressSpace()) { + if (!S.empty()) S += ' '; + S += "__attribute__((address_space("; + S += llvm::utostr_32(AddressSpace); + S += ")))"; + } + if (Qualifiers::GC GCAttrType = getObjCGCAttr()) { + if (!S.empty()) S += ' '; + S += "__attribute__((objc_gc("; + if (GCAttrType == Qualifiers::Weak) + S += "weak"; + else + S += "strong"; + S += ")))"; + } } std::string QualType::getAsString() const { @@ -1205,8 +993,8 @@ std::string QualType::getAsString() const { return S; } -void -QualType::getAsStringInternal(std::string &S, +void +QualType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { if (isNull()) { S += "NULL TYPE"; @@ -1217,19 +1005,22 @@ QualType::getAsStringInternal(std::string &S, return; // Print qualifiers as appropriate. - if (unsigned Tq = getCVRQualifiers()) { + Qualifiers Quals = getQualifiers(); + if (!Quals.empty()) { std::string TQS; - AppendTypeQualList(TQS, Tq); - if (!S.empty()) - S = TQS + ' ' + S; - else - S = TQS; + Quals.getAsStringInternal(TQS, Policy); + + if (!S.empty()) { + TQS += ' '; + TQS += S; + } + std::swap(S, TQS); } getTypePtr()->getAsStringInternal(S, Policy); } -void BuiltinType::getAsStringInternal(std::string &S, +void BuiltinType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { if (S.empty()) { S = getName(Policy.LangOpts); @@ -1260,33 +1051,14 @@ void ComplexType::getAsStringInternal(std::string &S, const PrintingPolicy &Poli S = "_Complex " + S; } -void ExtQualType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - bool NeedsSpace = false; - if (AddressSpace) { - S = "__attribute__((address_space("+llvm::utostr_32(AddressSpace)+")))" + S; - NeedsSpace = true; - } - if (GCAttrType != QualType::GCNone) { - if (NeedsSpace) - S += ' '; - S += "__attribute__((objc_gc("; - if (GCAttrType == QualType::Weak) - S += "weak"; - else - S += "strong"; - S += ")))"; - } - BaseType->getAsStringInternal(S, Policy); -} - void PointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { S = '*' + S; - + // Handle things like 'int (*A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. if (isa(getPointeeType())) S = '(' + S + ')'; - + getPointeeType().getAsStringInternal(S, Policy); } @@ -1335,10 +1107,33 @@ void ConstantArrayType::getAsStringInternal(std::string &S, const PrintingPolicy S += '['; S += llvm::utostr(getSize().getZExtValue()); S += ']'; - + getElementType().getAsStringInternal(S, Policy); } +void ConstantArrayWithExprType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + if (Policy.ConstantArraySizeAsWritten) { + std::string SStr; + llvm::raw_string_ostream s(SStr); + getSizeExpr()->printPretty(s, 0, Policy); + S += '['; + S += s.str(); + S += ']'; + getElementType().getAsStringInternal(S, Policy); + } + else + ConstantArrayType::getAsStringInternal(S, Policy); +} + +void ConstantArrayWithoutExprType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + if (Policy.ConstantArraySizeAsWritten) { + S += "[]"; + getElementType().getAsStringInternal(S, Policy); + } + else + ConstantArrayType::getAsStringInternal(S, Policy); +} + void IncompleteArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { S += "[]"; @@ -1347,17 +1142,17 @@ void IncompleteArrayType::getAsStringInternal(std::string &S, const PrintingPoli void VariableArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { S += '['; - - if (getIndexTypeQualifier()) { - AppendTypeQualList(S, getIndexTypeQualifier()); + + if (getIndexTypeQualifiers().hasQualifiers()) { + AppendTypeQualList(S, getIndexTypeCVRQualifiers()); S += ' '; } - + if (getSizeModifier() == Static) S += "static"; else if (getSizeModifier() == Star) S += '*'; - + if (getSizeExpr()) { std::string SStr; llvm::raw_string_ostream s(SStr); @@ -1365,23 +1160,23 @@ void VariableArrayType::getAsStringInternal(std::string &S, const PrintingPolicy S += s.str(); } S += ']'; - + getElementType().getAsStringInternal(S, Policy); } void DependentSizedArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { S += '['; - - if (getIndexTypeQualifier()) { - AppendTypeQualList(S, getIndexTypeQualifier()); + + if (getIndexTypeQualifiers().hasQualifiers()) { + AppendTypeQualList(S, getIndexTypeCVRQualifiers()); S += ' '; } - + if (getSizeModifier() == Static) S += "static"; else if (getSizeModifier() == Star) S += '*'; - + if (getSizeExpr()) { std::string SStr; llvm::raw_string_ostream s(SStr); @@ -1389,7 +1184,7 @@ void DependentSizedArrayType::getAsStringInternal(std::string &S, const Printing S += s.str(); } S += ']'; - + getElementType().getAsStringInternal(S, Policy); } @@ -1439,7 +1234,7 @@ void TypeOfType::getAsStringInternal(std::string &InnerString, const PrintingPol InnerString = "typeof(" + Tmp + ")" + InnerString; } -void DecltypeType::getAsStringInternal(std::string &InnerString, +void DecltypeType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { if (!InnerString.empty()) // Prefix the basic type, e.g. 'decltype(t) X'. InnerString = ' ' + InnerString; @@ -1453,8 +1248,10 @@ void FunctionNoProtoType::getAsStringInternal(std::string &S, const PrintingPoli // If needed for precedence reasons, wrap the inner part in grouping parens. if (!S.empty()) S = "(" + S + ")"; - + S += "()"; + if (getNoReturnAttr()) + S += " __attribute__((noreturn))"; getResultType().getAsStringInternal(S, Policy); } @@ -1462,7 +1259,7 @@ void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy // If needed for precedence reasons, wrap the inner part in grouping parens. if (!S.empty()) S = "(" + S + ")"; - + S += "("; std::string Tmp; PrintingPolicy ParamPolicy(Policy); @@ -1473,7 +1270,7 @@ void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy S += Tmp; Tmp.clear(); } - + if (isVariadic()) { if (getNumArgs()) S += ", "; @@ -1482,8 +1279,10 @@ void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy // Do not emit int() if we have a proto, emit 'int(void)'. S += "void"; } - + S += ")"; + if (getNoReturnAttr()) + S += " __attribute__((noreturn))"; getResultType().getAsStringInternal(S, Policy); } @@ -1499,13 +1298,13 @@ void TemplateTypeParmType::getAsStringInternal(std::string &InnerString, const P InnerString = ' ' + InnerString; if (!Name) - InnerString = "type-parameter-" + llvm::utostr_32(Depth) + '-' + + InnerString = "type-parameter-" + llvm::utostr_32(Depth) + '-' + llvm::utostr_32(Index) + InnerString; else InnerString = Name->getName() + InnerString; } -std::string +std::string TemplateSpecializationType::PrintTemplateArgumentList( const TemplateArgument *Args, unsigned NumArgs, @@ -1515,7 +1314,7 @@ TemplateSpecializationType::PrintTemplateArgumentList( for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { if (Arg) SpecString += ", "; - + // Print the argument into a string. std::string ArgString; switch (Args[Arg].getKind()) { @@ -1565,7 +1364,7 @@ TemplateSpecializationType::PrintTemplateArgumentList( return SpecString; } -void +void TemplateSpecializationType:: getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { std::string SpecString; @@ -1589,10 +1388,11 @@ void QualifiedNameType::getAsStringInternal(std::string &InnerString, const Prin llvm::raw_string_ostream OS(MyString); NNS->print(OS, Policy); } - + std::string TypeStr; PrintingPolicy InnerPolicy(Policy); InnerPolicy.SuppressTagKind = true; + InnerPolicy.SuppressScope = true; NamedType.getAsStringInternal(TypeStr, InnerPolicy); MyString += TypeStr; @@ -1615,35 +1415,65 @@ void TypenameType::getAsStringInternal(std::string &InnerString, const PrintingP else if (const TemplateSpecializationType *Spec = getTemplateId()) { Spec->getTemplateName().print(OS, Policy, true); OS << TemplateSpecializationType::PrintTemplateArgumentList( - Spec->getArgs(), + Spec->getArgs(), Spec->getNumArgs(), Policy); } } - + if (InnerString.empty()) InnerString.swap(MyString); else InnerString = MyString + ' ' + InnerString; } -void ObjCInterfaceType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. - InnerString = ' ' + InnerString; - InnerString = getDecl()->getIdentifier()->getName() + InnerString; +void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID, + const ObjCInterfaceDecl *Decl, + ObjCProtocolDecl **protocols, + unsigned NumProtocols) { + ID.AddPointer(Decl); + for (unsigned i = 0; i != NumProtocols; i++) + ID.AddPointer(protocols[i]); } -void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString, - const PrintingPolicy &Policy) const { +void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID) { + if (getNumProtocols()) + Profile(ID, getDecl(), &Protocols[0], getNumProtocols()); + else + Profile(ID, getDecl(), 0, 0); +} + +void ObjCInterfaceType::getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const { if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. InnerString = ' ' + InnerString; + std::string ObjCQIString = getDecl()->getNameAsString(); + if (getNumProtocols()) { + ObjCQIString += '<'; + bool isFirst = true; + for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) { + if (isFirst) + isFirst = false; + else + ObjCQIString += ','; + ObjCQIString += (*I)->getNameAsString(); + } + ObjCQIString += '>'; + } + InnerString = ObjCQIString + InnerString; +} + +void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const { std::string ObjCQIString; - - if (getDecl()) - ObjCQIString = getDecl()->getNameAsString(); - else + + if (isObjCIdType() || isObjCQualifiedIdType()) ObjCQIString = "id"; + else if (isObjCClassType() || isObjCQualifiedClassType()) + ObjCQIString = "Class"; + else + ObjCQIString = getInterfaceDecl()->getNameAsString(); if (!qual_empty()) { ObjCQIString += '<'; @@ -1654,15 +1484,23 @@ void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString, } ObjCQIString += '>'; } + + PointeeType.getQualifiers().getAsStringInternal(ObjCQIString, Policy); + + if (!isObjCIdType() && !isObjCQualifiedIdType()) + ObjCQIString += " *"; // Don't forget the implicit pointer. + else if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + InnerString = ObjCQIString + InnerString; } -void -ObjCQualifiedInterfaceType::getAsStringInternal(std::string &InnerString, +void ObjCProtocolListType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. InnerString = ' ' + InnerString; - std::string ObjCQIString = getDecl()->getNameAsString(); + + std::string ObjCQIString = getBaseType().getAsString(Policy); ObjCQIString += '<'; bool isFirst = true; for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) { @@ -1676,13 +1514,23 @@ ObjCQualifiedInterfaceType::getAsStringInternal(std::string &InnerString, InnerString = ObjCQIString + InnerString; } +void ElaboratedType::getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const { + std::string TypeStr; + PrintingPolicy InnerPolicy(Policy); + InnerPolicy.SuppressTagKind = true; + UnderlyingType.getAsStringInternal(InnerString, InnerPolicy); + + InnerString = std::string(getNameForTagKind(getTagKind())) + ' ' + InnerString; +} + void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { if (Policy.SuppressTag) return; if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. InnerString = ' ' + InnerString; - + const char *Kind = Policy.SuppressTagKind? 0 : getDecl()->getKindName(); const char *ID; if (const IdentifierInfo *II = getDecl()->getIdentifier()) @@ -1696,10 +1544,10 @@ void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy // If this is a class template specialization, print the template // arguments. - if (ClassTemplateSpecializationDecl *Spec + if (ClassTemplateSpecializationDecl *Spec = dyn_cast(getDecl())) { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); - std::string TemplateArgsStr + std::string TemplateArgsStr = TemplateSpecializationType::PrintTemplateArgumentList( TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size(), @@ -1707,17 +1555,17 @@ void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy InnerString = TemplateArgsStr + InnerString; } - if (Kind) { + if (!Policy.SuppressScope) { // Compute the full nested-name-specifier for this type. In C, // this will always be empty. std::string ContextStr; - for (DeclContext *DC = getDecl()->getDeclContext(); + for (DeclContext *DC = getDecl()->getDeclContext(); !DC->isTranslationUnit(); DC = DC->getParent()) { std::string MyPart; if (NamespaceDecl *NS = dyn_cast(DC)) { if (NS->getIdentifier()) MyPart = NS->getNameAsString(); - } else if (ClassTemplateSpecializationDecl *Spec + } else if (ClassTemplateSpecializationDecl *Spec = dyn_cast(DC)) { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); std::string TemplateArgsStr @@ -1737,7 +1585,10 @@ void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy ContextStr = MyPart + "::" + ContextStr; } - InnerString = std::string(Kind) + " " + ContextStr + ID + InnerString; + if (Kind) + InnerString = std::string(Kind) + ' ' + ContextStr + ID + InnerString; + else + InnerString = ContextStr + ID + InnerString; } else InnerString = ID + InnerString; } diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp new file mode 100644 index 000000000000..c24477ae81c5 --- /dev/null +++ b/lib/AST/TypeLoc.cpp @@ -0,0 +1,370 @@ +//===--- TypeLoc.cpp - Type Source Info Wrapper -----------------*- 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 TypeLoc subclasses implementations. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/TypeLocVisitor.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// TypeLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +/// \brief Return the source range for the visited TypeSpecLoc. +class TypeLocRanger : public TypeLocVisitor { +public: +#define ABSTRACT_TYPELOC(CLASS) +#define TYPELOC(CLASS, PARENT, TYPE) \ + SourceRange Visit##CLASS(CLASS TyLoc) { return TyLoc.getSourceRange(); } +#include "clang/AST/TypeLocNodes.def" + + SourceRange VisitTypeLoc(TypeLoc TyLoc) { + assert(0 && "A typeloc wrapper was not handled!"); + return SourceRange(); + } +}; + +} + +SourceRange TypeLoc::getSourceRange() const { + if (isNull()) + return SourceRange(); + return TypeLocRanger().Visit(*this); +} + +/// \brief Returns the size of type source info data block for the given type. +unsigned TypeLoc::getFullDataSizeForType(QualType Ty) { + return TypeLoc(Ty, 0).getFullDataSize(); +} + +/// \brief Find the TypeSpecLoc that is part of this TypeLoc. +TypeSpecLoc TypeLoc::getTypeSpecLoc() const { + if (isNull()) + return TypeSpecLoc(); + + if (const DeclaratorLoc *DL = dyn_cast(this)) + return DL->getTypeSpecLoc(); + return cast(*this); +} + +/// \brief Find the TypeSpecLoc that is part of this TypeLoc and return its +/// SourceRange. +SourceRange TypeLoc::getTypeSpecRange() const { + return getTypeSpecLoc().getSourceRange(); +} + +namespace { + +/// \brief Report the full source info data size for the visited TypeLoc. +class TypeSizer : public TypeLocVisitor { +public: +#define ABSTRACT_TYPELOC(CLASS) +#define TYPELOC(CLASS, PARENT, TYPE) \ + unsigned Visit##CLASS(CLASS TyLoc) { return TyLoc.getFullDataSize(); } +#include "clang/AST/TypeLocNodes.def" + + unsigned VisitTypeLoc(TypeLoc TyLoc) { + assert(0 && "A type loc wrapper was not handled!"); + return 0; + } +}; + +} + +/// \brief Returns the size of the type source info data block. +unsigned TypeLoc::getFullDataSize() const { + if (isNull()) return 0; + return TypeSizer().Visit(*this); +} + +namespace { + +/// \brief Return the "next" TypeLoc for the visited TypeLoc, e.g for "int*" the +/// TypeLoc is a PointerLoc and next TypeLoc is for "int". +class NextLoc : public TypeLocVisitor { +public: +#define TYPELOC(CLASS, PARENT, TYPE) +#define DECLARATOR_TYPELOC(CLASS, TYPE) \ + TypeLoc Visit##CLASS(CLASS TyLoc); +#include "clang/AST/TypeLocNodes.def" + + TypeLoc VisitTypeSpecLoc(TypeLoc TyLoc) { return TypeLoc(); } + TypeLoc VisitObjCProtocolListLoc(ObjCProtocolListLoc TL); + + TypeLoc VisitTypeLoc(TypeLoc TyLoc) { + assert(0 && "A declarator loc wrapper was not handled!"); + return TypeLoc(); + } +}; + +} + +TypeLoc NextLoc::VisitObjCProtocolListLoc(ObjCProtocolListLoc TL) { + return TL.getBaseTypeLoc(); +} + +TypeLoc NextLoc::VisitPointerLoc(PointerLoc TL) { + return TL.getPointeeLoc(); +} +TypeLoc NextLoc::VisitMemberPointerLoc(MemberPointerLoc TL) { + return TL.getPointeeLoc(); +} +TypeLoc NextLoc::VisitBlockPointerLoc(BlockPointerLoc TL) { + return TL.getPointeeLoc(); +} +TypeLoc NextLoc::VisitReferenceLoc(ReferenceLoc TL) { + return TL.getPointeeLoc(); +} +TypeLoc NextLoc::VisitFunctionLoc(FunctionLoc TL) { + return TL.getResultLoc(); +} +TypeLoc NextLoc::VisitArrayLoc(ArrayLoc TL) { + return TL.getElementLoc(); +} + +/// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the +/// TypeLoc is a PointerLoc and next TypeLoc is for "int". +TypeLoc TypeLoc::getNextTypeLoc() const { + return NextLoc().Visit(*this); +} + +//===----------------------------------------------------------------------===// +// TypeSpecLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { +class TypeSpecChecker : public TypeLocVisitor { +public: + bool VisitTypeSpecLoc(TypeSpecLoc TyLoc) { return true; } +}; + +} + +bool TypeSpecLoc::classof(const TypeLoc *TL) { + return TypeSpecChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// DeclaratorLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +/// \brief Return the TypeSpecLoc for the visited DeclaratorLoc. +class TypeSpecGetter : public TypeLocVisitor { +public: +#define TYPELOC(CLASS, PARENT, TYPE) +#define DECLARATOR_TYPELOC(CLASS, TYPE) \ + TypeSpecLoc Visit##CLASS(CLASS TyLoc) { return TyLoc.getTypeSpecLoc(); } +#include "clang/AST/TypeLocNodes.def" + + TypeSpecLoc VisitTypeLoc(TypeLoc TyLoc) { + assert(0 && "A declarator loc wrapper was not handled!"); + return TypeSpecLoc(); + } +}; + +} + +/// \brief Find the TypeSpecLoc that is part of this DeclaratorLoc. +TypeSpecLoc DeclaratorLoc::getTypeSpecLoc() const { + return TypeSpecGetter().Visit(*this); +} + +namespace { + +class DeclaratorLocChecker : public TypeLocVisitor { +public: + bool VisitDeclaratorLoc(DeclaratorLoc TyLoc) { return true; } +}; + +} + +bool DeclaratorLoc::classof(const TypeLoc *TL) { + return DeclaratorLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// DefaultTypeSpecLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class DefaultTypeSpecLocChecker : + public TypeLocVisitor { +public: + bool VisitDefaultTypeSpecLoc(DefaultTypeSpecLoc TyLoc) { return true; } +}; + +} + +bool DefaultTypeSpecLoc::classof(const TypeLoc *TL) { + return DefaultTypeSpecLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// TypedefLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class TypedefLocChecker : public TypeLocVisitor { +public: + bool VisitTypedefLoc(TypedefLoc TyLoc) { return true; } +}; + +} + +bool TypedefLoc::classof(const TypeLoc *TL) { + return TypedefLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// ObjCInterfaceLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class ObjCInterfaceLocChecker : + public TypeLocVisitor { +public: + bool VisitObjCInterfaceLoc(ObjCInterfaceLoc TyLoc) { return true; } +}; + +} + +bool ObjCInterfaceLoc::classof(const TypeLoc *TL) { + return ObjCInterfaceLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// ObjCProtocolListLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class ObjCProtocolListLocChecker : + public TypeLocVisitor { +public: + bool VisitObjCProtocolListLoc(ObjCProtocolListLoc TyLoc) { return true; } +}; + +} + +bool ObjCProtocolListLoc::classof(const TypeLoc *TL) { + return ObjCProtocolListLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// PointerLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class PointerLocChecker : public TypeLocVisitor { +public: + bool VisitPointerLoc(PointerLoc TyLoc) { return true; } +}; + +} + +bool PointerLoc::classof(const TypeLoc *TL) { + return PointerLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// BlockPointerLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class BlockPointerLocChecker : + public TypeLocVisitor { +public: + bool VisitBlockPointerLoc(BlockPointerLoc TyLoc) { return true; } +}; + +} + +bool BlockPointerLoc::classof(const TypeLoc *TL) { + return BlockPointerLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// MemberPointerLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class MemberPointerLocChecker : + public TypeLocVisitor { +public: + bool VisitMemberPointerLoc(MemberPointerLoc TyLoc) { return true; } +}; + +} + +bool MemberPointerLoc::classof(const TypeLoc *TL) { + return MemberPointerLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// ReferenceLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class ReferenceLocChecker : public TypeLocVisitor { +public: + bool VisitReferenceLoc(ReferenceLoc TyLoc) { return true; } +}; + +} + +bool ReferenceLoc::classof(const TypeLoc *TL) { + return ReferenceLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// FunctionLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class FunctionLocChecker : public TypeLocVisitor { +public: + bool VisitFunctionLoc(FunctionLoc TyLoc) { return true; } +}; + +} + +bool FunctionLoc::classof(const TypeLoc *TL) { + return FunctionLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// ArrayLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class ArrayLocChecker : public TypeLocVisitor { +public: + bool VisitArrayLoc(ArrayLoc TyLoc) { return true; } +}; + +} + +bool ArrayLoc::classof(const TypeLoc *TL) { + return ArrayLocChecker().Visit(*TL); +} diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp new file mode 100644 index 000000000000..a4cb66be04b3 --- /dev/null +++ b/lib/Analysis/AnalysisContext.cpp @@ -0,0 +1,138 @@ +//== AnalysisContext.cpp - Analysis context for Path Sens analysis -*- 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 AnalysisContext, a class that manages the analysis context +// data for path sensitive analysis. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/AnalysisContext.h" +#include "clang/Analysis/Analyses/LiveVariables.h" +#include "clang/Analysis/CFG.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/ParentMap.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace clang; + +AnalysisContext::~AnalysisContext() { + delete cfg; + delete liveness; + delete PM; +} + +AnalysisContextManager::~AnalysisContextManager() { + for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I) + delete I->second; +} + +Stmt *AnalysisContext::getBody() { + if (const FunctionDecl *FD = dyn_cast(D)) + return FD->getBody(); + else if (const ObjCMethodDecl *MD = dyn_cast(D)) + return MD->getBody(); + + llvm::llvm_unreachable("unknown code decl"); +} + +const ImplicitParamDecl *AnalysisContext::getSelfDecl() const { + if (const ObjCMethodDecl *MD = dyn_cast(D)) + return MD->getSelfDecl(); + + return NULL; +} + +CFG *AnalysisContext::getCFG() { + if (!cfg) + cfg = CFG::buildCFG(getBody(), &D->getASTContext()); + return cfg; +} + +ParentMap &AnalysisContext::getParentMap() { + if (!PM) + PM = new ParentMap(getBody()); + return *PM; +} + +LiveVariables *AnalysisContext::getLiveVariables() { + if (!liveness) { + CFG *c = getCFG(); + if (!c) + return 0; + + liveness = new LiveVariables(D->getASTContext(), *c); + liveness->runOnCFG(*c); + liveness->runOnAllBlocks(*c, 0, true); + } + + return liveness; +} + +AnalysisContext *AnalysisContextManager::getContext(const Decl *D) { + AnalysisContext *&AC = Contexts[D]; + if (!AC) + AC = new AnalysisContext(D); + + return AC; +} + +void LocationContext::Profile(llvm::FoldingSetNodeID &ID, ContextKind k, + AnalysisContext *ctx, + const LocationContext *parent) { + ID.AddInteger(k); + ID.AddPointer(ctx); + ID.AddPointer(parent); +} + +void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID,AnalysisContext *ctx, + const LocationContext *parent, const Stmt *s) { + LocationContext::Profile(ID, StackFrame, ctx, parent); + ID.AddPointer(s); +} + +void ScopeContext::Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, + const LocationContext *parent, const Stmt *s) { + LocationContext::Profile(ID, Scope, ctx, parent); + ID.AddPointer(s); +} + +StackFrameContext* +LocationContextManager::getStackFrame(AnalysisContext *ctx, + const LocationContext *parent, + const Stmt *s) { + llvm::FoldingSetNodeID ID; + StackFrameContext::Profile(ID, ctx, parent, s); + void *InsertPos; + + StackFrameContext *f = + cast_or_null(Contexts.FindNodeOrInsertPos(ID, InsertPos)); + if (!f) { + f = new StackFrameContext(ctx, parent, s); + Contexts.InsertNode(f, InsertPos); + } + return f; +} + +ScopeContext *LocationContextManager::getScope(AnalysisContext *ctx, + const LocationContext *parent, + const Stmt *s) { + llvm::FoldingSetNodeID ID; + ScopeContext::Profile(ID, ctx, parent, s); + void *InsertPos; + + ScopeContext *scope = + cast_or_null(Contexts.FindNodeOrInsertPos(ID, InsertPos)); + + if (!scope) { + scope = new ScopeContext(ctx, parent, s); + Contexts.InsertNode(scope, InsertPos); + } + return scope; +} diff --git a/lib/Analysis/AnalysisManager.cpp b/lib/Analysis/AnalysisManager.cpp new file mode 100644 index 000000000000..c2733faa683c --- /dev/null +++ b/lib/Analysis/AnalysisManager.cpp @@ -0,0 +1,35 @@ +//== AnalysisManager.cpp - Path sensitive analysis data manager ----*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the AnalysisManager class. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/AnalysisManager.h" +#include "clang/Basic/SourceManager.h" + +using namespace clang; + +void AnalysisManager::DisplayFunction(Decl *D) { + + if (DisplayedFunction) + return; + + DisplayedFunction = true; + + // FIXME: Is getCodeDecl() always a named decl? + if (isa(D) || isa(D)) { + const NamedDecl *ND = cast(D); + SourceManager &SM = getASTContext().getSourceManager(); + (llvm::errs() << "ANALYZE: " + << SM.getPresumedLoc(ND->getLocation()).getFilename() + << ' ' << ND->getNameAsString() << '\n').flush(); + } +} + diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Analysis/BasicConstraintManager.cpp index cb89d3065107..d0b828952854 100644 --- a/lib/Analysis/BasicConstraintManager.cpp +++ b/lib/Analysis/BasicConstraintManager.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines BasicConstraintManager, a class that tracks simple +// This file defines BasicConstraintManager, a class that tracks simple // equality and inequality constraints on symbolic values of GRState. // //===----------------------------------------------------------------------===// @@ -27,22 +27,22 @@ namespace { class VISIBILITY_HIDDEN ConstEq {}; } typedef llvm::ImmutableMap ConstNotEqTy; typedef llvm::ImmutableMap ConstEqTy; - + static int ConstEqIndex = 0; static int ConstNotEqIndex = 0; namespace clang { template<> struct GRStateTrait : public GRStatePartialTrait { - static inline void* GDMIndex() { return &ConstNotEqIndex; } + static inline void* GDMIndex() { return &ConstNotEqIndex; } }; template<> struct GRStateTrait : public GRStatePartialTrait { - static inline void* GDMIndex() { return &ConstEqIndex; } + static inline void* GDMIndex() { return &ConstEqIndex; } }; -} - +} + namespace { // BasicConstraintManager only tracks equality and inequality constraints of // constants and integer variables. @@ -50,7 +50,7 @@ class VISIBILITY_HIDDEN BasicConstraintManager : public SimpleConstraintManager { GRState::IntSetTy::Factory ISetFactory; public: - BasicConstraintManager(GRStateManager& statemgr) + BasicConstraintManager(GRStateManager& statemgr) : ISetFactory(statemgr.getAllocator()) {} const GRState* AssumeSymNE(const GRState* state, SymbolRef sym, @@ -83,7 +83,7 @@ public: const GRState* RemoveDeadBindings(const GRState* state, SymbolReaper& SymReaper); - void print(const GRState* state, llvm::raw_ostream& Out, + void print(const GRState* state, llvm::raw_ostream& Out, const char* nl, const char *sep); }; @@ -133,7 +133,7 @@ const GRState *BasicConstraintManager::AssumeSymEQ(const GRState *state, // These logic will be handled in another ConstraintManager. const GRState *BasicConstraintManager::AssumeSymLT(const GRState *state, SymbolRef sym, - const llvm::APSInt& V) { + const llvm::APSInt& V) { // Is 'V' the smallest possible value? if (V == llvm::APSInt::getMinValue(V.getBitWidth(), V.isUnsigned())) { // sym cannot be any value less than 'V'. This path is infeasible. @@ -167,14 +167,14 @@ const GRState *BasicConstraintManager::AssumeSymGE(const GRState *state, bool isFeasible = *X >= V; return isFeasible ? state : NULL; } - + // Sym is not a constant, but it is worth looking to see if V is the // maximum integer value. if (V == llvm::APSInt::getMaxValue(V.getBitWidth(), V.isUnsigned())) { // If we know that sym != V, then this condition is infeasible since - // there is no other value greater than V. + // there is no other value greater than V. bool isFeasible = !isNotEqual(state, sym, V); - + // If the path is still feasible then as a consequence we know that // 'sym == V' because we cannot have 'sym > V' (no larger values). // Add this constraint. @@ -193,20 +193,20 @@ BasicConstraintManager::AssumeSymLE(const GRState* state, SymbolRef sym, bool isFeasible = *X <= V; return isFeasible ? state : NULL; } - + // Sym is not a constant, but it is worth looking to see if V is the // minimum integer value. if (V == llvm::APSInt::getMinValue(V.getBitWidth(), V.isUnsigned())) { // If we know that sym != V, then this condition is infeasible since - // there is no other value less than V. + // there is no other value less than V. bool isFeasible = !isNotEqual(state, sym, V); - + // If the path is still feasible then as a consequence we know that // 'sym == V' because we cannot have 'sym < V' (no smaller values). // Add this constraint. return isFeasible ? AddEQ(state, sym, V) : NULL; } - + return state; } @@ -222,10 +222,10 @@ const GRState* BasicConstraintManager::AddNE(const GRState* state, SymbolRef sym // First, retrieve the NE-set associated with the given symbol. ConstNotEqTy::data_type* T = state->get(sym); GRState::IntSetTy S = T ? *T : ISetFactory.GetEmptySet(); - + // Now add V to the NE set. S = ISetFactory.Add(S, &V); - + // Create a new state with the old binding replaced. return state->set(sym, S); } @@ -236,7 +236,7 @@ const llvm::APSInt* BasicConstraintManager::getSymVal(const GRState* state, return T ? *T : NULL; } -bool BasicConstraintManager::isNotEqual(const GRState* state, SymbolRef sym, +bool BasicConstraintManager::isNotEqual(const GRState* state, SymbolRef sym, const llvm::APSInt& V) const { // Retrieve the NE-set associated with the given symbol. @@ -273,14 +273,14 @@ BasicConstraintManager::RemoveDeadBindings(const GRState* state, ConstNotEqTy::Factory& CNEFactory = state->get_context(); for (ConstNotEqTy::iterator I = CNE.begin(), E = CNE.end(); I != E; ++I) { - SymbolRef sym = I.getKey(); + SymbolRef sym = I.getKey(); if (SymReaper.maybeDead(sym)) CNE = CNEFactory.Remove(CNE, sym); } - + return state->set(CNE); } -void BasicConstraintManager::print(const GRState* state, llvm::raw_ostream& Out, +void BasicConstraintManager::print(const GRState* state, llvm::raw_ostream& Out, const char* nl, const char *sep) { // Print equality constraints. @@ -293,23 +293,23 @@ void BasicConstraintManager::print(const GRState* state, llvm::raw_ostream& Out, } // Print != constraints. - + ConstNotEqTy CNE = state->get(); - + if (!CNE.isEmpty()) { Out << nl << sep << "'!=' constraints:"; - + for (ConstNotEqTy::iterator I = CNE.begin(), EI = CNE.end(); I!=EI; ++I) { Out << nl << " $" << I.getKey() << " : "; bool isFirst = true; - - GRState::IntSetTy::iterator J = I.getData().begin(), - EJ = I.getData().end(); - - for ( ; J != EJ; ++J) { + + GRState::IntSetTy::iterator J = I.getData().begin(), + EJ = I.getData().end(); + + for ( ; J != EJ; ++J) { if (isFirst) isFirst = false; else Out << ", "; - + Out << (*J)->getSExtValue(); // Hack: should print to raw_ostream. } } diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp index aa85769157e7..af300f36fa72 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/lib/Analysis/BasicObjCFoundationChecks.cpp @@ -31,26 +31,21 @@ using namespace clang; -static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) { - Expr* Receiver = ME->getReceiver(); - +static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) { + const Expr* Receiver = ME->getReceiver(); + if (!Receiver) return NULL; - - QualType X = Receiver->getType(); - - if (X->isPointerType()) { - Type* TP = X.getTypePtr(); - const PointerType* T = TP->getAsPointerType(); - return dyn_cast(T->getPointeeType().getTypePtr()); - } - // FIXME: Support ObjCQualifiedIdType? + if (const ObjCObjectPointerType *PT = + Receiver->getType()->getAs()) + return PT->getInterfaceType(); + return NULL; } -static const char* GetReceiverNameType(ObjCMessageExpr* ME) { - ObjCInterfaceType* ReceiverType = GetReceiverType(ME); +static const char* GetReceiverNameType(const ObjCMessageExpr* ME) { + const ObjCInterfaceType *ReceiverType = GetReceiverType(ME); return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName() : NULL; } @@ -61,76 +56,75 @@ class VISIBILITY_HIDDEN APIMisuse : public BugType { public: APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {} }; - + class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck { APIMisuse *BT; BugReporter& BR; ASTContext &Ctx; - - bool isNSString(ObjCInterfaceType* T, const char* suffix); - bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME); - - void Warn(NodeTy* N, Expr* E, const std::string& s); - void WarnNilArg(NodeTy* N, Expr* E); - - bool CheckNilArg(NodeTy* N, unsigned Arg); + + bool isNSString(const ObjCInterfaceType *T, const char* suffix); + bool AuditNSString(ExplodedNode* N, const ObjCMessageExpr* ME); + + void Warn(ExplodedNode* N, const Expr* E, const std::string& s); + void WarnNilArg(ExplodedNode* N, const Expr* E); + + bool CheckNilArg(ExplodedNode* N, unsigned Arg); public: - BasicObjCFoundationChecks(ASTContext& ctx, BugReporter& br) + BasicObjCFoundationChecks(ASTContext& ctx, BugReporter& br) : BT(0), BR(br), Ctx(ctx) {} - - bool Audit(ExplodedNode* N, GRStateManager&); - -private: - void WarnNilArg(NodeTy* N, ObjCMessageExpr* ME, unsigned Arg) { + + bool Audit(ExplodedNode* N, GRStateManager&); + +private: + void WarnNilArg(ExplodedNode* N, const ObjCMessageExpr* ME, unsigned Arg) { std::string sbuf; llvm::raw_string_ostream os(sbuf); os << "Argument to '" << GetReceiverNameType(ME) << "' method '" << ME->getSelector().getAsString() << "' cannot be nil."; - + // Lazily create the BugType object for NilArg. This will be owned // by the BugReporter object 'BR' once we call BR.EmitWarning. if (!BT) BT = new APIMisuse("nil argument"); - + RangedBugReport *R = new RangedBugReport(*BT, os.str().c_str(), N); R->addRange(ME->getArg(Arg)->getSourceRange()); BR.EmitReport(R); } }; - + } // end anonymous namespace GRSimpleAPICheck* clang::CreateBasicObjCFoundationChecks(ASTContext& Ctx, BugReporter& BR) { - return new BasicObjCFoundationChecks(Ctx, BR); + return new BasicObjCFoundationChecks(Ctx, BR); } -bool BasicObjCFoundationChecks::Audit(ExplodedNode* N, +bool BasicObjCFoundationChecks::Audit(ExplodedNode* N, GRStateManager&) { - - ObjCMessageExpr* ME = + + const ObjCMessageExpr* ME = cast(cast(N->getLocation()).getStmt()); - ObjCInterfaceType* ReceiverType = GetReceiverType(ME); - + const ObjCInterfaceType *ReceiverType = GetReceiverType(ME); + if (!ReceiverType) return false; - + const char* name = ReceiverType->getDecl()->getIdentifier()->getName(); - + if (!name) return false; if (name[0] != 'N' || name[1] != 'S') return false; - + name += 2; - + // FIXME: Make all of this faster. - if (isNSString(ReceiverType, name)) return AuditNSString(N, ME); @@ -138,24 +132,24 @@ bool BasicObjCFoundationChecks::Audit(ExplodedNode* N, } static inline bool isNil(SVal X) { - return isa(X); + return isa(X); } //===----------------------------------------------------------------------===// // Error reporting. //===----------------------------------------------------------------------===// -bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) { - ObjCMessageExpr* ME = +bool BasicObjCFoundationChecks::CheckNilArg(ExplodedNode* N, unsigned Arg) { + const ObjCMessageExpr* ME = cast(cast(N->getLocation()).getStmt()); - - Expr * E = ME->getArg(Arg); - + + const Expr * E = ME->getArg(Arg); + if (isNil(N->getState()->getSVal(E))) { WarnNilArg(N, ME, Arg); return true; } - + return false; } @@ -163,37 +157,36 @@ bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) { // NSString checking. //===----------------------------------------------------------------------===// -bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T, +bool BasicObjCFoundationChecks::isNSString(const ObjCInterfaceType *T, const char* suffix) { - return !strcmp("String", suffix) || !strcmp("MutableString", suffix); } -bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N, - ObjCMessageExpr* ME) { - +bool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N, + const ObjCMessageExpr* ME) { + Selector S = ME->getSelector(); - + if (S.isUnarySelector()) return false; // 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: + 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 @@ -201,41 +194,41 @@ bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N, // 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; - + + break; + case 37: if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:")) return CheckNilArg(N, 0); - - break; + + break; } - + return false; } @@ -247,7 +240,7 @@ namespace { class VISIBILITY_HIDDEN AuditCFNumberCreate : public GRSimpleAPICheck { APIMisuse* BT; - + // FIXME: Either this should be refactored into GRSimpleAPICheck, or // it should always be passed with a call to Audit. The latter // approach makes this class more stateless. @@ -256,16 +249,16 @@ class VISIBILITY_HIDDEN AuditCFNumberCreate : public GRSimpleAPICheck { BugReporter& BR; public: - AuditCFNumberCreate(ASTContext& ctx, BugReporter& br) + AuditCFNumberCreate(ASTContext& ctx, BugReporter& br) : BT(0), Ctx(ctx), II(&Ctx.Idents.get("CFNumberCreate")), BR(br){} - + ~AuditCFNumberCreate() {} - - bool Audit(ExplodedNode* N, GRStateManager&); - + + bool Audit(ExplodedNode* N, GRStateManager&); + private: - void AddError(const TypedRegion* R, Expr* Ex, ExplodedNode *N, - uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind); + void AddError(const TypedRegion* R, const Expr* Ex, ExplodedNode *N, + uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind); }; } // end anonymous namespace @@ -296,7 +289,7 @@ namespace { public: Optional() : IsKnown(false), Val(0) {} Optional(const T& val) : IsKnown(true), Val(val) {} - + bool isKnown() const { return IsKnown; } const T& getValue() const { @@ -312,12 +305,12 @@ namespace { static Optional GetCFNumberSize(ASTContext& Ctx, uint64_t i) { static unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 }; - + if (i < kCFNumberCharType) return FixedSize[i-1]; - + QualType T; - + switch (i) { case kCFNumberCharType: T = Ctx.CharTy; break; case kCFNumberShortType: T = Ctx.ShortTy; break; @@ -329,11 +322,11 @@ static Optional GetCFNumberSize(ASTContext& Ctx, uint64_t i) { case kCFNumberCFIndexType: case kCFNumberNSIntegerType: case kCFNumberCGFloatType: - // FIXME: We need a way to map from names to Type*. + // FIXME: We need a way to map from names to Type*. default: return Optional(); } - + return Ctx.getTypeSize(T); } @@ -357,100 +350,98 @@ static const char* GetCFNumberTypeStr(uint64_t i) { "kCFNumberNSIntegerType", "kCFNumberCGFloatType" }; - + return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType"; } #endif -bool AuditCFNumberCreate::Audit(ExplodedNode* N,GRStateManager&){ - CallExpr* CE = cast(cast(N->getLocation()).getStmt()); - Expr* Callee = CE->getCallee(); - SVal CallV = N->getState()->getSVal(Callee); +bool AuditCFNumberCreate::Audit(ExplodedNode* N,GRStateManager&){ + const CallExpr* CE = + cast(cast(N->getLocation()).getStmt()); + const Expr* Callee = CE->getCallee(); + SVal CallV = N->getState()->getSVal(Callee); const FunctionDecl* FD = CallV.getAsFunctionDecl(); if (!FD || FD->getIdentifier() != II || CE->getNumArgs()!=3) return false; - + // Get the value of the "theType" argument. SVal TheTypeVal = N->getState()->getSVal(CE->getArg(1)); - + // FIXME: We really should allow ranges of valid theType values, and // bifurcate the state appropriately. nonloc::ConcreteInt* V = dyn_cast(&TheTypeVal); - + if (!V) return false; - + uint64_t NumberKind = V->getValue().getLimitedValue(); Optional TargetSize = GetCFNumberSize(Ctx, NumberKind); - + // FIXME: In some cases we can emit an error. if (!TargetSize.isKnown()) return false; - + // Look at the value of the integer being passed by reference. Essentially // we want to catch cases where the value passed in is not equal to the // size of the type being created. SVal TheValueExpr = N->getState()->getSVal(CE->getArg(2)); - + // FIXME: Eventually we should handle arbitrary locations. We can do this // by having an enhanced memory model that does low-level typing. loc::MemRegionVal* LV = dyn_cast(&TheValueExpr); if (!LV) return false; - - const TypedRegion* R = dyn_cast(LV->getRegion()); - if (!R) return false; - - while (const TypedViewRegion* ATR = dyn_cast(R)) { - R = dyn_cast(ATR->getSuperRegion()); - if (!R) return false; - } - + + const TypedRegion* R = dyn_cast(LV->getBaseRegion()); + + if (!R) + return false; + QualType T = Ctx.getCanonicalType(R->getValueType(Ctx)); - + // FIXME: If the pointee isn't an integer type, should we flag a warning? // People can do weird stuff with pointers. - - if (!T->isIntegerType()) + + if (!T->isIntegerType()) return false; - + uint64_t SourceSize = Ctx.getTypeSize(T); - + // CHECK: is SourceSize == TargetSize - + if (SourceSize == TargetSize) return false; - + AddError(R, CE->getArg(2), N, SourceSize, TargetSize, NumberKind); - + // FIXME: We can actually create an abstract "CFNumber" object that has // the bits initialized to the provided values. return SourceSize < TargetSize; } -void AuditCFNumberCreate::AddError(const TypedRegion* R, Expr* Ex, - ExplodedNode *N, +void AuditCFNumberCreate::AddError(const TypedRegion* R, const Expr* Ex, + ExplodedNode *N, uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind) { - + std::string sbuf; llvm::raw_string_ostream os(sbuf); - + os << (SourceSize == 8 ? "An " : "A ") << SourceSize << " bit integer is used to initialize a CFNumber " "object that represents " << (TargetSize == 8 ? "an " : "a ") - << TargetSize << " bit integer. "; + << TargetSize << " bit integer. "; if (SourceSize < TargetSize) os << (TargetSize - SourceSize) - << " bits of the CFNumber value will be garbage." ; + << " bits of the CFNumber value will be garbage." ; else os << (SourceSize - TargetSize) << " bits of the input integer will be lost."; - + // Lazily create the BugType object. This will be owned // by the BugReporter object 'BR' once we call BR.EmitWarning. if (!BT) BT = new APIMisuse("Bad use of CFNumberCreate"); @@ -460,22 +451,98 @@ void AuditCFNumberCreate::AddError(const TypedRegion* R, Expr* Ex, } GRSimpleAPICheck* -clang::CreateAuditCFNumberCreate(ASTContext& Ctx, BugReporter& BR) { +clang::CreateAuditCFNumberCreate(ASTContext& Ctx, BugReporter& BR) { return new AuditCFNumberCreate(Ctx, BR); } +//===----------------------------------------------------------------------===// +// CFRetain/CFRelease auditing for null arguments. +//===----------------------------------------------------------------------===// + +namespace { +class VISIBILITY_HIDDEN AuditCFRetainRelease : public GRSimpleAPICheck { + APIMisuse *BT; + + // FIXME: Either this should be refactored into GRSimpleAPICheck, or + // it should always be passed with a call to Audit. The latter + // approach makes this class more stateless. + ASTContext& Ctx; + IdentifierInfo *Retain, *Release; + BugReporter& BR; + +public: + AuditCFRetainRelease(ASTContext& ctx, BugReporter& br) + : BT(0), Ctx(ctx), + Retain(&Ctx.Idents.get("CFRetain")), Release(&Ctx.Idents.get("CFRelease")), + BR(br){} + + ~AuditCFRetainRelease() {} + + bool Audit(ExplodedNode* N, GRStateManager&); +}; +} // end anonymous namespace + + +bool AuditCFRetainRelease::Audit(ExplodedNode* N, GRStateManager&) { + const CallExpr* CE = cast(cast(N->getLocation()).getStmt()); + + // If the CallExpr doesn't have exactly 1 argument just give up checking. + if (CE->getNumArgs() != 1) + return false; + + // Check if we called CFRetain/CFRelease. + const GRState* state = N->getState(); + SVal X = state->getSVal(CE->getCallee()); + const FunctionDecl* FD = X.getAsFunctionDecl(); + + if (!FD) + return false; + + const IdentifierInfo *FuncII = FD->getIdentifier(); + if (!(FuncII == Retain || FuncII == Release)) + return false; + + // Finally, check if the argument is NULL. + // FIXME: We should be able to bifurcate the state here, as a successful + // check will result in the value not being NULL afterwards. + // FIXME: Need a way to register vistors for the BugReporter. Would like + // to benefit from the same diagnostics that regular null dereference + // reporting has. + if (state->getStateManager().isEqual(state, CE->getArg(0), 0)) { + if (!BT) + BT = new APIMisuse("null passed to CFRetain/CFRelease"); + + const char *description = (FuncII == Retain) + ? "Null pointer argument in call to CFRetain" + : "Null pointer argument in call to CFRelease"; + + RangedBugReport *report = new RangedBugReport(*BT, description, N); + report->addRange(CE->getArg(0)->getSourceRange()); + BR.EmitReport(report); + return true; + } + + return false; +} + + +GRSimpleAPICheck* +clang::CreateAuditCFRetainRelease(ASTContext& Ctx, BugReporter& BR) { + return new AuditCFRetainRelease(Ctx, BR); +} + //===----------------------------------------------------------------------===// // Check registration. +//===----------------------------------------------------------------------===// -void clang::RegisterAppleChecks(GRExprEngine& Eng) { +void clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) { ASTContext& Ctx = Eng.getContext(); BugReporter &BR = Eng.getBugReporter(); Eng.AddCheck(CreateBasicObjCFoundationChecks(Ctx, BR), Stmt::ObjCMessageExprClass); + Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, BR), Stmt::CallExprClass); + Eng.AddCheck(CreateAuditCFRetainRelease(Ctx, BR), Stmt::CallExprClass); - Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, BR), - Stmt::CallExprClass); - - RegisterNSErrorChecks(BR, Eng); + RegisterNSErrorChecks(BR, Eng, D); } diff --git a/lib/Analysis/BasicObjCFoundationChecks.h b/lib/Analysis/BasicObjCFoundationChecks.h index 5c9701ecdd36..1271ae4ab1c0 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.h +++ b/lib/Analysis/BasicObjCFoundationChecks.h @@ -25,21 +25,24 @@ #define LLVM_CLANG_ANALYSIS_BASICOBJCFOUNDATIONCHECKS namespace clang { - + class GRSimpleAPICheck; class ASTContext; -class GRStateManager; +class GRStateManager; class BugReporter; class GRExprEngine; - -GRSimpleAPICheck* CreateBasicObjCFoundationChecks(ASTContext& Ctx, + +GRSimpleAPICheck *CreateBasicObjCFoundationChecks(ASTContext& Ctx, BugReporter& BR); - -GRSimpleAPICheck* CreateAuditCFNumberCreate(ASTContext& Ctx, + +GRSimpleAPICheck *CreateAuditCFNumberCreate(ASTContext& Ctx, BugReporter& BR); - -void RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng); - + +GRSimpleAPICheck *CreateAuditCFRetainRelease(ASTContext& Ctx, + BugReporter& BR); + +void RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng, const Decl &D); + } // end clang namespace #endif diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp index 19d641ee9753..a4f451f36490 100644 --- a/lib/Analysis/BasicStore.cpp +++ b/lib/Analysis/BasicStore.cpp @@ -13,17 +13,17 @@ #include "clang/AST/ExprObjC.h" #include "clang/Analysis/Analyses/LiveVariables.h" +#include "clang/Analysis/PathSensitive/AnalysisContext.h" #include "clang/Analysis/PathSensitive/GRState.h" -#include "llvm/ADT/ImmutableMap.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/Streams.h" +#include "llvm/ADT/ImmutableMap.h" using namespace clang; -typedef llvm::ImmutableMap BindingsTy; +typedef llvm::ImmutableMap BindingsTy; namespace { - + class VISIBILITY_HIDDEN BasicStoreSubRegionMap : public SubRegionMap { public: BasicStoreSubRegionMap() {} @@ -32,81 +32,78 @@ public: return true; // Do nothing. No subregions. } }; - + class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager { BindingsTy::Factory VBFactory; - const MemRegion* SelfRegion; - public: BasicStoreManager(GRStateManager& mgr) - : StoreManager(mgr), - VBFactory(mgr.getAllocator()), - SelfRegion(0) {} - + : StoreManager(mgr), VBFactory(mgr.getAllocator()) {} + ~BasicStoreManager() {} SubRegionMap *getSubRegionMap(const GRState *state) { return new BasicStoreSubRegionMap(); } - SVal Retrieve(const GRState *state, Loc loc, QualType T = QualType()); + SValuator::CastResult Retrieve(const GRState *state, Loc loc, + QualType T = QualType()); + + const GRState *InvalidateRegion(const GRState *state, const MemRegion *R, + const Expr *E, unsigned Count); const GRState *Bind(const GRState *state, Loc L, SVal V) { return state->makeWithStore(BindInternal(state->getStore(), L, V)); } - Store scanForIvars(Stmt *B, const Decl* SelfDecl, Store St); - - Store BindInternal(Store St, Loc loc, SVal V); + Store scanForIvars(Stmt *B, const Decl* SelfDecl, + const MemRegion *SelfRegion, Store St); + + Store BindInternal(Store St, Loc loc, SVal V); Store Remove(Store St, Loc loc); - Store getInitialStore(); + Store getInitialStore(const LocationContext *InitLoc); // FIXME: Investigate what is using this. This method should be removed. - virtual Loc getLoc(const VarDecl* VD) { - return ValMgr.makeLoc(MRMgr.getVarRegion(VD)); + virtual Loc getLoc(const VarDecl* VD, const LocationContext *LC) { + return ValMgr.makeLoc(MRMgr.getVarRegion(VD, LC)); } - + const GRState *BindCompoundLiteral(const GRState *state, const CompoundLiteralExpr* cl, SVal val) { return state; } - - SVal getLValueVar(const GRState *state, const VarDecl* VD); - SVal getLValueString(const GRState *state, const StringLiteral* S); - SVal getLValueCompoundLiteral(const GRState *state, - const CompoundLiteralExpr* CL); - SVal getLValueIvar(const GRState *state, const ObjCIvarDecl* D, SVal Base); - SVal getLValueField(const GRState *state, SVal Base, const FieldDecl* D); - SVal getLValueElement(const GRState *state, QualType elementType, - SVal Base, SVal Offset); + + SVal getLValueVar(const VarDecl *VD, const LocationContext *LC); + SVal getLValueString(const StringLiteral *S); + SVal getLValueCompoundLiteral(const CompoundLiteralExpr *CL); + 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; } - /// getSelfRegion - Returns the region for the 'self' (Objective-C) or - /// 'this' object (C++). When used when analyzing a normal function this - /// method returns NULL. - const MemRegion* getSelfRegion(Store) { return SelfRegion; } - /// RemoveDeadBindings - Scans a BasicStore of 'state' for dead values. - /// It returns a new Store with these values removed. - Store RemoveDeadBindings(const GRState *state, Stmt* Loc, - SymbolReaper& SymReaper, - llvm::SmallVectorImpl& RegionRoots); + /// It updatees the GRState object in place with the values removed. + void RemoveDeadBindings(GRState &state, Stmt* Loc, SymbolReaper& SymReaper, + llvm::SmallVectorImpl& RegionRoots); void iterBindings(Store store, BindingsHandler& f); - const GRState *BindDecl(const GRState *state, const VarDecl* VD, SVal InitVal) { - return state->makeWithStore(BindDeclInternal(state->getStore(),VD, &InitVal)); + const GRState *BindDecl(const GRState *state, const VarDecl *VD, + const LocationContext *LC, SVal InitVal) { + return state->makeWithStore(BindDeclInternal(state->getStore(),VD, LC, + &InitVal)); } - const GRState *BindDeclWithNoInit(const GRState *state, const VarDecl* VD) { - return state->makeWithStore(BindDeclInternal(state->getStore(), VD, 0)); + const GRState *BindDeclWithNoInit(const GRState *state, const VarDecl *VD, + const LocationContext *LC) { + return state->makeWithStore(BindDeclInternal(state->getStore(), VD, LC, 0)); } - Store BindDeclInternal(Store store, const VarDecl* VD, SVal* InitVal); + Store BindDeclInternal(Store store, const VarDecl *VD, + const LocationContext *LC, SVal *InitVal); static inline BindingsTy GetBindings(Store store) { return BindingsTy(static_cast(store)); @@ -118,7 +115,7 @@ public: private: ASTContext& getContext() { return StateMgr.getContext(); } }; - + } // end anonymous namespace @@ -126,23 +123,21 @@ StoreManager* clang::CreateBasicStoreManager(GRStateManager& StMgr) { return new BasicStoreManager(StMgr); } -SVal BasicStoreManager::getLValueVar(const GRState *state, const VarDecl* VD) { - return ValMgr.makeLoc(MRMgr.getVarRegion(VD)); +SVal BasicStoreManager::getLValueVar(const VarDecl* VD, + const LocationContext *LC) { + return ValMgr.makeLoc(MRMgr.getVarRegion(VD, LC)); } -SVal BasicStoreManager::getLValueString(const GRState *state, - const StringLiteral* S) { +SVal BasicStoreManager::getLValueString(const StringLiteral* S) { return ValMgr.makeLoc(MRMgr.getStringRegion(S)); } -SVal BasicStoreManager::getLValueCompoundLiteral(const GRState *state, - const CompoundLiteralExpr* CL){ +SVal BasicStoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL){ return ValMgr.makeLoc(MRMgr.getCompoundLiteralRegion(CL)); } -SVal BasicStoreManager::getLValueIvar(const GRState *state, const ObjCIvarDecl* D, - SVal Base) { - +SVal BasicStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) { + if (Base.isUnknownOrUndef()) return Base; @@ -150,23 +145,20 @@ SVal BasicStoreManager::getLValueIvar(const GRState *state, const ObjCIvarDecl* if (isa(BaseL)) { const MemRegion *BaseR = cast(BaseL).getRegion(); - - if (BaseR == SelfRegion) - return ValMgr.makeLoc(MRMgr.getObjCIvarRegion(D, BaseR)); + return ValMgr.makeLoc(MRMgr.getObjCIvarRegion(D, BaseR)); } - + return UnknownVal(); } -SVal BasicStoreManager::getLValueField(const GRState *state, SVal Base, - const FieldDecl* D) { +SVal BasicStoreManager::getLValueField(const FieldDecl* D, SVal Base) { if (Base.isUnknownOrUndef()) return Base; - - Loc BaseL = cast(Base); + + Loc BaseL = cast(Base); const MemRegion* BaseR = 0; - + switch(BaseL.getSubKind()) { case loc::GotoLabelKind: return UndefinedVal(); @@ -174,7 +166,7 @@ SVal BasicStoreManager::getLValueField(const GRState *state, SVal Base, case loc::MemRegionKind: BaseR = cast(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, @@ -186,28 +178,27 @@ SVal BasicStoreManager::getLValueField(const GRState *state, SVal Base, assert ("Unhandled Base."); return Base; } - + return ValMgr.makeLoc(MRMgr.getFieldRegion(D, BaseR)); } -SVal BasicStoreManager::getLValueElement(const GRState *state, - QualType elementType, - SVal Base, SVal Offset) { +SVal BasicStoreManager::getLValueElement(QualType elementType, + SVal Offset, SVal Base) { if (Base.isUnknownOrUndef()) return Base; - - Loc BaseL = cast(Base); + + Loc BaseL = cast(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(BaseL).getRegion(); - + if (isa(R)) { // int x; // char* y = (char*) &x; @@ -215,12 +206,12 @@ SVal BasicStoreManager::getLValueElement(const GRState *state, // y[0] = 'a'; return Base; } - + if (isa(R) || isa(R)) { BaseR = R; break; } - + break; } @@ -230,13 +221,13 @@ SVal BasicStoreManager::getLValueElement(const GRState *state, // 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) { + + if (BaseR) { return ValMgr.makeLoc(MRMgr.getElementRegion(elementType, UnknownVal(), BaseR, getContext())); } @@ -246,37 +237,38 @@ SVal BasicStoreManager::getLValueElement(const GRState *state, static bool isHigherOrderRawPtr(QualType T, ASTContext &C) { bool foundPointer = false; - while (1) { - const PointerType *PT = T->getAsPointerType(); + while (1) { + const PointerType *PT = T->getAs(); if (!PT) { if (!foundPointer) return false; - + // intptr_t* or intptr_t**, etc? if (T->isIntegerType() && C.getTypeSize(T) == C.getTypeSize(C.VoidPtrTy)) return true; - + QualType X = C.getCanonicalType(T).getUnqualifiedType(); return X == C.VoidTy; } - + foundPointer = true; T = PT->getPointeeType(); - } + } } - -SVal BasicStoreManager::Retrieve(const GRState *state, Loc loc, QualType T) { - + +SValuator::CastResult BasicStoreManager::Retrieve(const GRState *state, + Loc loc, QualType T) { + if (isa(loc)) - return UnknownVal(); - - assert (!isa(loc)); - + return SValuator::CastResult(state, UnknownVal()); + + assert(!isa(loc)); + switch (loc.getSubKind()) { case loc::MemRegionKind: { const MemRegion* R = cast(loc).getRegion(); - + if (const ElementRegion *ER = dyn_cast(R)) { // Just support void**, void***, intptr_t*, intptr_t**, etc., for now. // This is needed to handle OSCompareAndSwapPtr() and friends. @@ -284,42 +276,46 @@ SVal BasicStoreManager::Retrieve(const GRState *state, Loc loc, QualType T) { QualType T = ER->getLocationType(Ctx); if (!isHigherOrderRawPtr(T, Ctx)) - return UnknownVal(); - + return SValuator::CastResult(state, UnknownVal()); + // FIXME: Should check for element 0. // Otherwise, strip the element region. R = ER->getSuperRegion(); } - + if (!(isa(R) || isa(R))) - return UnknownVal(); - + return SValuator::CastResult(state, UnknownVal()); + BindingsTy B = GetBindings(state->getStore()); - BindingsTy::data_type* T = B.lookup(R); - return T ? *T : UnknownVal(); + BindingsTy::data_type *Val = B.lookup(R); + + if (!Val) + break; + + return CastRetrievedVal(*Val, state, cast(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 UndefinedVal(); - + return SValuator::CastResult(state, UndefinedVal()); + default: assert (false && "Invalid Loc."); break; } - - return UnknownVal(); + + return SValuator::CastResult(state, UnknownVal()); } - -Store BasicStoreManager::BindInternal(Store store, Loc loc, SVal V) { + +Store BasicStoreManager::BindInternal(Store store, Loc loc, SVal V) { if (isa(loc)) return store; const MemRegion* R = cast(loc).getRegion(); ASTContext &C = StateMgr.getContext(); - + // Special case: handle store of pointer values (Loc) to pointers via // a cast to intXX_t*, void*, etc. This is needed to handle // OSCompareAndSwap32Barrier/OSCompareAndSwap64Barrier. @@ -327,19 +323,21 @@ Store BasicStoreManager::BindInternal(Store store, Loc loc, SVal V) { if (const ElementRegion *ER = dyn_cast(R)) { // FIXME: Should check for index 0. QualType T = ER->getLocationType(C); - + if (isHigherOrderRawPtr(T, C)) R = ER->getSuperRegion(); - } - + } + if (!(isa(R) || isa(R))) return store; - - // We only track bindings to self.ivar. - if (const ObjCIvarRegion *IVR = dyn_cast(R)) - if (IVR->getSuperRegion() != SelfRegion) - return store; - + + const TypedRegion *TyR = cast(R); + + // Do not bind to arrays. We need to explicitly check for this so that + // we do not encounter any weirdness of trying to load/store from arrays. + if (TyR->isBoundable() && TyR->getValueType(C)->isArrayType()) + return store; + if (nonloc::LocAsInteger *X = dyn_cast(&V)) { // Only convert 'V' to a location iff the underlying region type // is a location as well. @@ -347,11 +345,8 @@ Store BasicStoreManager::BindInternal(Store store, Loc loc, SVal V) { // a pointer. We may wish to flag a type error here if the types // are incompatible. This may also cause lots of breakage // elsewhere. Food for thought. - if (const TypedRegion *TyR = dyn_cast(R)) { - if (TyR->isBoundable() && - Loc::IsLocType(TyR->getValueType(C))) - V = X->getLoc(); - } + if (TyR->isBoundable() && Loc::IsLocType(TyR->getValueType(C))) + V = X->getLoc(); } BindingsTy B = GetBindings(store); @@ -364,10 +359,10 @@ Store BasicStoreManager::Remove(Store store, Loc loc) { switch (loc.getSubKind()) { case loc::MemRegionKind: { const MemRegion* R = cast(loc).getRegion(); - + if (!(isa(R) || isa(R))) return store; - + return VBFactory.Remove(GetBindings(store), R).getRoot(); } default: @@ -376,16 +371,15 @@ Store BasicStoreManager::Remove(Store store, Loc loc) { } } -Store -BasicStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc, +void +BasicStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, SymbolReaper& SymReaper, - llvm::SmallVectorImpl& RegionRoots) + llvm::SmallVectorImpl& RegionRoots) { - - Store store = state->getStore(); + Store store = state.getStore(); BindingsTy B = GetBindings(store); typedef SVal::symbol_iterator symbol_iterator; - + // Iterate over the variable bindings. for (BindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) { if (const VarRegion *VR = dyn_cast(I.getKey())) { @@ -399,20 +393,20 @@ BasicStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc, } else continue; - + // Mark the bindings in the data as live. SVal X = I.getData(); for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI) SymReaper.markLive(*SI); } - + // Scan for live variables and live symbols. llvm::SmallPtrSet Marked; - + while (!RegionRoots.empty()) { const MemRegion* MR = RegionRoots.back(); RegionRoots.pop_back(); - + while (MR) { if (const SymbolicRegion* SymR = dyn_cast(MR)) { SymReaper.markLive(SymR->getSymbol()); @@ -421,17 +415,17 @@ BasicStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc, else if (isa(MR) || isa(MR)) { if (Marked.count(MR)) break; - + Marked.insert(MR); - SVal X = Retrieve(state, loc::MemRegionVal(MR)); - + SVal X = Retrieve(&state, loc::MemRegionVal(MR)).getSVal(); + // FIXME: We need to handle symbols nested in region definitions. for (symbol_iterator SI=X.symbol_begin(),SE=X.symbol_end();SI!=SE;++SI) SymReaper.markLive(*SI); - + if (!isa(X)) break; - + const loc::MemRegionVal& LVD = cast(X); RegionRoots.push_back(LVD.getRegion()); break; @@ -442,30 +436,32 @@ BasicStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc, break; } } - - // Remove dead variable bindings. + + // Remove dead variable bindings. for (BindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) { const MemRegion* R = I.getKey(); - + if (!Marked.count(R)) { store = Remove(store, ValMgr.makeLoc(R)); SVal X = I.getData(); - + for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI) SymReaper.maybeDead(*SI); } } - return store; + // Write the store back. + state.setStore(store); } -Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl, Store St) { +Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl, + const MemRegion *SelfRegion, Store St) { for (Stmt::child_iterator CI=B->child_begin(), CE=B->child_end(); CI != CE; ++CI) { - + if (!*CI) continue; - + // Check if the statement is an ivar reference. We only // care about self.ivar. if (ObjCIvarRefExpr *IV = dyn_cast(*CI)) { @@ -473,25 +469,25 @@ Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl, Store St) { if (const DeclRefExpr *DR = dyn_cast(Base)) { if (DR->getDecl() == SelfDecl) { const MemRegion *IVR = MRMgr.getObjCIvarRegion(IV->getDecl(), - SelfRegion); - SVal X = ValMgr.getRegionValueSymbolVal(IVR); + SelfRegion); + SVal X = ValMgr.getRegionValueSymbolVal(IVR); St = BindInternal(St, ValMgr.makeLoc(IVR), X); } } } else - St = scanForIvars(*CI, SelfDecl, St); + St = scanForIvars(*CI, SelfDecl, SelfRegion, St); } - + return St; } -Store BasicStoreManager::getInitialStore() { +Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) { // The LiveVariables information already has a compilation of all VarDecls // used in the function. Iterate through this set, and "symbolicate" // any VarDecl whose value originally comes from outside the function. typedef LiveVariables::AnalysisDataTy LVDataTy; - LVDataTy& D = StateMgr.getLiveVariables().getAnalysisData(); + LVDataTy& D = InitLoc->getLiveVariables()->getAnalysisData(); Store St = VBFactory.GetEmptyMap().getRoot(); for (LVDataTy::decl_iterator I=D.begin_decl(), E=D.end_decl(); I != E; ++I) { @@ -499,38 +495,35 @@ Store BasicStoreManager::getInitialStore() { // Handle implicit parameters. if (ImplicitParamDecl* PD = dyn_cast(ND)) { - const Decl& CD = StateMgr.getCodeDecl(); + const Decl& CD = *InitLoc->getDecl(); if (const ObjCMethodDecl* MD = dyn_cast(&CD)) { if (MD->getSelfDecl() == PD) { - // Create a region for "self". - assert (SelfRegion == 0); - SelfRegion = MRMgr.getObjCObjectRegion(MD->getClassInterface(), - MRMgr.getHeapRegion()); - - St = BindInternal(St, ValMgr.makeLoc(MRMgr.getVarRegion(PD)), + // FIXME: Just use a symbolic region, and remove ObjCObjectRegion + // entirely. + const ObjCObjectRegion *SelfRegion = + MRMgr.getObjCObjectRegion(MD->getClassInterface(), + MRMgr.getHeapRegion()); + + St = BindInternal(St, ValMgr.makeLoc(MRMgr.getVarRegion(PD, InitLoc)), ValMgr.makeLoc(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, St); + St = scanForIvars(MD->getBody(), PD, SelfRegion, St); } } } else if (VarDecl* VD = dyn_cast(ND)) { - // Punt on static variables for now. - if (VD->getStorageClass() == VarDecl::Static) - continue; - // Only handle simple types that we can symbolicate. if (!SymbolManager::canSymbolicate(VD->getType())) continue; // Initialize globals and parameters to symbolic values. // Initialize local variables to undefined. - const MemRegion *R = ValMgr.getRegionManager().getVarRegion(VD); - SVal X = R->hasGlobalsOrParametersStorage() - ? ValMgr.getRegionValueSymbolVal(R) - : UndefinedVal(); + const MemRegion *R = ValMgr.getRegionManager().getVarRegion(VD, InitLoc); + SVal X = UndefinedVal(); + if (R->hasGlobalsOrParametersStorage()) + X = ValMgr.getRegionValueSymbolVal(R); St = BindInternal(St, ValMgr.makeLoc(R), X); } @@ -539,10 +532,11 @@ Store BasicStoreManager::getInitialStore() { } Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD, + const LocationContext *LC, SVal* InitVal) { - + BasicValueFactory& BasicVals = StateMgr.getBasicVals(); - + // BasicStore does not model arrays and structs. if (VD->getType()->isArrayType() || VD->getType()->isStructureType()) return store; @@ -557,28 +551,28 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD, // Static global variables should not be visited here. assert(!(VD->getStorageClass() == VarDecl::Static && VD->isFileVarDecl())); - + // Process static variables. if (VD->getStorageClass() == VarDecl::Static) { // C99: 6.7.8 Initialization // If an object that has static storage duration is not initialized - // explicitly, then: - // —if it has pointer type, it is initialized to a null pointer; - // —if it has arithmetic type, it is initialized to (positive or + // explicitly, then: + // —if it has pointer type, it is initialized to a null pointer; + // —if it has arithmetic type, it is initialized to (positive or // unsigned) zero; if (!InitVal) { QualType T = VD->getType(); if (Loc::IsLocType(T)) - store = BindInternal(store, getLoc(VD), + store = BindInternal(store, getLoc(VD, LC), loc::ConcreteInt(BasicVals.getValue(0, T))); else if (T->isIntegerType()) - store = BindInternal(store, getLoc(VD), + store = BindInternal(store, getLoc(VD, LC), nonloc::ConcreteInt(BasicVals.getValue(0, T))); else { // assert(0 && "ignore other types of variables"); } } else { - store = BindInternal(store, getLoc(VD), *InitVal); + store = BindInternal(store, getLoc(VD, LC), *InitVal); } } } else { @@ -586,7 +580,7 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD, QualType T = VD->getType(); if (ValMgr.getSymbolManager().canSymbolicate(T)) { SVal V = InitVal ? *InitVal : UndefinedVal(); - store = BindInternal(store, getLoc(VD), V); + store = BindInternal(store, getLoc(VD, LC), V); } } @@ -595,30 +589,48 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD, void BasicStoreManager::print(Store store, llvm::raw_ostream& Out, const char* nl, const char *sep) { - + BindingsTy B = GetBindings(store); Out << "Variables:" << nl; - + bool isFirst = true; - + for (BindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) { if (isFirst) isFirst = false; else Out << nl; - - Out << ' ' << I.getKey() << " : "; - I.getData().print(Out); + + Out << ' ' << I.getKey() << " : " << I.getData(); } } void BasicStoreManager::iterBindings(Store store, BindingsHandler& f) { BindingsTy B = GetBindings(store); - + for (BindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) f.HandleBinding(*this, store, I.getKey(), I.getData()); } StoreManager::BindingsHandler::~BindingsHandler() {} + +//===----------------------------------------------------------------------===// +// Binding invalidation. +//===----------------------------------------------------------------------===// + +const GRState *BasicStoreManager::InvalidateRegion(const GRState *state, + const MemRegion *R, + const Expr *E, + unsigned Count) { + R = R->getBaseRegion(); + + if (!(isa(R) || isa(R))) + return state; + + QualType T = cast(R)->getValueType(R->getContext()); + SVal V = ValMgr.getConjuredSymbolVal(R, E, T, Count); + return Bind(state, loc::MemRegionVal(R), V); +} + diff --git a/lib/Analysis/BasicValueFactory.cpp b/lib/Analysis/BasicValueFactory.cpp index 72ad0a5ed8f1..b33c277f86f9 100644 --- a/lib/Analysis/BasicValueFactory.cpp +++ b/lib/Analysis/BasicValueFactory.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This file defines BasicValueFactory, a class that manages the lifetime -// of APSInt objects and symbolic constraints used by GRExprEngine +// of APSInt objects and symbolic constraints used by GRExprEngine // and related classes. // //===----------------------------------------------------------------------===// @@ -17,12 +17,19 @@ using namespace clang; -void CompoundValData::Profile(llvm::FoldingSetNodeID& ID, QualType T, +void CompoundValData::Profile(llvm::FoldingSetNodeID& ID, QualType T, llvm::ImmutableList L) { T.Profile(ID); ID.AddPointer(L.getInternalPointer()); } +void LazyCompoundValData::Profile(llvm::FoldingSetNodeID& ID, + const GRState *state, + const TypedRegion *region) { + ID.AddPointer(state); + ID.AddPointer(region); +} + typedef std::pair SValData; typedef std::pair SValPair; @@ -33,7 +40,7 @@ template<> struct FoldingSetTrait { ID.AddPointer( (void*) X.second); } }; - + template<> struct FoldingSetTrait { static inline void Profile(const SValPair& X, llvm::FoldingSetNodeID& ID) { X.first.Profile(ID); @@ -54,8 +61,8 @@ BasicValueFactory::~BasicValueFactory() { // frees an aux. memory allocated to represent very large constants. for (APSIntSetTy::iterator I=APSIntSet.begin(), E=APSIntSet.end(); I!=E; ++I) I->getValue().~APSInt(); - - delete (PersistentSValsTy*) PersistentSVals; + + delete (PersistentSValsTy*) PersistentSVals; delete (PersistentSValPairsTy*) PersistentSValPairs; } @@ -63,16 +70,16 @@ const llvm::APSInt& BasicValueFactory::getValue(const llvm::APSInt& X) { llvm::FoldingSetNodeID ID; void* InsertPos; typedef llvm::FoldingSetNodeWrapper FoldNodeTy; - + X.Profile(ID); FoldNodeTy* P = APSIntSet.FindNodeOrInsertPos(ID, InsertPos); - - if (!P) { + + if (!P) { P = (FoldNodeTy*) BPAlloc.Allocate(); new (P) FoldNodeTy(X); APSIntSet.InsertNode(P, InsertPos); } - + return *P; } @@ -85,22 +92,22 @@ const llvm::APSInt& BasicValueFactory::getValue(const llvm::APInt& X, const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, unsigned BitWidth, bool isUnsigned) { llvm::APSInt V(BitWidth, isUnsigned); - V = X; + V = X; return getValue(V); } const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, QualType T) { - + unsigned bits = Ctx.getTypeSize(T); llvm::APSInt V(bits, T->isUnsignedIntegerType() || Loc::IsLocType(T)); V = X; return getValue(V); } -const CompoundValData* +const CompoundValData* BasicValueFactory::getCompoundValData(QualType T, llvm::ImmutableList Vals) { - + llvm::FoldingSetNodeID ID; CompoundValData::Profile(ID, T, Vals); void* InsertPos; @@ -116,91 +123,110 @@ BasicValueFactory::getCompoundValData(QualType T, return D; } +const LazyCompoundValData* +BasicValueFactory::getLazyCompoundValData(const GRState *state, + const TypedRegion *region) { + llvm::FoldingSetNodeID ID; + LazyCompoundValData::Profile(ID, state, region); + void* InsertPos; + + LazyCompoundValData *D = + LazyCompoundValDataSet.FindNodeOrInsertPos(ID, InsertPos); + + if (!D) { + D = (LazyCompoundValData*) BPAlloc.Allocate(); + new (D) LazyCompoundValData(state, region); + LazyCompoundValDataSet.InsertNode(D, InsertPos); + } + + return D; +} + const llvm::APSInt* BasicValueFactory::EvaluateAPSInt(BinaryOperator::Opcode Op, const llvm::APSInt& V1, const llvm::APSInt& V2) { - + switch (Op) { default: assert (false && "Invalid Opcode."); - + case BinaryOperator::Mul: return &getValue( V1 * V2 ); - + case BinaryOperator::Div: return &getValue( V1 / V2 ); - + case BinaryOperator::Rem: return &getValue( V1 % V2 ); - + case BinaryOperator::Add: return &getValue( V1 + V2 ); - + case BinaryOperator::Sub: return &getValue( V1 - V2 ); - + case BinaryOperator::Shl: { // FIXME: This logic should probably go higher up, where we can // test these conditions symbolically. - + // FIXME: Expand these checks to include all undefined behavior. - + if (V2.isSigned() && V2.isNegative()) return NULL; - + uint64_t Amt = V2.getZExtValue(); - + if (Amt > V1.getBitWidth()) return NULL; - + return &getValue( V1.operator<<( (unsigned) Amt )); } - + case BinaryOperator::Shr: { - + // FIXME: This logic should probably go higher up, where we can // test these conditions symbolically. - + // FIXME: Expand these checks to include all undefined behavior. - + if (V2.isSigned() && V2.isNegative()) return NULL; - + uint64_t Amt = V2.getZExtValue(); - + if (Amt > V1.getBitWidth()) return NULL; - + return &getValue( V1.operator>>( (unsigned) Amt )); } - + case BinaryOperator::LT: return &getTruthValue( V1 < V2 ); - + case BinaryOperator::GT: return &getTruthValue( V1 > V2 ); - + case BinaryOperator::LE: return &getTruthValue( V1 <= V2 ); - + case BinaryOperator::GE: return &getTruthValue( V1 >= V2 ); - + case BinaryOperator::EQ: return &getTruthValue( V1 == V2 ); - + case BinaryOperator::NE: return &getTruthValue( V1 != V2 ); - + // Note: LAnd, LOr, Comma are handled specially by higher-level logic. - + case BinaryOperator::And: return &getValue( V1 & V2 ); - + case BinaryOperator::Or: return &getValue( V1 | V2 ); - + case BinaryOperator::Xor: return &getValue( V1 ^ V2 ); } @@ -209,21 +235,21 @@ BasicValueFactory::EvaluateAPSInt(BinaryOperator::Opcode Op, const std::pair& BasicValueFactory::getPersistentSValWithData(const SVal& V, uintptr_t Data) { - + // Lazily create the folding set. if (!PersistentSVals) PersistentSVals = new PersistentSValsTy(); - + llvm::FoldingSetNodeID ID; void* InsertPos; V.Profile(ID); ID.AddPointer((void*) Data); - + PersistentSValsTy& Map = *((PersistentSValsTy*) PersistentSVals); - + typedef llvm::FoldingSetNodeWrapper FoldNodeTy; FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos); - - if (!P) { + + if (!P) { P = (FoldNodeTy*) BPAlloc.Allocate(); new (P) FoldNodeTy(std::make_pair(V, Data)); Map.InsertNode(P, InsertPos); @@ -234,31 +260,31 @@ BasicValueFactory::getPersistentSValWithData(const SVal& V, uintptr_t Data) { const std::pair& BasicValueFactory::getPersistentSValPair(const SVal& V1, const SVal& V2) { - + // Lazily create the folding set. if (!PersistentSValPairs) PersistentSValPairs = new PersistentSValPairsTy(); - + llvm::FoldingSetNodeID ID; void* InsertPos; V1.Profile(ID); V2.Profile(ID); - + PersistentSValPairsTy& Map = *((PersistentSValPairsTy*) PersistentSValPairs); - + typedef llvm::FoldingSetNodeWrapper FoldNodeTy; FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos); - - if (!P) { + + if (!P) { P = (FoldNodeTy*) BPAlloc.Allocate(); new (P) FoldNodeTy(std::make_pair(V1, V2)); Map.InsertNode(P, InsertPos); } - + return P->getValue(); } const SVal* BasicValueFactory::getPersistentSVal(SVal X) { return &getPersistentSValWithData(X, 0).first; -} +} diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp index 3db96ca9eacb..8235f4acb179 100644 --- a/lib/Analysis/BugReporter.cpp +++ b/lib/Analysis/BugReporter.cpp @@ -15,7 +15,7 @@ #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/CFG.h" +#include "clang/Analysis/CFG.h" #include "clang/AST/Expr.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtObjC.h" @@ -40,36 +40,36 @@ BugReporterContext::~BugReporterContext() { // Helper routines for walking the ExplodedGraph and fetching statements. //===----------------------------------------------------------------------===// -static inline Stmt* GetStmt(ProgramPoint P) { - if (const PostStmt* PS = dyn_cast(&P)) - return PS->getStmt(); +static inline const Stmt* GetStmt(ProgramPoint P) { + if (const StmtPoint* SP = dyn_cast(&P)) + return SP->getStmt(); else if (const BlockEdge* BE = dyn_cast(&P)) return BE->getSrc()->getTerminator(); - + return 0; } -static inline const ExplodedNode* -GetPredecessorNode(const ExplodedNode* N) { +static inline const ExplodedNode* +GetPredecessorNode(const ExplodedNode* N) { return N->pred_empty() ? NULL : *(N->pred_begin()); } -static inline const ExplodedNode* -GetSuccessorNode(const ExplodedNode* N) { +static inline const ExplodedNode* +GetSuccessorNode(const ExplodedNode* N) { return N->succ_empty() ? NULL : *(N->succ_begin()); } -static Stmt* GetPreviousStmt(const ExplodedNode* N) { +static const Stmt* GetPreviousStmt(const ExplodedNode* N) { for (N = GetPredecessorNode(N); N; N = GetPredecessorNode(N)) - if (Stmt *S = GetStmt(N->getLocation())) + if (const Stmt *S = GetStmt(N->getLocation())) return S; - + return 0; } -static Stmt* GetNextStmt(const ExplodedNode* N) { +static const Stmt* GetNextStmt(const ExplodedNode* N) { for (N = GetSuccessorNode(N); N; N = GetSuccessorNode(N)) - if (Stmt *S = GetStmt(N->getLocation())) { + if (const Stmt *S = GetStmt(N->getLocation())) { // Check if the statement is '?' or '&&'/'||'. These are "merges", // not actual statement points. switch (S->getStmtClass()) { @@ -84,23 +84,30 @@ static Stmt* GetNextStmt(const ExplodedNode* N) { default: break; } + + // Some expressions don't have locations. + if (S->getLocStart().isInvalid()) + continue; + return S; } - + return 0; } -static inline Stmt* GetCurrentOrPreviousStmt(const ExplodedNode* N) { - if (Stmt *S = GetStmt(N->getLocation())) +static inline const Stmt* +GetCurrentOrPreviousStmt(const ExplodedNode* N) { + if (const Stmt *S = GetStmt(N->getLocation())) return S; - + return GetPreviousStmt(N); } - -static inline Stmt* GetCurrentOrNextStmt(const ExplodedNode* N) { - if (Stmt *S = GetStmt(N->getLocation())) + +static inline const Stmt* +GetCurrentOrNextStmt(const ExplodedNode* N) { + if (const Stmt *S = GetStmt(N->getLocation())) return S; - + return GetNextStmt(N); } @@ -108,8 +115,8 @@ static inline Stmt* GetCurrentOrNextStmt(const ExplodedNode* N) { // PathDiagnosticBuilder and its associated routines and helper objects. //===----------------------------------------------------------------------===// -typedef llvm::DenseMap*, -const ExplodedNode*> NodeBackMap; +typedef llvm::DenseMap NodeBackMap; namespace { class VISIBILITY_HIDDEN NodeMapClosure : public BugReport::NodeResolver { @@ -117,101 +124,100 @@ class VISIBILITY_HIDDEN NodeMapClosure : public BugReport::NodeResolver { public: NodeMapClosure(NodeBackMap *m) : M(*m) {} ~NodeMapClosure() {} - - const ExplodedNode* getOriginalNode(const ExplodedNode* N) { + + const ExplodedNode* getOriginalNode(const ExplodedNode* N) { NodeBackMap::iterator I = M.find(N); return I == M.end() ? 0 : I->second; } }; - + class VISIBILITY_HIDDEN PathDiagnosticBuilder : public BugReporterContext { BugReport *R; PathDiagnosticClient *PDC; llvm::OwningPtr PM; NodeMapClosure NMC; -public: +public: PathDiagnosticBuilder(GRBugReporter &br, - BugReport *r, NodeBackMap *Backmap, + BugReport *r, NodeBackMap *Backmap, PathDiagnosticClient *pdc) : BugReporterContext(br), - R(r), PDC(pdc), NMC(Backmap) - { + R(r), PDC(pdc), NMC(Backmap) { addVisitor(R); } - - PathDiagnosticLocation ExecutionContinues(const ExplodedNode* N); - + + PathDiagnosticLocation ExecutionContinues(const ExplodedNode* N); + PathDiagnosticLocation ExecutionContinues(llvm::raw_string_ostream& os, - const ExplodedNode* N); - - ParentMap& getParentMap() { - if (PM.get() == 0) - PM.reset(new ParentMap(getCodeDecl().getBody())); - return *PM.get(); - } - + const ExplodedNode* N); + + Decl const &getCodeDecl() { return R->getEndNode()->getCodeDecl(); } + + ParentMap& getParentMap() { return R->getEndNode()->getParentMap(); } + const Stmt *getParent(const Stmt *S) { return getParentMap().getParent(S); } - + virtual NodeMapClosure& getNodeResolver() { return NMC; } BugReport& getReport() { return *R; } PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S); - + PathDiagnosticLocation getEnclosingStmtLocation(const PathDiagnosticLocation &L) { if (const Stmt *S = L.asStmt()) return getEnclosingStmtLocation(S); - + return L; } - + PathDiagnosticClient::PathGenerationScheme getGenerationScheme() const { return PDC ? PDC->getGenerationScheme() : PathDiagnosticClient::Extensive; } bool supportsLogicalOpControlFlow() const { return PDC ? PDC->supportsLogicalOpControlFlow() : true; - } + } }; } // end anonymous namespace PathDiagnosticLocation -PathDiagnosticBuilder::ExecutionContinues(const ExplodedNode* N) { - if (Stmt *S = GetNextStmt(N)) +PathDiagnosticBuilder::ExecutionContinues(const ExplodedNode* N) { + if (const Stmt *S = GetNextStmt(N)) return PathDiagnosticLocation(S, getSourceManager()); - return FullSourceLoc(getCodeDecl().getBodyRBrace(), getSourceManager()); + return FullSourceLoc(N->getLocationContext()->getDecl()->getBodyRBrace(), + getSourceManager()); } - + PathDiagnosticLocation PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream& os, - const ExplodedNode* N) { + const ExplodedNode* N) { // Slow, but probably doesn't matter. if (os.str().empty()) os << ' '; - + const PathDiagnosticLocation &Loc = ExecutionContinues(N); - + if (Loc.asStmt()) os << "Execution continues on line " << getSourceManager().getInstantiationLineNumber(Loc.asLocation()) << '.'; else os << "Execution jumps to the end of the " - << (isa(getCodeDecl()) ? "method" : "function") << '.'; - + << (isa(N->getLocationContext()->getDecl()) ? + "method" : "function") << '.'; + return Loc; } static bool IsNested(const Stmt *S, ParentMap &PM) { if (isa(S) && PM.isConsumedExpr(cast(S))) return true; - + const Stmt *Parent = PM.getParentIgnoreParens(S); - + if (Parent) switch (Parent->getStmtClass()) { case Stmt::ForStmtClass: @@ -221,29 +227,29 @@ static bool IsNested(const Stmt *S, ParentMap &PM) { default: break; } - - return false; + + return false; } PathDiagnosticLocation PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) { assert(S && "Null Stmt* passed to getEnclosingStmtLocation"); - ParentMap &P = getParentMap(); + ParentMap &P = getParentMap(); SourceManager &SMgr = getSourceManager(); while (IsNested(S, P)) { const Stmt *Parent = P.getParentIgnoreParens(S); - + if (!Parent) break; - + switch (Parent->getStmtClass()) { case Stmt::BinaryOperatorClass: { const BinaryOperator *B = cast(Parent); if (B->isLogicalOp()) return PathDiagnosticLocation(S, SMgr); break; - } + } case Stmt::CompoundStmtClass: case Stmt::StmtExprClass: return PathDiagnosticLocation(S, SMgr); @@ -253,20 +259,20 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) { if (cast(Parent)->getCond() == S) return PathDiagnosticLocation(Parent, SMgr); else - return PathDiagnosticLocation(S, SMgr); + return PathDiagnosticLocation(S, SMgr); case Stmt::ConditionalOperatorClass: // For '?', if we are referring to condition, just have the edge point // to the entire '?' expression. if (cast(Parent)->getCond() == S) return PathDiagnosticLocation(Parent, SMgr); else - return PathDiagnosticLocation(S, SMgr); + return PathDiagnosticLocation(S, SMgr); case Stmt::DoStmtClass: - return PathDiagnosticLocation(S, SMgr); + return PathDiagnosticLocation(S, SMgr); case Stmt::ForStmtClass: if (cast(Parent)->getBody() == S) - return PathDiagnosticLocation(S, SMgr); - break; + return PathDiagnosticLocation(S, SMgr); + break; case Stmt::IfStmtClass: if (cast(Parent)->getCond() != S) return PathDiagnosticLocation(S, SMgr); @@ -285,7 +291,7 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) { S = Parent; } - + assert(S && "Cannot have null Stmt for PathDiagnosticLocation"); // Special case: DeclStmts can appear in for statement declarations, in which @@ -298,8 +304,8 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) { return PathDiagnosticLocation(Parent, SMgr); default: break; - } - } + } + } } else if (isa(S)) { // Special case: the binary operator represents the initialization @@ -320,86 +326,86 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) { //===----------------------------------------------------------------------===// static const VarDecl* -GetMostRecentVarDeclBinding(const ExplodedNode* N, +GetMostRecentVarDeclBinding(const ExplodedNode* N, GRStateManager& VMgr, SVal X) { - + for ( ; N ; N = N->pred_empty() ? 0 : *N->pred_begin()) { - + ProgramPoint P = N->getLocation(); - + if (!isa(P)) continue; - - DeclRefExpr* DR = dyn_cast(cast(P).getStmt()); - + + const DeclRefExpr* DR = dyn_cast(cast(P).getStmt()); + if (!DR) continue; - + SVal Y = N->getState()->getSVal(DR); - + if (X != Y) continue; - - VarDecl* VD = dyn_cast(DR->getDecl()); - + + const VarDecl* VD = dyn_cast(DR->getDecl()); + if (!VD) continue; - + return VD; } - + return 0; } namespace { -class VISIBILITY_HIDDEN NotableSymbolHandler +class VISIBILITY_HIDDEN NotableSymbolHandler : public StoreManager::BindingsHandler { - + SymbolRef Sym; const GRState* PrevSt; const Stmt* S; GRStateManager& VMgr; - const ExplodedNode* Pred; - PathDiagnostic& PD; + const ExplodedNode* Pred; + PathDiagnostic& PD; BugReporter& BR; - + public: - + NotableSymbolHandler(SymbolRef sym, const GRState* prevst, const Stmt* s, - GRStateManager& vmgr, const ExplodedNode* pred, + GRStateManager& vmgr, const ExplodedNode* pred, PathDiagnostic& pd, BugReporter& br) : Sym(sym), PrevSt(prevst), S(s), VMgr(vmgr), Pred(pred), PD(pd), BR(br) {} - + bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R, SVal V) { - + SymbolRef ScanSym = V.getAsSymbol(); - + if (ScanSym != Sym) return true; - - // Check if the previous state has this binding. + + // Check if the previous state has this binding. SVal X = PrevSt->getSVal(loc::MemRegionVal(R)); - + if (X == V) // Same binding? return true; - + // Different binding. Only handle assignments for now. We don't pull - // this check out of the loop because we will eventually handle other + // this check out of the loop because we will eventually handle other // cases. - + VarDecl *VD = 0; - + if (const BinaryOperator* B = dyn_cast(S)) { if (!B->isAssignmentOp()) return true; - + // What variable did we assign to? DeclRefExpr* DR = dyn_cast(B->getLHS()->IgnoreParenCasts()); - + if (!DR) return true; - + VD = dyn_cast(DR->getDecl()); } else if (const DeclStmt* DS = dyn_cast(S)) { @@ -408,42 +414,42 @@ public: // holds by contruction in the CFG. VD = dyn_cast(*DS->decl_begin()); } - + if (!VD) return true; - + // What is the most recently referenced variable with this binding? const VarDecl* MostRecent = GetMostRecentVarDeclBinding(Pred, VMgr, V); - + if (!MostRecent) return true; - + // Create the diagnostic. FullSourceLoc L(S->getLocStart(), BR.getSourceManager()); - + if (Loc::IsLocType(VD->getType())) { std::string msg = "'" + std::string(VD->getNameAsString()) + "' now aliases '" + MostRecent->getNameAsString() + "'"; - + PD.push_front(new PathDiagnosticEventPiece(L, msg)); } - + return true; - } + } }; } -static void HandleNotableSymbol(const ExplodedNode* N, +static void HandleNotableSymbol(const ExplodedNode* N, const Stmt* S, SymbolRef Sym, BugReporter& BR, PathDiagnostic& PD) { - - const ExplodedNode* Pred = N->pred_empty() ? 0 : *N->pred_begin(); + + const ExplodedNode* Pred = N->pred_empty() ? 0 : *N->pred_begin(); const GRState* PrevSt = Pred ? Pred->getState() : 0; - + if (!PrevSt) return; - + // Look at the region bindings of the current state that map to the // specified symbol. Are any of them not in the previous state? GRStateManager& VMgr = cast(BR).getStateManager(); @@ -454,34 +460,34 @@ static void HandleNotableSymbol(const ExplodedNode* N, namespace { class VISIBILITY_HIDDEN ScanNotableSymbols : public StoreManager::BindingsHandler { - + llvm::SmallSet AlreadyProcessed; - const ExplodedNode* N; - Stmt* S; + const ExplodedNode* N; + const Stmt* S; GRBugReporter& BR; PathDiagnostic& PD; - + public: - ScanNotableSymbols(const ExplodedNode* n, Stmt* s, GRBugReporter& br, - PathDiagnostic& pd) + ScanNotableSymbols(const ExplodedNode* n, const Stmt* s, + GRBugReporter& br, PathDiagnostic& pd) : N(n), S(s), BR(br), PD(pd) {} - + bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R, SVal V) { - + SymbolRef ScanSym = V.getAsSymbol(); - + if (!ScanSym) return true; - + if (!BR.isNotable(ScanSym)) return true; - + if (AlreadyProcessed.count(ScanSym)) return true; - + AlreadyProcessed.insert(ScanSym); - + HandleNotableSymbol(N, S, ScanSym, BR, PD); return true; } @@ -496,57 +502,57 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM); static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, PathDiagnosticBuilder &PDB, - const ExplodedNode *N) { + const ExplodedNode *N) { SourceManager& SMgr = PDB.getSourceManager(); - const ExplodedNode* NextNode = N->pred_empty() + const ExplodedNode* NextNode = N->pred_empty() ? NULL : *(N->pred_begin()); while (NextNode) { - N = NextNode; + N = NextNode; NextNode = GetPredecessorNode(N); - + ProgramPoint P = N->getLocation(); - + if (const BlockEdge* BE = dyn_cast(&P)) { CFGBlock* Src = BE->getSrc(); CFGBlock* Dst = BE->getDst(); Stmt* T = Src->getTerminator(); - + if (!T) continue; - + FullSourceLoc Start(T->getLocStart(), SMgr); - + switch (T->getStmtClass()) { default: break; - + case Stmt::GotoStmtClass: - case Stmt::IndirectGotoStmtClass: { - Stmt* S = GetNextStmt(N); - + case Stmt::IndirectGotoStmtClass: { + const Stmt* S = GetNextStmt(N); + if (!S) continue; - + std::string sbuf; - llvm::raw_string_ostream os(sbuf); + llvm::raw_string_ostream os(sbuf); const PathDiagnosticLocation &End = PDB.getEnclosingStmtLocation(S); - + os << "Control jumps to line " << End.asLocation().getInstantiationLineNumber(); PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, os.str())); break; } - - case Stmt::SwitchStmtClass: { + + case Stmt::SwitchStmtClass: { // Figure out what case arm we took. std::string sbuf; llvm::raw_string_ostream os(sbuf); - + if (Stmt* S = Dst->getLabel()) { PathDiagnosticLocation End(S, SMgr); - + switch (S->getStmtClass()) { default: os << "No cases match in the switch statement. " @@ -557,21 +563,21 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, os << "Control jumps to the 'default' case at line " << End.asLocation().getInstantiationLineNumber(); break; - + case Stmt::CaseStmtClass: { - os << "Control jumps to 'case "; - CaseStmt* Case = cast(S); + os << "Control jumps to 'case "; + CaseStmt* Case = cast(S); Expr* LHS = Case->getLHS()->IgnoreParenCasts(); - - // Determine if it is an enum. + + // Determine if it is an enum. bool GetRawInt = true; - + if (DeclRefExpr* DR = dyn_cast(LHS)) { // FIXME: Maybe this should be an assertion. Are there cases // were it is not an EnumConstantDecl? EnumConstantDecl* D = dyn_cast(DR->getDecl()); - + if (D) { GetRawInt = false; os << D->getNameAsString(); @@ -591,14 +597,14 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, } else { os << "'Default' branch taken. "; - const PathDiagnosticLocation &End = PDB.ExecutionContinues(os, N); + const PathDiagnosticLocation &End = PDB.ExecutionContinues(os, N); PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, os.str())); } - + break; } - + case Stmt::BreakStmtClass: case Stmt::ContinueStmtClass: { std::string sbuf; @@ -608,117 +614,117 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, os.str())); break; } - + // Determine control-flow for ternary '?'. case Stmt::ConditionalOperatorClass: { std::string sbuf; llvm::raw_string_ostream os(sbuf); os << "'?' condition is "; - + if (*(Src->succ_begin()+1) == Dst) os << "false"; else os << "true"; - + PathDiagnosticLocation End = PDB.ExecutionContinues(N); - + if (const Stmt *S = End.asStmt()) End = PDB.getEnclosingStmtLocation(S); - + PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, os.str())); break; } - + // Determine control-flow for short-circuited '&&' and '||'. case Stmt::BinaryOperatorClass: { if (!PDB.supportsLogicalOpControlFlow()) break; - + BinaryOperator *B = cast(T); std::string sbuf; llvm::raw_string_ostream os(sbuf); os << "Left side of '"; - + if (B->getOpcode() == BinaryOperator::LAnd) { os << "&&" << "' is "; - + if (*(Src->succ_begin()+1) == Dst) { os << "false"; PathDiagnosticLocation End(B->getLHS(), SMgr); PathDiagnosticLocation Start(B->getOperatorLoc(), SMgr); PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, os.str())); - } + } else { os << "true"; PathDiagnosticLocation Start(B->getLHS(), SMgr); PathDiagnosticLocation End = PDB.ExecutionContinues(N); PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, os.str())); - } + } } else { assert(B->getOpcode() == BinaryOperator::LOr); os << "||" << "' is "; - + if (*(Src->succ_begin()+1) == Dst) { os << "false"; PathDiagnosticLocation Start(B->getLHS(), SMgr); PathDiagnosticLocation End = PDB.ExecutionContinues(N); PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, - os.str())); + os.str())); } else { os << "true"; PathDiagnosticLocation End(B->getLHS(), SMgr); PathDiagnosticLocation Start(B->getOperatorLoc(), SMgr); PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, - os.str())); + os.str())); } } - + break; } - - case Stmt::DoStmtClass: { + + case Stmt::DoStmtClass: { if (*(Src->succ_begin()) == Dst) { std::string sbuf; llvm::raw_string_ostream os(sbuf); - + os << "Loop condition is true. "; PathDiagnosticLocation End = PDB.ExecutionContinues(os, N); - + if (const Stmt *S = End.asStmt()) End = PDB.getEnclosingStmtLocation(S); - + PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, os.str())); } else { PathDiagnosticLocation End = PDB.ExecutionContinues(N); - + if (const Stmt *S = End.asStmt()) End = PDB.getEnclosingStmtLocation(S); - + PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, "Loop condition is false. Exiting loop")); } - + break; } - + case Stmt::WhileStmtClass: - case Stmt::ForStmtClass: { + case Stmt::ForStmtClass: { if (*(Src->succ_begin()+1) == Dst) { std::string sbuf; llvm::raw_string_ostream os(sbuf); - + os << "Loop condition is false. "; PathDiagnosticLocation End = PDB.ExecutionContinues(os, N); if (const Stmt *S = End.asStmt()) End = PDB.getEnclosingStmtLocation(S); - + PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, os.str())); } @@ -726,32 +732,32 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, PathDiagnosticLocation End = PDB.ExecutionContinues(N); if (const Stmt *S = End.asStmt()) End = PDB.getEnclosingStmtLocation(S); - + PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, "Loop condition is true. Entering loop body")); } - + break; } - + case Stmt::IfStmtClass: { PathDiagnosticLocation End = PDB.ExecutionContinues(N); - + if (const Stmt *S = End.asStmt()) End = PDB.getEnclosingStmtLocation(S); - + if (*(Src->succ_begin()+1) == Dst) PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, "Taking false branch")); - else + else PD.push_front(new PathDiagnosticControlFlowPiece(Start, End, "Taking true branch")); - + break; } } } - + if (NextNode) { for (BugReporterContext::visitor_iterator I = PDB.visitor_begin(), E = PDB.visitor_end(); I!=E; ++I) { @@ -759,15 +765,15 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, PD.push_front(p); } } - - if (const PostStmt* PS = dyn_cast(&P)) { + + if (const PostStmt* PS = dyn_cast(&P)) { // Scan the region bindings, and see if a "notable" symbol has a new // lval binding. ScanNotableSymbols SNS(N, PS->getStmt(), PDB.getBugReporter(), PD); PDB.getStateManager().iterBindings(N->getState(), SNS); } } - + // After constructing the full PathDiagnostic, do a pass over it to compact // PathDiagnosticPieces that occur within a macro. CompactPathDiagnostic(PD, PDB.getSourceManager()); @@ -779,20 +785,20 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, static bool IsControlFlowExpr(const Stmt *S) { const Expr *E = dyn_cast(S); - + if (!E) return false; - - E = E->IgnoreParenCasts(); - + + E = E->IgnoreParenCasts(); + if (isa(E)) return true; - + if (const BinaryOperator *B = dyn_cast(E)) if (B->isLogicalOp()) return true; - - return false; + + return false; } namespace { @@ -801,25 +807,25 @@ class VISIBILITY_HIDDEN ContextLocation : public PathDiagnosticLocation { public: ContextLocation(const PathDiagnosticLocation &L, bool isdead = false) : PathDiagnosticLocation(L), IsDead(isdead) {} - - void markDead() { IsDead = true; } + + void markDead() { IsDead = true; } bool isDead() const { return IsDead; } }; - + class VISIBILITY_HIDDEN EdgeBuilder { std::vector CLocs; typedef std::vector::iterator iterator; PathDiagnostic &PD; PathDiagnosticBuilder &PDB; PathDiagnosticLocation PrevLoc; - + bool IsConsumedExpr(const PathDiagnosticLocation &L); - + bool containsLocation(const PathDiagnosticLocation &Container, const PathDiagnosticLocation &Containee); - + PathDiagnosticLocation getContextLocation(const PathDiagnosticLocation &L); - + PathDiagnosticLocation cleanUpLocation(PathDiagnosticLocation L, bool firstCharOnly = false) { if (const Stmt *S = L.asStmt()) { @@ -847,20 +853,20 @@ class VISIBILITY_HIDDEN EdgeBuilder { firstCharOnly = true; continue; } - + break; } - + if (S != Original) L = PathDiagnosticLocation(S, L.getManager()); } - + if (firstCharOnly) L = PathDiagnosticLocation(L.asLocation()); return L; } - + void popLocation() { if (!CLocs.back().isDead() && CLocs.back().asLocation().isFileID()) { // For contexts, we only one the first character as the range. @@ -868,18 +874,18 @@ class VISIBILITY_HIDDEN EdgeBuilder { } CLocs.pop_back(); } - - PathDiagnosticLocation IgnoreParens(const PathDiagnosticLocation &L); + + PathDiagnosticLocation IgnoreParens(const PathDiagnosticLocation &L); public: EdgeBuilder(PathDiagnostic &pd, PathDiagnosticBuilder &pdb) : PD(pd), PDB(pdb) { - + // If the PathDiagnostic already has pieces, add the enclosing statement // of the first piece as a context as well. if (!PD.empty()) { PrevLoc = PD.begin()->getLocation(); - + if (const Stmt *S = PrevLoc.asStmt()) addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt()); } @@ -887,7 +893,7 @@ public: ~EdgeBuilder() { while (!CLocs.empty()) popLocation(); - + // Finally, add an initial edge from the start location of the first // statement (if it doesn't already exist). // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. @@ -897,20 +903,20 @@ public: SourceLocation Loc = (*CS->body_begin())->getLocStart(); rawAddEdge(PathDiagnosticLocation(Loc, PDB.getSourceManager())); } - + } void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false); - + void addEdge(const Stmt *S, bool alwaysAdd = false) { addEdge(PathDiagnosticLocation(S, PDB.getSourceManager()), alwaysAdd); } - + void rawAddEdge(PathDiagnosticLocation NewLoc); - + void addContext(const Stmt *S); void addExtendedContext(const Stmt *S); -}; +}; } // end anonymous namespace @@ -919,10 +925,10 @@ EdgeBuilder::getContextLocation(const PathDiagnosticLocation &L) { if (const Stmt *S = L.asStmt()) { if (IsControlFlowExpr(S)) return L; - - return PDB.getEnclosingStmtLocation(S); + + return PDB.getEnclosingStmtLocation(S); } - + return L; } @@ -931,10 +937,10 @@ bool EdgeBuilder::containsLocation(const PathDiagnosticLocation &Container, if (Container == Containee) return true; - + if (Container.asDecl()) return true; - + if (const Stmt *S = Containee.asStmt()) if (const Stmt *ContainerS = Container.asStmt()) { while (S) { @@ -948,25 +954,25 @@ bool EdgeBuilder::containsLocation(const PathDiagnosticLocation &Container, // Less accurate: compare using source ranges. SourceRange ContainerR = Container.asRange(); SourceRange ContaineeR = Containee.asRange(); - + SourceManager &SM = PDB.getSourceManager(); SourceLocation ContainerRBeg = SM.getInstantiationLoc(ContainerR.getBegin()); SourceLocation ContainerREnd = SM.getInstantiationLoc(ContainerR.getEnd()); SourceLocation ContaineeRBeg = SM.getInstantiationLoc(ContaineeR.getBegin()); SourceLocation ContaineeREnd = SM.getInstantiationLoc(ContaineeR.getEnd()); - + unsigned ContainerBegLine = SM.getInstantiationLineNumber(ContainerRBeg); unsigned ContainerEndLine = SM.getInstantiationLineNumber(ContainerREnd); unsigned ContaineeBegLine = SM.getInstantiationLineNumber(ContaineeRBeg); unsigned ContaineeEndLine = SM.getInstantiationLineNumber(ContaineeREnd); - + assert(ContainerBegLine <= ContainerEndLine); - assert(ContaineeBegLine <= ContaineeEndLine); - + assert(ContaineeBegLine <= ContaineeEndLine); + return (ContainerBegLine <= ContaineeBegLine && ContainerEndLine >= ContaineeEndLine && (ContainerBegLine != ContaineeBegLine || - SM.getInstantiationColumnNumber(ContainerRBeg) <= + SM.getInstantiationColumnNumber(ContainerRBeg) <= SM.getInstantiationColumnNumber(ContaineeRBeg)) && (ContainerEndLine != ContaineeEndLine || SM.getInstantiationColumnNumber(ContainerREnd) >= @@ -986,13 +992,13 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) { PrevLoc = NewLoc; return; } - + const PathDiagnosticLocation &NewLocClean = cleanUpLocation(NewLoc); const PathDiagnosticLocation &PrevLocClean = cleanUpLocation(PrevLoc); - + if (NewLocClean.asLocation() == PrevLocClean.asLocation()) return; - + // FIXME: Ignore intra-macro edges for now. if (NewLocClean.asLocation().getInstantiationLoc() == PrevLocClean.asLocation().getInstantiationLoc()) @@ -1003,15 +1009,15 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) { } void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) { - + if (!alwaysAdd && NewLoc.asLocation().isMacroID()) return; - + const PathDiagnosticLocation &CLoc = getContextLocation(NewLoc); while (!CLocs.empty()) { ContextLocation &TopContextLoc = CLocs.back(); - + // Is the top location context the same as the one for the new location? if (TopContextLoc == CLoc) { if (alwaysAdd) { @@ -1028,21 +1034,21 @@ void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) { if (containsLocation(TopContextLoc, CLoc)) { if (alwaysAdd) { rawAddEdge(NewLoc); - + if (IsConsumedExpr(CLoc) && !IsControlFlowExpr(CLoc.asStmt())) { CLocs.push_back(ContextLocation(CLoc, true)); return; } } - + CLocs.push_back(CLoc); - return; + return; } // Context does not contain the location. Flush it. popLocation(); } - + // If we reach here, there is no enclosing context. Just add the edge. rawAddEdge(NewLoc); } @@ -1050,15 +1056,15 @@ void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) { bool EdgeBuilder::IsConsumedExpr(const PathDiagnosticLocation &L) { if (const Expr *X = dyn_cast_or_null(L.asStmt())) return PDB.getParentMap().isConsumedExpr(X) && !IsControlFlowExpr(X); - + return false; } - + void EdgeBuilder::addExtendedContext(const Stmt *S) { if (!S) return; - - const Stmt *Parent = PDB.getParent(S); + + const Stmt *Parent = PDB.getParent(S); while (Parent) { if (isa(Parent)) Parent = PDB.getParent(Parent); @@ -1075,16 +1081,16 @@ void EdgeBuilder::addExtendedContext(const Stmt *S) { break; } } - + addContext(S); } - + void EdgeBuilder::addContext(const Stmt *S) { if (!S) return; PathDiagnosticLocation L(S, PDB.getSourceManager()); - + while (!CLocs.empty()) { const PathDiagnosticLocation &TopContextLoc = CLocs.back(); @@ -1094,7 +1100,7 @@ void EdgeBuilder::addContext(const Stmt *S) { if (containsLocation(TopContextLoc, L)) { CLocs.push_back(L); - return; + return; } // Context does not contain the location. Flush it. @@ -1106,12 +1112,12 @@ void EdgeBuilder::addContext(const Stmt *S) { static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, PathDiagnosticBuilder &PDB, - const ExplodedNode *N) { - - + const ExplodedNode *N) { + + EdgeBuilder EB(PD, PDB); - const ExplodedNode* NextNode = N->pred_empty() + const ExplodedNode* NextNode = N->pred_empty() ? NULL : *(N->pred_begin()); while (NextNode) { N = NextNode; @@ -1123,26 +1129,26 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, if (const BlockEdge *BE = dyn_cast(&P)) { const CFGBlock &Blk = *BE->getSrc(); const Stmt *Term = Blk.getTerminator(); - + // Are we jumping to the head of a loop? Add a special diagnostic. if (const Stmt *Loop = BE->getDst()->getLoopTarget()) { PathDiagnosticLocation L(Loop, PDB.getSourceManager()); const CompoundStmt *CS = NULL; - + if (!Term) { if (const ForStmt *FS = dyn_cast(Loop)) CS = dyn_cast(FS->getBody()); else if (const WhileStmt *WS = dyn_cast(Loop)) - CS = dyn_cast(WS->getBody()); + CS = dyn_cast(WS->getBody()); } - + PathDiagnosticEventPiece *p = new PathDiagnosticEventPiece(L, "Looping back to the head of the loop"); - + EB.addEdge(p->getLocation(), true); PD.push_front(p); - + if (CS) { PathDiagnosticLocation BL(CS->getRBracLoc(), PDB.getSourceManager()); @@ -1150,14 +1156,14 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, EB.addEdge(BL); } } - + if (Term) EB.addContext(Term); - + break; } - if (const BlockEntrance *BE = dyn_cast(&P)) { + if (const BlockEntrance *BE = dyn_cast(&P)) { if (const Stmt* S = BE->getFirstStmt()) { if (IsControlFlowExpr(S)) { // Add the proper context for '&&', '||', and '?'. @@ -1170,10 +1176,10 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, break; } } while (0); - + if (!NextNode) continue; - + for (BugReporterContext::visitor_iterator I = PDB.visitor_begin(), E = PDB.visitor_end(); I!=E; ++I) { if (PathDiagnosticPiece* p = (*I)->VisitNode(N, NextNode, PDB)) { @@ -1181,16 +1187,25 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, EB.addEdge(Loc, true); PD.push_front(p); if (const Stmt *S = Loc.asStmt()) - EB.addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt()); + EB.addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt()); } - } + } } } //===----------------------------------------------------------------------===// // Methods for BugType and subclasses. //===----------------------------------------------------------------------===// -BugType::~BugType() {} +BugType::~BugType() { + // Free up the equivalence class objects. Observe that we get a pointer to + // the object first before incrementing the iterator, as destroying the + // node before doing so means we will read from freed memory. + for (iterator I = begin(), E = end(); I !=E; ) { + BugReportEquivClass *EQ = &*I; + ++I; + delete EQ; + } +} void BugType::FlushReports(BugReporter &BR) {} //===----------------------------------------------------------------------===// @@ -1199,46 +1214,47 @@ void BugType::FlushReports(BugReporter &BR) {} BugReport::~BugReport() {} RangedBugReport::~RangedBugReport() {} -Stmt* BugReport::getStmt(BugReporter& BR) const { - ProgramPoint ProgP = EndNode->getLocation(); - Stmt *S = NULL; - +const Stmt* BugReport::getStmt() const { + ProgramPoint ProgP = EndNode->getLocation(); + const Stmt *S = NULL; + if (BlockEntrance* BE = dyn_cast(&ProgP)) { - if (BE->getBlock() == &BR.getCFG()->getExit()) S = GetPreviousStmt(EndNode); + CFGBlock &Exit = ProgP.getLocationContext()->getCFG()->getExit(); + if (BE->getBlock() == &Exit) + S = GetPreviousStmt(EndNode); } - if (!S) S = GetStmt(ProgP); - - return S; + if (!S) + S = GetStmt(ProgP); + + return S; } PathDiagnosticPiece* BugReport::getEndPath(BugReporterContext& BRC, - const ExplodedNode* EndPathNode) { - - Stmt* S = getStmt(BRC.getBugReporter()); - + const ExplodedNode* EndPathNode) { + + const Stmt* S = getStmt(); + if (!S) return NULL; const SourceRange *Beg, *End; - getRanges(BRC.getBugReporter(), Beg, End); + getRanges(Beg, End); PathDiagnosticLocation L(S, BRC.getSourceManager()); - + // Only add the statement itself as a range if we didn't specify any // special ranges for this report. PathDiagnosticPiece* P = new PathDiagnosticEventPiece(L, getDescription(), Beg == End); - + for (; Beg != End; ++Beg) P->addRange(*Beg); - + return P; } -void BugReport::getRanges(BugReporter& BR, const SourceRange*& beg, - const SourceRange*& end) { - - if (Expr* E = dyn_cast_or_null(getStmt(BR))) { +void BugReport::getRanges(const SourceRange*& beg, const SourceRange*& end) { + if (const Expr* E = dyn_cast_or_null(getStmt())) { R = E->getSourceRange(); assert(R.isValid()); beg = &R; @@ -1248,12 +1264,15 @@ void BugReport::getRanges(BugReporter& BR, const SourceRange*& beg, beg = end = 0; } -SourceLocation BugReport::getLocation() const { +SourceLocation BugReport::getLocation() const { if (EndNode) - if (Stmt* S = GetCurrentOrPreviousStmt(EndNode)) { + if (const Stmt* S = GetCurrentOrPreviousStmt(EndNode)) { // For member expressions, return the location of the '.' or '->'. - if (MemberExpr* ME = dyn_cast(S)) + if (const MemberExpr *ME = dyn_cast(S)) return ME->getMemberLoc(); + // For binary operators, return the location of the operator. + if (const BinaryOperator *B = dyn_cast(S)) + return B->getOperatorLoc(); return S->getLocStart(); } @@ -1261,8 +1280,8 @@ SourceLocation BugReport::getLocation() const { return FullSourceLoc(); } -PathDiagnosticPiece* BugReport::VisitNode(const ExplodedNode* N, - const ExplodedNode* PrevN, +PathDiagnosticPiece* BugReport::VisitNode(const ExplodedNode* N, + const ExplodedNode* PrevN, BugReporterContext &BRC) { return NULL; } @@ -1275,11 +1294,10 @@ BugReportEquivClass::~BugReportEquivClass() { for (iterator I=begin(), E=end(); I!=E; ++I) delete *I; } -GRBugReporter::~GRBugReporter() { FlushReports(); } +GRBugReporter::~GRBugReporter() { } BugReporterData::~BugReporterData() {} -ExplodedGraph& -GRBugReporter::getGraph() { return Eng.getGraph(); } +ExplodedGraph &GRBugReporter::getGraph() { return Eng.getGraph(); } GRStateManager& GRBugReporter::getStateManager() { return Eng.getStateManager(); } @@ -1308,9 +1326,8 @@ void BugReporter::FlushReports() { BugReportEquivClass& EQ = *EI; FlushReport(EQ); } - - // Delete the BugType object. This will also delete the equivalence - // classes. + + // Delete the BugType object. delete BT; } @@ -1322,137 +1339,134 @@ void BugReporter::FlushReports() { // PathDiagnostics generation. //===----------------------------------------------------------------------===// -static std::pair*, NodeBackMap*>, - std::pair*, unsigned> > -MakeReportGraph(const ExplodedGraph* G, - const ExplodedNode** NStart, - const ExplodedNode** NEnd) { - +static std::pair, + std::pair > +MakeReportGraph(const ExplodedGraph* G, + const ExplodedNode** NStart, + const ExplodedNode** NEnd) { + // Create the trimmed graph. It will contain the shortest paths from the - // error nodes to the root. In the new graph we should only have one + // error nodes to the root. In the new graph we should only have one // error node unless there are two or more error nodes with the same minimum // path length. - ExplodedGraph* GTrim; - InterExplodedGraphMap* NMap; + ExplodedGraph* GTrim; + InterExplodedGraphMap* NMap; llvm::DenseMap InverseMap; llvm::tie(GTrim, NMap) = G->Trim(NStart, NEnd, &InverseMap); - + // Create owning pointers for GTrim and NMap just to ensure that they are // released when this function exists. - llvm::OwningPtr > AutoReleaseGTrim(GTrim); - llvm::OwningPtr > AutoReleaseNMap(NMap); - + llvm::OwningPtr AutoReleaseGTrim(GTrim); + llvm::OwningPtr AutoReleaseNMap(NMap); + // Find the (first) error node in the trimmed graph. We just need to consult // the node map (NMap) which maps from nodes in the original graph to nodes // in the new graph. - std::queue*> WS; - typedef llvm::DenseMap*,unsigned> IndexMapTy; + std::queue WS; + typedef llvm::DenseMap IndexMapTy; IndexMapTy IndexMap; - for (const ExplodedNode** I = NStart; I != NEnd; ++I) - if (const ExplodedNode *N = NMap->getMappedNode(*I)) { + for (const ExplodedNode** I = NStart; I != NEnd; ++I) + if (const ExplodedNode *N = NMap->getMappedNode(*I)) { unsigned NodeIndex = (I - NStart) / sizeof(*I); WS.push(N); IndexMap[*I] = NodeIndex; } - + assert(!WS.empty() && "No error node found in the trimmed graph."); // Create a new (third!) graph with a single path. This is the graph // that will be returned to the caller. - ExplodedGraph *GNew = - new ExplodedGraph(GTrim->getCFG(), GTrim->getCodeDecl(), - GTrim->getContext()); - + ExplodedGraph *GNew = new ExplodedGraph(GTrim->getContext()); + // Sometimes the trimmed graph can contain a cycle. Perform a reverse BFS // to the root node, and then construct a new graph that contains only // a single path. llvm::DenseMap Visited; - + unsigned cnt = 0; - const ExplodedNode* Root = 0; - + const ExplodedNode* Root = 0; + while (!WS.empty()) { - const ExplodedNode* Node = WS.front(); + const ExplodedNode* Node = WS.front(); WS.pop(); - + if (Visited.find(Node) != Visited.end()) continue; - + Visited[Node] = cnt++; - + if (Node->pred_empty()) { Root = Node; break; } - - for (ExplodedNode::const_pred_iterator I=Node->pred_begin(), + + for (ExplodedNode::const_pred_iterator I=Node->pred_begin(), E=Node->pred_end(); I!=E; ++I) WS.push(*I); } - + assert(Root); - + // Now walk from the root down the BFS path, always taking the successor // with the lowest number. - ExplodedNode *Last = 0, *First = 0; + ExplodedNode *Last = 0, *First = 0; NodeBackMap *BM = new NodeBackMap(); unsigned NodeIndex = 0; - - for ( const ExplodedNode *N = Root ;;) { + + for ( const ExplodedNode *N = Root ;;) { // Lookup the number associated with the current node. llvm::DenseMap::iterator I = Visited.find(N); assert(I != Visited.end()); - + // Create the equivalent node in the new graph with the same state // and location. - ExplodedNode* NewN = - GNew->getNode(N->getLocation(), N->getState()); - + ExplodedNode* NewN = GNew->getNode(N->getLocation(), N->getState()); + // Store the mapping to the original node. llvm::DenseMap::iterator IMitr=InverseMap.find(N); assert(IMitr != InverseMap.end() && "No mapping to original node."); - (*BM)[NewN] = (const ExplodedNode*) IMitr->second; - + (*BM)[NewN] = (const ExplodedNode*) IMitr->second; + // Link up the new node with the previous node. if (Last) - NewN->addPredecessor(Last); - + NewN->addPredecessor(Last, *GNew); + Last = NewN; - + // Are we at the final node? IndexMapTy::iterator IMI = - IndexMap.find((const ExplodedNode*)(IMitr->second)); + IndexMap.find((const ExplodedNode*)(IMitr->second)); if (IMI != IndexMap.end()) { First = NewN; NodeIndex = IMI->second; break; } - + // Find the next successor node. We choose the node that is marked // with the lowest DFS number. - ExplodedNode::const_succ_iterator SI = N->succ_begin(); - ExplodedNode::const_succ_iterator SE = N->succ_end(); + ExplodedNode::const_succ_iterator SI = N->succ_begin(); + ExplodedNode::const_succ_iterator SE = N->succ_end(); N = 0; - + for (unsigned MinVal = 0; SI != SE; ++SI) { - + I = Visited.find(*SI); - + if (I == Visited.end()) continue; - + if (!N || I->second < MinVal) { N = *SI; MinVal = I->second; } } - + assert(N); } - + assert(First); return std::make_pair(std::make_pair(GNew, BM), @@ -1464,23 +1478,23 @@ MakeReportGraph(const ExplodedGraph* G, static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) { typedef std::vector > MacroStackTy; - + typedef std::vector PiecesTy; - + MacroStackTy MacroStack; PiecesTy Pieces; - + for (PathDiagnostic::iterator I = PD.begin(), E = PD.end(); I!=E; ++I) { // Get the location of the PathDiagnosticPiece. - const FullSourceLoc Loc = I->getLocation().asLocation(); - + const FullSourceLoc Loc = I->getLocation().asLocation(); + // Determine the instantiation location, which is the location we group // related PathDiagnosticPieces. - SourceLocation InstantiationLoc = Loc.isMacroID() ? + SourceLocation InstantiationLoc = Loc.isMacroID() ? SM.getInstantiationLoc(Loc) : SourceLocation(); - + if (Loc.isFileID()) { MacroStack.clear(); Pieces.push_back(&*I); @@ -1488,7 +1502,7 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) { } assert(Loc.isMacroID()); - + // Is the PathDiagnosticPiece within the same macro group? if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) { MacroStack.back().first->push_back(&*I); @@ -1502,22 +1516,22 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) { SourceLocation ParentInstantiationLoc = InstantiationLoc.isMacroID() ? SM.getInstantiationLoc(Loc) : SourceLocation(); - + // Walk the entire macro stack. while (!MacroStack.empty()) { if (InstantiationLoc == MacroStack.back().second) { MacroGroup = MacroStack.back().first; break; } - + if (ParentInstantiationLoc == MacroStack.back().second) { MacroGroup = MacroStack.back().first; break; } - + MacroStack.pop_back(); } - + if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) { // Create a new macro group and add it to the stack. PathDiagnosticMacroPiece *NewGroup = new PathDiagnosticMacroPiece(Loc); @@ -1528,7 +1542,7 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) { assert(InstantiationLoc.isFileID()); Pieces.push_back(NewGroup); } - + MacroGroup = NewGroup; MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc)); } @@ -1536,62 +1550,62 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) { // Finally, add the PathDiagnosticPiece to the group. MacroGroup->push_back(&*I); } - + // Now take the pieces and construct a new PathDiagnostic. PD.resetPath(false); - + for (PiecesTy::iterator I=Pieces.begin(), E=Pieces.end(); I!=E; ++I) { if (PathDiagnosticMacroPiece *MP=dyn_cast(*I)) if (!MP->containsEvent()) { delete MP; continue; } - + PD.push_back(*I); } } void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, BugReportEquivClass& EQ) { - - std::vector*> Nodes; - + + std::vector Nodes; + for (BugReportEquivClass::iterator I=EQ.begin(), E=EQ.end(); I!=E; ++I) { - const ExplodedNode* N = I->getEndNode(); + const ExplodedNode* N = I->getEndNode(); if (N) Nodes.push_back(N); } - + if (Nodes.empty()) return; - + // Construct a new graph that contains only a single path from the error - // node to a root. - const std::pair*, NodeBackMap*>, - std::pair*, unsigned> >& + // node to a root. + const std::pair, + std::pair >& GPair = MakeReportGraph(&getGraph(), &Nodes[0], &Nodes[0] + Nodes.size()); - + // Find the BugReport with the original location. BugReport *R = 0; unsigned i = 0; for (BugReportEquivClass::iterator I=EQ.begin(), E=EQ.end(); I!=E; ++I, ++i) if (i == GPair.second.second) { R = *I; break; } - + assert(R && "No original report found for sliced graph."); - - llvm::OwningPtr > ReportGraph(GPair.first.first); + + llvm::OwningPtr ReportGraph(GPair.first.first); llvm::OwningPtr BackMap(GPair.first.second); - const ExplodedNode *N = GPair.second.first; - - // Start building the path diagnostic... + const ExplodedNode *N = GPair.second.first; + + // Start building the path diagnostic... PathDiagnosticBuilder PDB(*this, R, BackMap.get(), getPathDiagnosticClient()); - + if (PathDiagnosticPiece* Piece = R->getEndPath(PDB, N)) PD.push_back(Piece); else return; - + R->registerInitialVisitors(PDB, N); - + switch (PDB.getGenerationScheme()) { case PathDiagnosticClient::Extensive: GenerateExtensivePathDiagnostic(PD, PDB, N); @@ -1606,17 +1620,17 @@ void BugReporter::Register(BugType *BT) { BugTypes = F.Add(BugTypes, BT); } -void BugReporter::EmitReport(BugReport* R) { +void BugReporter::EmitReport(BugReport* R) { // Compute the bug report's hash to determine its equivalence class. llvm::FoldingSetNodeID ID; R->Profile(ID); - - // Lookup the equivance class. If there isn't one, create it. + + // Lookup the equivance class. If there isn't one, create it. BugType& BT = R->getBugType(); Register(&BT); void *InsertPos; - BugReportEquivClass* EQ = BT.EQClasses.FindNodeOrInsertPos(ID, InsertPos); - + BugReportEquivClass* EQ = BT.EQClasses.FindNodeOrInsertPos(ID, InsertPos); + if (!EQ) { EQ = new BugReportEquivClass(R); BT.EQClasses.InsertNode(EQ, InsertPos); @@ -1625,34 +1639,178 @@ void BugReporter::EmitReport(BugReport* R) { EQ->AddReport(R); } + +//===----------------------------------------------------------------------===// +// Emitting reports in equivalence classes. +//===----------------------------------------------------------------------===// + +namespace { +struct VISIBILITY_HIDDEN FRIEC_WLItem { + const ExplodedNode *N; + ExplodedNode::const_succ_iterator I, E; + + FRIEC_WLItem(const ExplodedNode *n) + : N(n), I(N->succ_begin()), E(N->succ_end()) {} +}; +} + +static BugReport *FindReportInEquivalenceClass(BugReportEquivClass& EQ) { + BugReportEquivClass::iterator I = EQ.begin(), E = EQ.end(); + assert(I != E); + BugReport *R = *I; + BugType& BT = R->getBugType(); + + if (!BT.isSuppressOnSink()) + return R; + + // For bug reports that should be suppressed when all paths are post-dominated + // by a sink node, iterate through the reports in the equivalence class + // until we find one that isn't post-dominated (if one exists). We use a + // DFS traversal of the ExplodedGraph to find a non-sink node. We could write + // this as a recursive function, but we don't want to risk blowing out the + // stack for very long paths. + for (; I != E; ++I) { + R = *I; + const ExplodedNode *N = R->getEndNode(); + + if (!N) + continue; + + if (N->isSink()) { + assert(false && + "BugType::isSuppressSink() should not be 'true' for sink end nodes"); + return R; + } + + if (N->succ_empty()) + return R; + + // At this point we know that 'N' is not a sink and it has at least one + // successor. Use a DFS worklist to find a non-sink end-of-path node. + typedef FRIEC_WLItem WLItem; + typedef llvm::SmallVector DFSWorkList; + llvm::DenseMap Visited; + + DFSWorkList WL; + WL.push_back(N); + Visited[N] = 1; + + while (!WL.empty()) { + WLItem &WI = WL.back(); + assert(!WI.N->succ_empty()); + + for (; WI.I != WI.E; ++WI.I) { + const ExplodedNode *Succ = *WI.I; + // End-of-path node? + if (Succ->succ_empty()) { + // If we found an end-of-path node that is not a sink, then return + // this report. + if (!Succ->isSink()) + return R; + + // Found a sink? Continue on to the next successor. + continue; + } + + // Mark the successor as visited. If it hasn't been explored, + // enqueue it to the DFS worklist. + unsigned &mark = Visited[Succ]; + if (!mark) { + mark = 1; + WL.push_back(Succ); + break; + } + } + + if (&WL.back() == &WI) + WL.pop_back(); + } + } + + // If we reach here, the end nodes for all reports in the equivalence + // class are post-dominated by a sink node. + return NULL; +} + + +//===----------------------------------------------------------------------===// +// DiagnosticCache. This is a hack to cache analyzer diagnostics. It +// uses global state, which eventually should go elsewhere. +//===----------------------------------------------------------------------===// +namespace { +class VISIBILITY_HIDDEN DiagCacheItem : public llvm::FoldingSetNode { + llvm::FoldingSetNodeID ID; +public: + DiagCacheItem(BugReport *R, PathDiagnostic *PD) { + ID.AddString(R->getBugType().getName()); + ID.AddString(R->getBugType().getCategory()); + ID.AddString(R->getDescription()); + ID.AddInteger(R->getLocation().getRawEncoding()); + PD->Profile(ID); + } + + void Profile(llvm::FoldingSetNodeID &id) { + id = ID; + } + + llvm::FoldingSetNodeID &getID() { return ID; } +}; +} + +static bool IsCachedDiagnostic(BugReport *R, PathDiagnostic *PD) { + // FIXME: Eventually this diagnostic cache should reside in something + // like AnalysisManager instead of being a static variable. This is + // really unsafe in the long term. + typedef llvm::FoldingSet DiagnosticCache; + static DiagnosticCache DC; + + void *InsertPos; + DiagCacheItem *Item = new DiagCacheItem(R, PD); + + if (DC.FindNodeOrInsertPos(Item->getID(), InsertPos)) { + delete Item; + return true; + } + + DC.InsertNode(Item, InsertPos); + return false; +} + void BugReporter::FlushReport(BugReportEquivClass& EQ) { - assert(!EQ.Reports.empty()); - BugReport &R = **EQ.begin(); - PathDiagnosticClient* PD = getPathDiagnosticClient(); + BugReport *R = FindReportInEquivalenceClass(EQ); + + if (!R) + return; + PathDiagnosticClient* PD = getPathDiagnosticClient(); + // FIXME: Make sure we use the 'R' for the path that was actually used. - // Probably doesn't make a difference in practice. - BugType& BT = R.getBugType(); - + // Probably doesn't make a difference in practice. + BugType& BT = R->getBugType(); + llvm::OwningPtr - D(new PathDiagnostic(R.getBugType().getName(), + D(new PathDiagnostic(R->getBugType().getName(), !PD || PD->useVerboseDescription() - ? R.getDescription() : R.getShortDescription(), + ? R->getDescription() : R->getShortDescription(), BT.getCategory())); GeneratePathDiagnostic(*D.get(), EQ); + + if (IsCachedDiagnostic(R, D.get())) + return; // Get the meta data. - std::pair Meta = R.getExtraDescriptiveText(); - for (const char** s = Meta.first; s != Meta.second; ++s) D->addMeta(*s); + std::pair Meta = R->getExtraDescriptiveText(); + for (const char** s = Meta.first; s != Meta.second; ++s) + D->addMeta(*s); // Emit a summary diagnostic to the regular Diagnostics engine. const SourceRange *Beg = 0, *End = 0; - R.getRanges(*this, Beg, End); + R->getRanges(Beg, End); Diagnostic& Diag = getDiagnostic(); - FullSourceLoc L(R.getLocation(), getSourceManager()); + FullSourceLoc L(R->getLocation(), getSourceManager()); unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, - R.getShortDescription().c_str()); + R->getShortDescription().c_str()); switch (End-Beg) { default: assert(0 && "Don't handle this many ranges yet!"); @@ -1665,15 +1823,15 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) { // Emit a full diagnostic for the path if we have a PathDiagnosticClient. if (!PD) return; - - if (D->empty()) { + + if (D->empty()) { PathDiagnosticPiece* piece = - new PathDiagnosticEventPiece(L, R.getDescription()); + new PathDiagnosticEventPiece(L, R->getDescription()); for ( ; Beg != End; ++Beg) piece->addRange(*Beg); D->push_back(piece); } - + PD->HandlePathDiagnostic(D.take()); } @@ -1686,7 +1844,7 @@ void BugReporter::EmitBasicReport(const char* name, const char* str, void BugReporter::EmitBasicReport(const char* name, const char* category, const char* str, SourceLocation Loc, SourceRange* RBeg, unsigned NumRanges) { - + // 'BT' will be owned by BugReporter as soon as we call 'EmitReport'. BugType *BT = new BugType(name, category); FullSourceLoc L = getContext().getFullLoc(Loc); diff --git a/lib/Analysis/BugReporterVisitors.cpp b/lib/Analysis/BugReporterVisitors.cpp new file mode 100644 index 000000000000..89c9ca10ec57 --- /dev/null +++ b/lib/Analysis/BugReporterVisitors.cpp @@ -0,0 +1,349 @@ +// BugReporterVisitors.cpp - Helpers for reporting bugs -----------*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a set of BugReporter "visitors" which can be used to +// enhance the diagnostics reported for a bug. +// +//===----------------------------------------------------------------------===// + +#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" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Utility functions. +//===----------------------------------------------------------------------===// + +const Stmt *clang::bugreporter::GetDerefExpr(const ExplodedNode *N) { + // Pattern match for a few useful cases (do something smarter later): + // a[0], p->f, *p + const Stmt *S = N->getLocationAs()->getStmt(); + + if (const UnaryOperator *U = dyn_cast(S)) { + if (U->getOpcode() == UnaryOperator::Deref) + return U->getSubExpr()->IgnoreParenCasts(); + } + else if (const MemberExpr *ME = dyn_cast(S)) { + return ME->getBase()->IgnoreParenCasts(); + } + else if (const ArraySubscriptExpr *AE = dyn_cast(S)) { + // Retrieve the base for arrays since BasicStoreManager doesn't know how + // to reason about them. + return AE->getBase(); + } + + return NULL; +} + +const Stmt* +clang::bugreporter::GetReceiverExpr(const ExplodedNode *N){ + const Stmt *S = N->getLocationAs()->getStmt(); + if (const ObjCMessageExpr *ME = dyn_cast(S)) + return ME->getReceiver(); + return NULL; +} + +const Stmt* +clang::bugreporter::GetDenomExpr(const ExplodedNode *N) { + const Stmt *S = N->getLocationAs()->getStmt(); + if (const BinaryOperator *BE = dyn_cast(S)) + return BE->getRHS(); + return NULL; +} + +const Stmt* +clang::bugreporter::GetCalleeExpr(const ExplodedNode *N) { + // Callee is checked as a PreVisit to the CallExpr. + const Stmt *S = N->getLocationAs()->getStmt(); + if (const CallExpr *CE = dyn_cast(S)) + return CE->getCallee(); + return NULL; +} + +const Stmt* +clang::bugreporter::GetRetValExpr(const ExplodedNode *N) { + const Stmt *S = N->getLocationAs()->getStmt(); + if (const ReturnStmt *RS = dyn_cast(S)) + return RS->getRetValue(); + return NULL; +} + +//===----------------------------------------------------------------------===// +// Definitions for bug reporter visitors. +//===----------------------------------------------------------------------===// + +namespace { +class VISIBILITY_HIDDEN FindLastStoreBRVisitor : public BugReporterVisitor { + const MemRegion *R; + SVal V; + bool satisfied; + const ExplodedNode *StoreSite; +public: + FindLastStoreBRVisitor(SVal v, const MemRegion *r) + : R(r), V(v), satisfied(false), StoreSite(0) {} + + PathDiagnosticPiece* VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext& BRC) { + + if (satisfied) + return NULL; + + if (!StoreSite) { + const ExplodedNode *Node = N, *Last = NULL; + + for ( ; Node ; Last = Node, Node = Node->getFirstPred()) { + + if (const VarRegion *VR = dyn_cast(R)) { + if (const PostStmt *P = Node->getLocationAs()) + if (const DeclStmt *DS = P->getStmtAs()) + if (DS->getSingleDecl() == VR->getDecl()) { + Last = Node; + break; + } + } + + if (Node->getState()->getSVal(R) != V) + break; + } + + if (!Node || !Last) { + satisfied = true; + return NULL; + } + + StoreSite = Last; + } + + if (StoreSite != N) + return NULL; + + satisfied = true; + std::string sbuf; + llvm::raw_string_ostream os(sbuf); + + if (const PostStmt *PS = N->getLocationAs()) { + if (const DeclStmt *DS = PS->getStmtAs()) { + + if (const VarRegion *VR = dyn_cast(R)) { + os << "Variable '" << VR->getDecl()->getNameAsString() << "' "; + } + else + return NULL; + + if (isa(V)) { + bool b = false; + ASTContext &C = BRC.getASTContext(); + if (R->isBoundable()) { + if (const TypedRegion *TR = dyn_cast(R)) { + if (TR->getValueType(C)->isObjCObjectPointerType()) { + os << "initialized to nil"; + b = true; + } + } + } + + if (!b) + os << "initialized to a null pointer value"; + } + else if (isa(V)) { + os << "initialized to " << cast(V).getValue(); + } + else if (V.isUndef()) { + if (isa(R)) { + const VarDecl *VD = cast(DS->getSingleDecl()); + if (VD->getInit()) + os << "initialized to a garbage value"; + else + os << "declared without an initial value"; + } + } + } + } + + if (os.str().empty()) { + if (isa(V)) { + bool b = false; + ASTContext &C = BRC.getASTContext(); + if (R->isBoundable()) { + if (const TypedRegion *TR = dyn_cast(R)) { + if (TR->getValueType(C)->isObjCObjectPointerType()) { + os << "nil object reference stored to "; + b = true; + } + } + } + + if (!b) + os << "Null pointer value stored to "; + } + else if (V.isUndef()) { + os << "Uninitialized value stored to "; + } + else if (isa(V)) { + os << "The value " << cast(V).getValue() + << " is assigned to "; + } + else + return NULL; + + if (const VarRegion *VR = dyn_cast(R)) { + os << '\'' << VR->getDecl()->getNameAsString() << '\''; + } + else + return NULL; + } + + // FIXME: Refactor this into BugReporterContext. + const Stmt *S = 0; + ProgramPoint P = N->getLocation(); + + if (BlockEdge *BE = dyn_cast(&P)) { + CFGBlock *BSrc = BE->getSrc(); + S = BSrc->getTerminatorCondition(); + } + else if (PostStmt *PS = dyn_cast(&P)) { + S = PS->getStmt(); + } + + if (!S) + return NULL; + + // Construct a new PathDiagnosticPiece. + PathDiagnosticLocation L(S, BRC.getSourceManager()); + return new PathDiagnosticEventPiece(L, os.str()); + } +}; + + +static void registerFindLastStore(BugReporterContext& BRC, const MemRegion *R, + SVal V) { + BRC.addVisitor(new FindLastStoreBRVisitor(V, R)); +} + +class VISIBILITY_HIDDEN TrackConstraintBRVisitor : public BugReporterVisitor { + DefinedSVal Constraint; + const bool Assumption; + bool isSatisfied; +public: + TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption) + : Constraint(constraint), Assumption(assumption), isSatisfied(false) {} + + PathDiagnosticPiece* VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext& BRC) { + if (isSatisfied) + return NULL; + + // Check if in the previous state it was feasible for this constraint + // to *not* be true. + if (PrevN->getState()->Assume(Constraint, !Assumption)) { + + isSatisfied = true; + + // As a sanity check, make sure that the negation of the constraint + // was infeasible in the current state. If it is feasible, we somehow + // missed the transition point. + if (N->getState()->Assume(Constraint, !Assumption)) + return NULL; + + // We found the transition point for the constraint. We now need to + // pretty-print the constraint. (work-in-progress) + std::string sbuf; + llvm::raw_string_ostream os(sbuf); + + if (isa(Constraint)) { + os << "Assuming pointer value is "; + os << (Assumption ? "non-null" : "null"); + } + + if (os.str().empty()) + return NULL; + + // FIXME: Refactor this into BugReporterContext. + const Stmt *S = 0; + ProgramPoint P = N->getLocation(); + + if (BlockEdge *BE = dyn_cast(&P)) { + CFGBlock *BSrc = BE->getSrc(); + S = BSrc->getTerminatorCondition(); + } + else if (PostStmt *PS = dyn_cast(&P)) { + S = PS->getStmt(); + } + + if (!S) + return NULL; + + // Construct a new PathDiagnosticPiece. + PathDiagnosticLocation L(S, BRC.getSourceManager()); + return new PathDiagnosticEventPiece(L, os.str()); + } + + return NULL; + } +}; +} // end anonymous namespace + +static void registerTrackConstraint(BugReporterContext& BRC, + DefinedSVal Constraint, + bool Assumption) { + BRC.addVisitor(new TrackConstraintBRVisitor(Constraint, Assumption)); +} + +void clang::bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC, + const void *data, + const ExplodedNode* N) { + + const Stmt *S = static_cast(data); + + if (!S) + return; + + GRStateManager &StateMgr = BRC.getStateManager(); + const GRState *state = N->getState(); + + if (const DeclRefExpr *DR = dyn_cast(S)) { + if (const VarDecl *VD = dyn_cast(DR->getDecl())) { + const VarRegion *R = + StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext()); + + // What did we load? + SVal V = state->getSVal(S); + + if (isa(V) || isa(V) + || V.isUndef()) { + registerFindLastStore(BRC, R, V); + } + } + } + + SVal V = state->getSValAsScalarOrLoc(S); + + // Uncomment this to find cases where we aren't properly getting the + // base value that was dereferenced. + // assert(!V.isUnknownOrUndef()); + + // Is it a symbolic value? + if (loc::MemRegionVal *L = dyn_cast(&V)) { + const SubRegion *R = cast(L->getRegion()); + while (R && !isa(R)) { + R = dyn_cast(R->getSuperRegion()); + } + + if (R) { + assert(isa(R)); + registerTrackConstraint(BRC, loc::MemRegionVal(R), false); + } + } +} diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp new file mode 100644 index 000000000000..7b1d50cb3aee --- /dev/null +++ b/lib/Analysis/CFG.cpp @@ -0,0 +1,2084 @@ +//===--- CFG.cpp - Classes for representing and building CFGs----*- 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 CFG and CFGBuilder classes for representing and +// building Control-Flow Graphs (CFGs) from ASTs. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Support/SaveAndRestore.h" +#include "clang/Analysis/CFG.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/PrettyPrinter.h" +#include "llvm/Support/GraphWriter.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Format.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" + +using namespace clang; + +namespace { + +static SourceLocation GetEndLoc(Decl* D) { + if (VarDecl* VD = dyn_cast(D)) + if (Expr* Ex = VD->getInit()) + return Ex->getSourceRange().getEnd(); + + return D->getLocation(); +} + +/// CFGBuilder - This class implements CFG construction from an AST. +/// The builder is stateful: an instance of the builder should be used to only +/// construct a single CFG. +/// +/// Example usage: +/// +/// CFGBuilder builder; +/// CFG* cfg = builder.BuildAST(stmt1); +/// +/// CFG construction is done via a recursive walk of an AST. We actually parse +/// the AST in reverse order so that the successor of a basic block is +/// constructed prior to its predecessor. This allows us to nicely capture +/// implicit fall-throughs without extra basic blocks. +/// +class VISIBILITY_HIDDEN CFGBuilder { + ASTContext *Context; + CFG* cfg; + + CFGBlock* Block; + CFGBlock* Succ; + CFGBlock* ContinueTargetBlock; + CFGBlock* BreakTargetBlock; + CFGBlock* SwitchTerminatedBlock; + CFGBlock* DefaultCaseBlock; + + // LabelMap records the mapping from Label expressions to their blocks. + typedef llvm::DenseMap LabelMapTy; + LabelMapTy LabelMap; + + // A list of blocks that end with a "goto" that must be backpatched to their + // resolved targets upon completion of CFG construction. + typedef std::vector BackpatchBlocksTy; + BackpatchBlocksTy BackpatchBlocks; + + // A list of labels whose address has been taken (for indirect gotos). + typedef llvm::SmallPtrSet LabelSetTy; + LabelSetTy AddressTakenLabels; + +public: + explicit CFGBuilder() : cfg(new CFG()), // crew a new CFG + Block(NULL), Succ(NULL), + ContinueTargetBlock(NULL), BreakTargetBlock(NULL), + SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) {} + + ~CFGBuilder() { delete cfg; } + + // buildCFG - Used by external clients to construct the CFG. + CFG* buildCFG(Stmt *Statement, ASTContext *C); + +private: + // Visitors to walk an AST and construct the CFG. + CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, bool alwaysAdd); + CFGBlock *VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd); + CFGBlock *VisitBlockExpr(BlockExpr* E, bool alwaysAdd); + CFGBlock *VisitBlockDeclRefExpr(BlockDeclRefExpr* E, bool alwaysAdd); + CFGBlock *VisitBreakStmt(BreakStmt *B); + CFGBlock *VisitCallExpr(CallExpr *C, bool alwaysAdd); + CFGBlock *VisitCaseStmt(CaseStmt *C); + CFGBlock *VisitChooseExpr(ChooseExpr *C); + CFGBlock *VisitCompoundStmt(CompoundStmt *C); + CFGBlock *VisitConditionalOperator(ConditionalOperator *C); + CFGBlock *VisitContinueStmt(ContinueStmt *C); + CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); + CFGBlock *VisitDeclStmt(DeclStmt *DS); + CFGBlock *VisitDeclSubExpr(Decl* D); + CFGBlock *VisitDefaultStmt(DefaultStmt *D); + CFGBlock *VisitDoStmt(DoStmt *D); + CFGBlock *VisitForStmt(ForStmt *F); + CFGBlock *VisitGotoStmt(GotoStmt* G); + CFGBlock *VisitIfStmt(IfStmt *I); + CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I); + CFGBlock *VisitLabelStmt(LabelStmt *L); + CFGBlock *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S); + CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S); + CFGBlock *VisitObjCAtThrowStmt(ObjCAtThrowStmt *S); + CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S); + CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S); + CFGBlock *VisitReturnStmt(ReturnStmt* R); + CFGBlock *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, bool alwaysAdd); + CFGBlock *VisitStmtExpr(StmtExpr *S, bool alwaysAdd); + CFGBlock *VisitSwitchStmt(SwitchStmt *S); + CFGBlock *VisitWhileStmt(WhileStmt *W); + + CFGBlock *Visit(Stmt *S, bool alwaysAdd = false); + CFGBlock *VisitStmt(Stmt *S, bool alwaysAdd); + CFGBlock *VisitChildren(Stmt* S); + + // NYS == Not Yet Supported + CFGBlock* NYS() { + badCFG = true; + return Block; + } + + void autoCreateBlock() { if (!Block) Block = createBlock(); } + CFGBlock *createBlock(bool add_successor = true); + bool FinishBlock(CFGBlock* B); + CFGBlock *addStmt(Stmt *S) { return Visit(S, true); } + + void AppendStmt(CFGBlock *B, Stmt *S) { + B->appendStmt(S, cfg->getBumpVectorContext()); + } + + void AddSuccessor(CFGBlock *B, CFGBlock *S) { + B->addSuccessor(S, cfg->getBumpVectorContext()); + } + + /// TryResult - a class representing a variant over the values + /// 'true', 'false', or 'unknown'. This is returned by TryEvaluateBool, + /// and is used by the CFGBuilder to decide if a branch condition + /// can be decided up front during CFG construction. + class TryResult { + int X; + public: + TryResult(bool b) : X(b ? 1 : 0) {} + TryResult() : X(-1) {} + + bool isTrue() const { return X == 1; } + bool isFalse() const { return X == 0; } + bool isKnown() const { return X >= 0; } + void negate() { + assert(isKnown()); + X ^= 0x1; + } + }; + + /// TryEvaluateBool - Try and evaluate the Stmt and return 0 or 1 + /// if we can evaluate to a known value, otherwise return -1. + TryResult TryEvaluateBool(Expr *S) { + Expr::EvalResult Result; + if (!S->isTypeDependent() && !S->isValueDependent() && + S->Evaluate(Result, *Context) && Result.Val.isInt()) + return Result.Val.getInt().getBoolValue(); + + return TryResult(); + } + + bool badCFG; +}; + +// FIXME: Add support for dependent-sized array types in C++? +// Does it even make sense to build a CFG for an uninstantiated template? +static VariableArrayType* FindVA(Type* t) { + while (ArrayType* vt = dyn_cast(t)) { + if (VariableArrayType* vat = dyn_cast(vt)) + if (vat->getSizeExpr()) + return vat; + + t = vt->getElementType().getTypePtr(); + } + + return 0; +} + +/// BuildCFG - Constructs a CFG from an AST (a Stmt*). The AST can represent an +/// arbitrary statement. Examples include a single expression or a function +/// body (compound statement). The ownership of the returned CFG is +/// transferred to the caller. If CFG construction fails, this method returns +/// NULL. +CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C) { + Context = C; + assert(cfg); + if (!Statement) + return NULL; + + badCFG = false; + + // Create an empty block that will serve as the exit block for the CFG. Since + // this is the first block added to the CFG, it will be implicitly registered + // as the exit block. + Succ = createBlock(); + assert(Succ == &cfg->getExit()); + Block = NULL; // the EXIT block is empty. Create all other blocks lazily. + + // Visit the statements and create the CFG. + CFGBlock* B = addStmt(Statement); + if (!B) B = Succ; + + if (B) { + // Finalize the last constructed block. This usually involves reversing the + // order of the statements in the block. + if (Block) FinishBlock(B); + + // Backpatch the gotos whose label -> block mappings we didn't know when we + // encountered them. + for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(), + E = BackpatchBlocks.end(); I != E; ++I ) { + + CFGBlock* B = *I; + GotoStmt* G = cast(B->getTerminator()); + LabelMapTy::iterator LI = LabelMap.find(G->getLabel()); + + // If there is no target for the goto, then we are looking at an + // incomplete AST. Handle this by not registering a successor. + if (LI == LabelMap.end()) continue; + + AddSuccessor(B, LI->second); + } + + // Add successors to the Indirect Goto Dispatch block (if we have one). + if (CFGBlock* B = cfg->getIndirectGotoBlock()) + for (LabelSetTy::iterator I = AddressTakenLabels.begin(), + E = AddressTakenLabels.end(); I != E; ++I ) { + + // Lookup the target block. + LabelMapTy::iterator LI = LabelMap.find(*I); + + // If there is no target block that contains label, then we are looking + // at an incomplete AST. Handle this by not registering a successor. + if (LI == LabelMap.end()) continue; + + AddSuccessor(B, LI->second); + } + + Succ = B; + } + + // Create an empty entry block that has no predecessors. + cfg->setEntry(createBlock()); + + if (badCFG) { + delete cfg; + cfg = NULL; + return NULL; + } + + // NULL out cfg so that repeated calls to the builder will fail and that the + // ownership of the constructed CFG is passed to the caller. + CFG* t = cfg; + cfg = NULL; + return t; +} + +/// createBlock - Used to lazily create blocks that are connected +/// to the current (global) succcessor. +CFGBlock* CFGBuilder::createBlock(bool add_successor) { + CFGBlock* B = cfg->createBlock(); + if (add_successor && Succ) + AddSuccessor(B, Succ); + return B; +} + +/// FinishBlock - "Finalize" the block by checking if we have a bad CFG. +bool CFGBuilder::FinishBlock(CFGBlock* B) { + if (badCFG) + return false; + + assert(B); + return true; +} + +/// Visit - Walk the subtree of a statement and add extra +/// blocks for ternary operators, &&, and ||. We also process "," and +/// DeclStmts (which may contain nested control-flow). +CFGBlock* CFGBuilder::Visit(Stmt * S, bool alwaysAdd) { +tryAgain: + switch (S->getStmtClass()) { + default: + return VisitStmt(S, alwaysAdd); + + case Stmt::AddrLabelExprClass: + return VisitAddrLabelExpr(cast(S), alwaysAdd); + + case Stmt::BinaryOperatorClass: + return VisitBinaryOperator(cast(S), alwaysAdd); + + case Stmt::BlockExprClass: + return VisitBlockExpr(cast(S), alwaysAdd); + + case Stmt::BlockDeclRefExprClass: + return VisitBlockDeclRefExpr(cast(S), alwaysAdd); + + case Stmt::BreakStmtClass: + return VisitBreakStmt(cast(S)); + + case Stmt::CallExprClass: + return VisitCallExpr(cast(S), alwaysAdd); + + case Stmt::CaseStmtClass: + return VisitCaseStmt(cast(S)); + + case Stmt::ChooseExprClass: + return VisitChooseExpr(cast(S)); + + case Stmt::CompoundStmtClass: + return VisitCompoundStmt(cast(S)); + + case Stmt::ConditionalOperatorClass: + return VisitConditionalOperator(cast(S)); + + case Stmt::ContinueStmtClass: + return VisitContinueStmt(cast(S)); + + case Stmt::DeclStmtClass: + return VisitDeclStmt(cast(S)); + + case Stmt::DefaultStmtClass: + return VisitDefaultStmt(cast(S)); + + case Stmt::DoStmtClass: + return VisitDoStmt(cast(S)); + + case Stmt::ForStmtClass: + return VisitForStmt(cast(S)); + + case Stmt::GotoStmtClass: + return VisitGotoStmt(cast(S)); + + case Stmt::IfStmtClass: + return VisitIfStmt(cast(S)); + + case Stmt::IndirectGotoStmtClass: + return VisitIndirectGotoStmt(cast(S)); + + case Stmt::LabelStmtClass: + return VisitLabelStmt(cast(S)); + + case Stmt::ObjCAtCatchStmtClass: + return VisitObjCAtCatchStmt(cast(S)); + + case Stmt::CXXThrowExprClass: + return VisitCXXThrowExpr(cast(S)); + + case Stmt::ObjCAtSynchronizedStmtClass: + return VisitObjCAtSynchronizedStmt(cast(S)); + + case Stmt::ObjCAtThrowStmtClass: + return VisitObjCAtThrowStmt(cast(S)); + + case Stmt::ObjCAtTryStmtClass: + return VisitObjCAtTryStmt(cast(S)); + + case Stmt::ObjCForCollectionStmtClass: + return VisitObjCForCollectionStmt(cast(S)); + + case Stmt::ParenExprClass: + S = cast(S)->getSubExpr(); + goto tryAgain; + + case Stmt::NullStmtClass: + return Block; + + case Stmt::ReturnStmtClass: + return VisitReturnStmt(cast(S)); + + case Stmt::SizeOfAlignOfExprClass: + return VisitSizeOfAlignOfExpr(cast(S), alwaysAdd); + + case Stmt::StmtExprClass: + return VisitStmtExpr(cast(S), alwaysAdd); + + case Stmt::SwitchStmtClass: + return VisitSwitchStmt(cast(S)); + + case Stmt::WhileStmtClass: + return VisitWhileStmt(cast(S)); + } +} + +CFGBlock *CFGBuilder::VisitStmt(Stmt *S, bool alwaysAdd) { + if (alwaysAdd) { + autoCreateBlock(); + AppendStmt(Block, S); + } + + return VisitChildren(S); +} + +/// VisitChildren - Visit the children of a Stmt. +CFGBlock *CFGBuilder::VisitChildren(Stmt* Terminator) { + CFGBlock *B = Block; + for (Stmt::child_iterator I = Terminator->child_begin(), + E = Terminator->child_end(); I != E; ++I) { + if (*I) B = Visit(*I); + } + return B; +} + +CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A, bool alwaysAdd) { + AddressTakenLabels.insert(A->getLabel()); + + if (alwaysAdd) { + autoCreateBlock(); + AppendStmt(Block, A); + } + + return Block; +} + +CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd) { + if (B->isLogicalOp()) { // && or || + CFGBlock* ConfluenceBlock = Block ? Block : createBlock(); + AppendStmt(ConfluenceBlock, B); + + if (!FinishBlock(ConfluenceBlock)) + return 0; + + // create the block evaluating the LHS + CFGBlock* LHSBlock = createBlock(false); + LHSBlock->setTerminator(B); + + // create the block evaluating the RHS + Succ = ConfluenceBlock; + Block = NULL; + CFGBlock* RHSBlock = addStmt(B->getRHS()); + if (!FinishBlock(RHSBlock)) + return 0; + + // See if this is a known constant. + TryResult KnownVal = TryEvaluateBool(B->getLHS()); + if (KnownVal.isKnown() && (B->getOpcode() == BinaryOperator::LOr)) + KnownVal.negate(); + + // Now link the LHSBlock with RHSBlock. + if (B->getOpcode() == BinaryOperator::LOr) { + AddSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock); + AddSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock); + } else { + assert (B->getOpcode() == BinaryOperator::LAnd); + AddSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock); + AddSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock); + } + + // Generate the blocks for evaluating the LHS. + Block = LHSBlock; + return addStmt(B->getLHS()); + } + else if (B->getOpcode() == BinaryOperator::Comma) { // , + autoCreateBlock(); + AppendStmt(Block, B); + addStmt(B->getRHS()); + return addStmt(B->getLHS()); + } + + return VisitStmt(B, alwaysAdd); +} + +CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr* E, bool alwaysAdd) { + // FIXME + return NYS(); +} + +CFGBlock *CFGBuilder::VisitBlockDeclRefExpr(BlockDeclRefExpr* E, + bool alwaysAdd) { + // FIXME + return NYS(); +} + +CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) { + // "break" is a control-flow statement. Thus we stop processing the current + // block. + if (Block && !FinishBlock(Block)) + return 0; + + // Now create a new block that ends with the break statement. + Block = createBlock(false); + Block->setTerminator(B); + + // If there is no target for the break, then we are looking at an incomplete + // AST. This means that the CFG cannot be constructed. + if (BreakTargetBlock) + AddSuccessor(Block, BreakTargetBlock); + else + badCFG = true; + + + return Block; +} + +CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, bool alwaysAdd) { + // If this is a call to a no-return function, this stops the block here. + bool NoReturn = false; + if (C->getCallee()->getType().getNoReturnAttr()) { + NoReturn = true; + } + + if (FunctionDecl *FD = C->getDirectCallee()) + if (FD->hasAttr()) + NoReturn = true; + + if (!NoReturn) + return VisitStmt(C, alwaysAdd); + + if (Block && !FinishBlock(Block)) + return 0; + + // Create new block with no successor for the remaining pieces. + Block = createBlock(false); + AppendStmt(Block, C); + + // Wire this to the exit block directly. + AddSuccessor(Block, &cfg->getExit()); + + return VisitChildren(C); +} + +CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C) { + CFGBlock* ConfluenceBlock = Block ? Block : createBlock(); + AppendStmt(ConfluenceBlock, C); + if (!FinishBlock(ConfluenceBlock)) + return 0; + + Succ = ConfluenceBlock; + Block = NULL; + CFGBlock* LHSBlock = addStmt(C->getLHS()); + if (!FinishBlock(LHSBlock)) + return 0; + + Succ = ConfluenceBlock; + Block = NULL; + CFGBlock* RHSBlock = addStmt(C->getRHS()); + if (!FinishBlock(RHSBlock)) + return 0; + + Block = createBlock(false); + // See if this is a known constant. + const TryResult& KnownVal = TryEvaluateBool(C->getCond()); + AddSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock); + AddSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock); + Block->setTerminator(C); + return addStmt(C->getCond()); +} + + +CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) { + CFGBlock* LastBlock = Block; + + for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend(); + I != E; ++I ) { + LastBlock = addStmt(*I); + + if (badCFG) + return NULL; + } + return LastBlock; +} + +CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C) { + // Create the confluence block that will "merge" the results of the ternary + // expression. + CFGBlock* ConfluenceBlock = Block ? Block : createBlock(); + AppendStmt(ConfluenceBlock, C); + if (!FinishBlock(ConfluenceBlock)) + return 0; + + // Create a block for the LHS expression if there is an LHS expression. A + // GCC extension allows LHS to be NULL, causing the condition to be the + // value that is returned instead. + // e.g: x ?: y is shorthand for: x ? x : y; + Succ = ConfluenceBlock; + Block = NULL; + CFGBlock* LHSBlock = NULL; + if (C->getLHS()) { + LHSBlock = addStmt(C->getLHS()); + if (!FinishBlock(LHSBlock)) + return 0; + Block = NULL; + } + + // Create the block for the RHS expression. + Succ = ConfluenceBlock; + CFGBlock* RHSBlock = addStmt(C->getRHS()); + if (!FinishBlock(RHSBlock)) + return 0; + + // Create the block that will contain the condition. + Block = createBlock(false); + + // See if this is a known constant. + const TryResult& KnownVal = TryEvaluateBool(C->getCond()); + if (LHSBlock) { + AddSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock); + } else { + if (KnownVal.isFalse()) { + // If we know the condition is false, add NULL as the successor for + // the block containing the condition. In this case, the confluence + // block will have just one predecessor. + AddSuccessor(Block, 0); + assert(ConfluenceBlock->pred_size() == 1); + } else { + // If we have no LHS expression, add the ConfluenceBlock as a direct + // successor for the block containing the condition. Moreover, we need to + // reverse the order of the predecessors in the ConfluenceBlock because + // the RHSBlock will have been added to the succcessors already, and we + // want the first predecessor to the the block containing the expression + // for the case when the ternary expression evaluates to true. + AddSuccessor(Block, ConfluenceBlock); + assert(ConfluenceBlock->pred_size() == 2); + std::reverse(ConfluenceBlock->pred_begin(), + ConfluenceBlock->pred_end()); + } + } + + AddSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock); + Block->setTerminator(C); + return addStmt(C->getCond()); +} + +CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) { + autoCreateBlock(); + + if (DS->isSingleDecl()) { + AppendStmt(Block, DS); + return VisitDeclSubExpr(DS->getSingleDecl()); + } + + CFGBlock *B = 0; + + // FIXME: Add a reverse iterator for DeclStmt to avoid this extra copy. + typedef llvm::SmallVector BufTy; + BufTy Buf(DS->decl_begin(), DS->decl_end()); + + for (BufTy::reverse_iterator I = Buf.rbegin(), E = Buf.rend(); I != E; ++I) { + // Get the alignment of the new DeclStmt, padding out to >=8 bytes. + unsigned A = llvm::AlignOf::Alignment < 8 + ? 8 : llvm::AlignOf::Alignment; + + // Allocate the DeclStmt using the BumpPtrAllocator. It will get + // automatically freed with the CFG. + DeclGroupRef DG(*I); + Decl *D = *I; + void *Mem = cfg->getAllocator().Allocate(sizeof(DeclStmt), A); + DeclStmt *DSNew = new (Mem) DeclStmt(DG, D->getLocation(), GetEndLoc(D)); + + // Append the fake DeclStmt to block. + AppendStmt(Block, DSNew); + B = VisitDeclSubExpr(D); + } + + return B; +} + +/// VisitDeclSubExpr - Utility method to add block-level expressions for +/// initializers in Decls. +CFGBlock *CFGBuilder::VisitDeclSubExpr(Decl* D) { + assert(Block); + + VarDecl *VD = dyn_cast(D); + + if (!VD) + return Block; + + Expr *Init = VD->getInit(); + + if (Init) { + // Optimization: Don't create separate block-level statements for literals. + switch (Init->getStmtClass()) { + case Stmt::IntegerLiteralClass: + case Stmt::CharacterLiteralClass: + case Stmt::StringLiteralClass: + break; + default: + Block = addStmt(Init); + } + } + + // If the type of VD is a VLA, then we must process its size expressions. + for (VariableArrayType* VA = FindVA(VD->getType().getTypePtr()); VA != 0; + VA = FindVA(VA->getElementType().getTypePtr())) + Block = addStmt(VA->getSizeExpr()); + + return Block; +} + +CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { + // We may see an if statement in the middle of a basic block, or it may be the + // first statement we are processing. In either case, we create a new basic + // block. First, we create the blocks for the then...else statements, and + // then we create the block containing the if statement. If we were in the + // middle of a block, we stop processing that block. That block is then the + // implicit successor for the "then" and "else" clauses. + + // The block we were proccessing is now finished. Make it the successor + // block. + if (Block) { + Succ = Block; + if (!FinishBlock(Block)) + return 0; + } + + // Process the false branch. + CFGBlock* ElseBlock = Succ; + + if (Stmt* Else = I->getElse()) { + SaveAndRestore sv(Succ); + + // NULL out Block so that the recursive call to Visit will + // create a new basic block. + Block = NULL; + ElseBlock = addStmt(Else); + + if (!ElseBlock) // Can occur when the Else body has all NullStmts. + ElseBlock = sv.get(); + else if (Block) { + if (!FinishBlock(ElseBlock)) + return 0; + } + } + + // Process the true branch. + CFGBlock* ThenBlock; + { + Stmt* Then = I->getThen(); + assert (Then); + SaveAndRestore sv(Succ); + Block = NULL; + ThenBlock = addStmt(Then); + + if (!ThenBlock) { + // We can reach here if the "then" body has all NullStmts. + // Create an empty block so we can distinguish between true and false + // branches in path-sensitive analyses. + ThenBlock = createBlock(false); + AddSuccessor(ThenBlock, sv.get()); + } else if (Block) { + if (!FinishBlock(ThenBlock)) + return 0; + } + } + + // Now create a new block containing the if statement. + Block = createBlock(false); + + // Set the terminator of the new block to the If statement. + Block->setTerminator(I); + + // See if this is a known constant. + const TryResult &KnownVal = TryEvaluateBool(I->getCond()); + + // Now add the successors. + AddSuccessor(Block, KnownVal.isFalse() ? NULL : ThenBlock); + AddSuccessor(Block, KnownVal.isTrue()? NULL : ElseBlock); + + // Add the condition as the last statement in the new block. This may create + // new blocks as the condition may contain control-flow. Any newly created + // blocks will be pointed to be "Block". + return addStmt(I->getCond()); +} + + +CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) { + // If we were in the middle of a block we stop processing that block. + // + // NOTE: If a "return" appears in the middle of a block, this means that the + // code afterwards is DEAD (unreachable). We still keep a basic block + // for that code; a simple "mark-and-sweep" from the entry block will be + // able to report such dead blocks. + if (Block) + FinishBlock(Block); + + // Create the new block. + Block = createBlock(false); + + // The Exit block is the only successor. + AddSuccessor(Block, &cfg->getExit()); + + // Add the return statement to the block. This may create new blocks if R + // contains control-flow (short-circuit operations). + return VisitStmt(R, true); +} + +CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt* L) { + // Get the block of the labeled statement. Add it to our map. + addStmt(L->getSubStmt()); + CFGBlock* LabelBlock = Block; + + if (!LabelBlock) // This can happen when the body is empty, i.e. + LabelBlock = createBlock(); // scopes that only contains NullStmts. + + assert(LabelMap.find(L) == LabelMap.end() && "label already in map"); + LabelMap[ L ] = LabelBlock; + + // Labels partition blocks, so this is the end of the basic block we were + // processing (L is the block's label). Because this is label (and we have + // already processed the substatement) there is no extra control-flow to worry + // about. + LabelBlock->setLabel(L); + if (!FinishBlock(LabelBlock)) + return 0; + + // We set Block to NULL to allow lazy creation of a new block (if necessary); + Block = NULL; + + // This block is now the implicit successor of other blocks. + Succ = LabelBlock; + + return LabelBlock; +} + +CFGBlock* CFGBuilder::VisitGotoStmt(GotoStmt* G) { + // Goto is a control-flow statement. Thus we stop processing the current + // block and create a new one. + if (Block) + FinishBlock(Block); + + Block = createBlock(false); + Block->setTerminator(G); + + // If we already know the mapping to the label block add the successor now. + LabelMapTy::iterator I = LabelMap.find(G->getLabel()); + + if (I == LabelMap.end()) + // We will need to backpatch this block later. + BackpatchBlocks.push_back(Block); + else + AddSuccessor(Block, I->second); + + return Block; +} + +CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { + CFGBlock* LoopSuccessor = NULL; + + // "for" is a control-flow statement. Thus we stop processing the current + // block. + if (Block) { + if (!FinishBlock(Block)) + return 0; + LoopSuccessor = Block; + } else + LoopSuccessor = Succ; + + // Because of short-circuit evaluation, the condition of the loop can span + // multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that + // evaluate the condition. + CFGBlock* ExitConditionBlock = createBlock(false); + CFGBlock* EntryConditionBlock = ExitConditionBlock; + + // Set the terminator for the "exit" condition block. + ExitConditionBlock->setTerminator(F); + + // Now add the actual condition to the condition block. Because the condition + // itself may contain control-flow, new blocks may be created. + if (Stmt* C = F->getCond()) { + Block = ExitConditionBlock; + EntryConditionBlock = addStmt(C); + if (Block) { + if (!FinishBlock(EntryConditionBlock)) + return 0; + } + } + + // The condition block is the implicit successor for the loop body as well as + // any code above the loop. + Succ = EntryConditionBlock; + + // See if this is a known constant. + TryResult KnownVal(true); + + if (F->getCond()) + KnownVal = TryEvaluateBool(F->getCond()); + + // Now create the loop body. + { + assert (F->getBody()); + + // Save the current values for Block, Succ, and continue and break targets + SaveAndRestore save_Block(Block), save_Succ(Succ), + save_continue(ContinueTargetBlock), + save_break(BreakTargetBlock); + + // Create a new block to contain the (bottom) of the loop body. + Block = NULL; + + if (Stmt* I = F->getInc()) { + // Generate increment code in its own basic block. This is the target of + // continue statements. + Succ = addStmt(I); + } else { + // No increment code. Create a special, empty, block that is used as the + // target block for "looping back" to the start of the loop. + assert(Succ == EntryConditionBlock); + Succ = createBlock(); + } + + // Finish up the increment (or empty) block if it hasn't been already. + if (Block) { + assert(Block == Succ); + if (!FinishBlock(Block)) + return 0; + Block = 0; + } + + ContinueTargetBlock = Succ; + + // The starting block for the loop increment is the block that should + // represent the 'loop target' for looping back to the start of the loop. + ContinueTargetBlock->setLoopTarget(F); + + // All breaks should go to the code following the loop. + BreakTargetBlock = LoopSuccessor; + + // Now populate the body block, and in the process create new blocks as we + // walk the body of the loop. + CFGBlock* BodyBlock = addStmt(F->getBody()); + + if (!BodyBlock) + BodyBlock = ContinueTargetBlock; // can happen for "for (...;...;...) ;" + else if (Block && !FinishBlock(BodyBlock)) + return 0; + + // This new body block is a successor to our "exit" condition block. + AddSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : BodyBlock); + } + + // Link up the condition block with the code that follows the loop. (the + // false branch). + AddSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor); + + // If the loop contains initialization, create a new block for those + // statements. This block can also contain statements that precede the loop. + if (Stmt* I = F->getInit()) { + Block = createBlock(); + return addStmt(I); + } else { + // There is no loop initialization. We are thus basically a while loop. + // NULL out Block to force lazy block construction. + Block = NULL; + Succ = EntryConditionBlock; + return EntryConditionBlock; + } +} + +CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { + // Objective-C fast enumeration 'for' statements: + // http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC + // + // for ( Type newVariable in collection_expression ) { statements } + // + // becomes: + // + // prologue: + // 1. collection_expression + // T. jump to loop_entry + // loop_entry: + // 1. side-effects of element expression + // 1. ObjCForCollectionStmt [performs binding to newVariable] + // T. ObjCForCollectionStmt TB, FB [jumps to TB if newVariable != nil] + // TB: + // statements + // T. jump to loop_entry + // FB: + // what comes after + // + // and + // + // Type existingItem; + // for ( existingItem in expression ) { statements } + // + // becomes: + // + // the same with newVariable replaced with existingItem; the binding works + // the same except that for one ObjCForCollectionStmt::getElement() returns + // a DeclStmt and the other returns a DeclRefExpr. + // + + CFGBlock* LoopSuccessor = 0; + + if (Block) { + if (!FinishBlock(Block)) + return 0; + LoopSuccessor = Block; + Block = 0; + } else + LoopSuccessor = Succ; + + // Build the condition blocks. + CFGBlock* ExitConditionBlock = createBlock(false); + CFGBlock* EntryConditionBlock = ExitConditionBlock; + + // Set the terminator for the "exit" condition block. + ExitConditionBlock->setTerminator(S); + + // The last statement in the block should be the ObjCForCollectionStmt, which + // performs the actual binding to 'element' and determines if there are any + // more items in the collection. + AppendStmt(ExitConditionBlock, S); + Block = ExitConditionBlock; + + // Walk the 'element' expression to see if there are any side-effects. We + // generate new blocks as necesary. We DON'T add the statement by default to + // the CFG unless it contains control-flow. + EntryConditionBlock = Visit(S->getElement(), false); + if (Block) { + if (!FinishBlock(EntryConditionBlock)) + return 0; + Block = 0; + } + + // The condition block is the implicit successor for the loop body as well as + // any code above the loop. + Succ = EntryConditionBlock; + + // Now create the true branch. + { + // Save the current values for Succ, continue and break targets. + SaveAndRestore save_Succ(Succ), + save_continue(ContinueTargetBlock), save_break(BreakTargetBlock); + + BreakTargetBlock = LoopSuccessor; + ContinueTargetBlock = EntryConditionBlock; + + CFGBlock* BodyBlock = addStmt(S->getBody()); + + if (!BodyBlock) + BodyBlock = EntryConditionBlock; // can happen for "for (X in Y) ;" + else if (Block) { + if (!FinishBlock(BodyBlock)) + return 0; + } + + // This new body block is a successor to our "exit" condition block. + AddSuccessor(ExitConditionBlock, BodyBlock); + } + + // Link up the condition block with the code that follows the loop. + // (the false branch). + AddSuccessor(ExitConditionBlock, LoopSuccessor); + + // Now create a prologue block to contain the collection expression. + Block = createBlock(); + return addStmt(S->getCollection()); +} + +CFGBlock* CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S) { + // FIXME: Add locking 'primitives' to CFG for @synchronized. + + // Inline the body. + CFGBlock *SyncBlock = addStmt(S->getSynchBody()); + + // The sync body starts its own basic block. This makes it a little easier + // for diagnostic clients. + if (SyncBlock) { + if (!FinishBlock(SyncBlock)) + return 0; + + Block = 0; + } + + Succ = SyncBlock; + + // Inline the sync expression. + return addStmt(S->getSynchExpr()); +} + +CFGBlock* CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt* S) { + // FIXME + return NYS(); +} + +CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) { + CFGBlock* LoopSuccessor = NULL; + + // "while" is a control-flow statement. Thus we stop processing the current + // block. + if (Block) { + if (!FinishBlock(Block)) + return 0; + LoopSuccessor = Block; + } else + LoopSuccessor = Succ; + + // Because of short-circuit evaluation, the condition of the loop can span + // multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that + // evaluate the condition. + CFGBlock* ExitConditionBlock = createBlock(false); + CFGBlock* EntryConditionBlock = ExitConditionBlock; + + // Set the terminator for the "exit" condition block. + ExitConditionBlock->setTerminator(W); + + // Now add the actual condition to the condition block. Because the condition + // itself may contain control-flow, new blocks may be created. Thus we update + // "Succ" after adding the condition. + if (Stmt* C = W->getCond()) { + Block = ExitConditionBlock; + EntryConditionBlock = addStmt(C); + assert(Block == EntryConditionBlock); + if (Block) { + if (!FinishBlock(EntryConditionBlock)) + return 0; + } + } + + // The condition block is the implicit successor for the loop body as well as + // any code above the loop. + Succ = EntryConditionBlock; + + // See if this is a known constant. + const TryResult& KnownVal = TryEvaluateBool(W->getCond()); + + // Process the loop body. + { + assert(W->getBody()); + + // Save the current values for Block, Succ, and continue and break targets + SaveAndRestore save_Block(Block), save_Succ(Succ), + save_continue(ContinueTargetBlock), + save_break(BreakTargetBlock); + + // Create an empty block to represent the transition block for looping back + // to the head of the loop. + Block = 0; + assert(Succ == EntryConditionBlock); + Succ = createBlock(); + Succ->setLoopTarget(W); + ContinueTargetBlock = Succ; + + // All breaks should go to the code following the loop. + BreakTargetBlock = LoopSuccessor; + + // NULL out Block to force lazy instantiation of blocks for the body. + Block = NULL; + + // Create the body. The returned block is the entry to the loop body. + CFGBlock* BodyBlock = addStmt(W->getBody()); + + if (!BodyBlock) + BodyBlock = ContinueTargetBlock; // can happen for "while(...) ;" + else if (Block) { + if (!FinishBlock(BodyBlock)) + return 0; + } + + // Add the loop body entry as a successor to the condition. + AddSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : BodyBlock); + } + + // Link up the condition block with the code that follows the loop. (the + // false branch). + AddSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor); + + // There can be no more statements in the condition block since we loop back + // to this block. NULL out Block to force lazy creation of another block. + Block = NULL; + + // Return the condition block, which is the dominating block for the loop. + Succ = EntryConditionBlock; + return EntryConditionBlock; +} + + +CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt* S) { + // FIXME: For now we pretend that @catch and the code it contains does not + // exit. + return Block; +} + +CFGBlock* CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt* S) { + // FIXME: This isn't complete. We basically treat @throw like a return + // statement. + + // If we were in the middle of a block we stop processing that block. + if (Block && !FinishBlock(Block)) + return 0; + + // Create the new block. + Block = createBlock(false); + + // The Exit block is the only successor. + AddSuccessor(Block, &cfg->getExit()); + + // Add the statement to the block. This may create new blocks if S contains + // control-flow (short-circuit operations). + return VisitStmt(S, true); +} + +CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) { + // If we were in the middle of a block we stop processing that block. + if (Block && !FinishBlock(Block)) + return 0; + + // Create the new block. + Block = createBlock(false); + + // The Exit block is the only successor. + AddSuccessor(Block, &cfg->getExit()); + + // Add the statement to the block. This may create new blocks if S contains + // control-flow (short-circuit operations). + return VisitStmt(T, true); +} + +CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) { + CFGBlock* LoopSuccessor = NULL; + + // "do...while" is a control-flow statement. Thus we stop processing the + // current block. + if (Block) { + if (!FinishBlock(Block)) + return 0; + LoopSuccessor = Block; + } else + LoopSuccessor = Succ; + + // Because of short-circuit evaluation, the condition of the loop can span + // multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that + // evaluate the condition. + CFGBlock* ExitConditionBlock = createBlock(false); + CFGBlock* EntryConditionBlock = ExitConditionBlock; + + // Set the terminator for the "exit" condition block. + ExitConditionBlock->setTerminator(D); + + // Now add the actual condition to the condition block. Because the condition + // itself may contain control-flow, new blocks may be created. + if (Stmt* C = D->getCond()) { + Block = ExitConditionBlock; + EntryConditionBlock = addStmt(C); + if (Block) { + if (!FinishBlock(EntryConditionBlock)) + return 0; + } + } + + // The condition block is the implicit successor for the loop body. + Succ = EntryConditionBlock; + + // See if this is a known constant. + const TryResult &KnownVal = TryEvaluateBool(D->getCond()); + + // Process the loop body. + CFGBlock* BodyBlock = NULL; + { + assert (D->getBody()); + + // Save the current values for Block, Succ, and continue and break targets + SaveAndRestore save_Block(Block), save_Succ(Succ), + save_continue(ContinueTargetBlock), + save_break(BreakTargetBlock); + + // All continues within this loop should go to the condition block + ContinueTargetBlock = EntryConditionBlock; + + // All breaks should go to the code following the loop. + BreakTargetBlock = LoopSuccessor; + + // NULL out Block to force lazy instantiation of blocks for the body. + Block = NULL; + + // Create the body. The returned block is the entry to the loop body. + BodyBlock = addStmt(D->getBody()); + + if (!BodyBlock) + BodyBlock = EntryConditionBlock; // can happen for "do ; while(...)" + else if (Block) { + if (!FinishBlock(BodyBlock)) + return 0; + } + + // Add an intermediate block between the BodyBlock and the + // ExitConditionBlock to represent the "loop back" transition. Create an + // empty block to represent the transition block for looping back to the + // head of the loop. + // FIXME: Can we do this more efficiently without adding another block? + Block = NULL; + Succ = BodyBlock; + CFGBlock *LoopBackBlock = createBlock(); + LoopBackBlock->setLoopTarget(D); + + // Add the loop body entry as a successor to the condition. + AddSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : LoopBackBlock); + } + + // Link up the condition block with the code that follows the loop. + // (the false branch). + AddSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor); + + // There can be no more statements in the body block(s) since we loop back to + // the body. NULL out Block to force lazy creation of another block. + Block = NULL; + + // Return the loop body, which is the dominating block for the loop. + Succ = BodyBlock; + return BodyBlock; +} + +CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) { + // "continue" is a control-flow statement. Thus we stop processing the + // current block. + if (Block && !FinishBlock(Block)) + return 0; + + // Now create a new block that ends with the continue statement. + Block = createBlock(false); + Block->setTerminator(C); + + // If there is no target for the continue, then we are looking at an + // incomplete AST. This means the CFG cannot be constructed. + if (ContinueTargetBlock) + AddSuccessor(Block, ContinueTargetBlock); + else + badCFG = true; + + return Block; +} + +CFGBlock *CFGBuilder::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, + bool alwaysAdd) { + + if (alwaysAdd) { + autoCreateBlock(); + AppendStmt(Block, E); + } + + // VLA types have expressions that must be evaluated. + if (E->isArgumentType()) { + for (VariableArrayType* VA = FindVA(E->getArgumentType().getTypePtr()); + VA != 0; VA = FindVA(VA->getElementType().getTypePtr())) + addStmt(VA->getSizeExpr()); + } + + return Block; +} + +/// VisitStmtExpr - Utility method to handle (nested) statement +/// expressions (a GCC extension). +CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, bool alwaysAdd) { + if (alwaysAdd) { + autoCreateBlock(); + AppendStmt(Block, SE); + } + return VisitCompoundStmt(SE->getSubStmt()); +} + +CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { + // "switch" is a control-flow statement. Thus we stop processing the current + // block. + CFGBlock* SwitchSuccessor = NULL; + + if (Block) { + if (!FinishBlock(Block)) + return 0; + SwitchSuccessor = Block; + } else SwitchSuccessor = Succ; + + // Save the current "switch" context. + SaveAndRestore save_switch(SwitchTerminatedBlock), + save_break(BreakTargetBlock), + save_default(DefaultCaseBlock); + + // Set the "default" case to be the block after the switch statement. If the + // switch statement contains a "default:", this value will be overwritten with + // the block for that code. + DefaultCaseBlock = SwitchSuccessor; + + // Create a new block that will contain the switch statement. + SwitchTerminatedBlock = createBlock(false); + + // Now process the switch body. The code after the switch is the implicit + // successor. + Succ = SwitchSuccessor; + BreakTargetBlock = SwitchSuccessor; + + // When visiting the body, the case statements should automatically get linked + // up to the switch. We also don't keep a pointer to the body, since all + // control-flow from the switch goes to case/default statements. + assert (Terminator->getBody() && "switch must contain a non-NULL body"); + Block = NULL; + CFGBlock *BodyBlock = addStmt(Terminator->getBody()); + if (Block) { + if (!FinishBlock(BodyBlock)) + return 0; + } + + // If we have no "default:" case, the default transition is to the code + // following the switch body. + AddSuccessor(SwitchTerminatedBlock, DefaultCaseBlock); + + // Add the terminator and condition in the switch block. + SwitchTerminatedBlock->setTerminator(Terminator); + assert (Terminator->getCond() && "switch condition must be non-NULL"); + Block = SwitchTerminatedBlock; + + return addStmt(Terminator->getCond()); +} + +CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) { + // CaseStmts are essentially labels, so they are the first statement in a + // block. + + if (CS->getSubStmt()) + addStmt(CS->getSubStmt()); + + CFGBlock* CaseBlock = Block; + if (!CaseBlock) + CaseBlock = createBlock(); + + // Cases statements partition blocks, so this is the top of the basic block we + // were processing (the "case XXX:" is the label). + CaseBlock->setLabel(CS); + + if (!FinishBlock(CaseBlock)) + return 0; + + // Add this block to the list of successors for the block with the switch + // statement. + assert(SwitchTerminatedBlock); + AddSuccessor(SwitchTerminatedBlock, CaseBlock); + + // We set Block to NULL to allow lazy creation of a new block (if necessary) + Block = NULL; + + // This block is now the implicit successor of other blocks. + Succ = CaseBlock; + + return CaseBlock; +} + +CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* Terminator) { + if (Terminator->getSubStmt()) + addStmt(Terminator->getSubStmt()); + + DefaultCaseBlock = Block; + + if (!DefaultCaseBlock) + DefaultCaseBlock = createBlock(); + + // Default statements partition blocks, so this is the top of the basic block + // we were processing (the "default:" is the label). + DefaultCaseBlock->setLabel(Terminator); + + if (!FinishBlock(DefaultCaseBlock)) + return 0; + + // Unlike case statements, we don't add the default block to the successors + // for the switch statement immediately. This is done when we finish + // processing the switch statement. This allows for the default case + // (including a fall-through to the code after the switch statement) to always + // be the last successor of a switch-terminated block. + + // We set Block to NULL to allow lazy creation of a new block (if necessary) + Block = NULL; + + // This block is now the implicit successor of other blocks. + Succ = DefaultCaseBlock; + + return DefaultCaseBlock; +} + +CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) { + // Lazily create the indirect-goto dispatch block if there isn't one already. + CFGBlock* IBlock = cfg->getIndirectGotoBlock(); + + if (!IBlock) { + IBlock = createBlock(false); + cfg->setIndirectGotoBlock(IBlock); + } + + // IndirectGoto is a control-flow statement. Thus we stop processing the + // current block and create a new one. + if (Block && !FinishBlock(Block)) + return 0; + + Block = createBlock(false); + Block->setTerminator(I); + AddSuccessor(Block, IBlock); + return addStmt(I->getTarget()); +} + +} // end anonymous namespace + +/// createBlock - Constructs and adds a new CFGBlock to the CFG. The block has +/// no successors or predecessors. If this is the first block created in the +/// CFG, it is automatically set to be the Entry and Exit of the CFG. +CFGBlock* CFG::createBlock() { + bool first_block = begin() == end(); + + // Create the block. + CFGBlock *Mem = getAllocator().Allocate(); + new (Mem) CFGBlock(NumBlockIDs++, BlkBVC); + Blocks.push_back(Mem, BlkBVC); + + // If this is the first block, set it as the Entry and Exit. + if (first_block) + Entry = Exit = &back(); + + // Return the block. + return &back(); +} + +/// buildCFG - Constructs a CFG from an AST. Ownership of the returned +/// CFG is returned to the caller. +CFG* CFG::buildCFG(Stmt* Statement, ASTContext *C) { + CFGBuilder Builder; + return Builder.buildCFG(Statement, C); +} + +//===----------------------------------------------------------------------===// +// CFG: Queries for BlkExprs. +//===----------------------------------------------------------------------===// + +namespace { + typedef llvm::DenseMap BlkExprMapTy; +} + +static void FindSubExprAssignments(Stmt* Terminator, llvm::SmallPtrSet& Set) { + if (!Terminator) + return; + + for (Stmt::child_iterator I=Terminator->child_begin(), E=Terminator->child_end(); I!=E; ++I) { + if (!*I) continue; + + if (BinaryOperator* B = dyn_cast(*I)) + if (B->isAssignmentOp()) Set.insert(B); + + FindSubExprAssignments(*I, Set); + } +} + +static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) { + BlkExprMapTy* M = new BlkExprMapTy(); + + // Look for assignments that are used as subexpressions. These are the only + // assignments that we want to *possibly* register as a block-level + // expression. Basically, if an assignment occurs both in a subexpression and + // at the block-level, it is a block-level expression. + llvm::SmallPtrSet SubExprAssignments; + + for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) + for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI) + FindSubExprAssignments(*BI, SubExprAssignments); + + for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) { + + // Iterate over the statements again on identify the Expr* and Stmt* at the + // block-level that are block-level expressions. + + for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI) + if (Expr* Exp = dyn_cast(*BI)) { + + if (BinaryOperator* B = dyn_cast(Exp)) { + // Assignment expressions that are not nested within another + // expression are really "statements" whose value is never used by + // another expression. + if (B->isAssignmentOp() && !SubExprAssignments.count(Exp)) + continue; + } else if (const StmtExpr* Terminator = dyn_cast(Exp)) { + // Special handling for statement expressions. The last statement in + // the statement expression is also a block-level expr. + const CompoundStmt* C = Terminator->getSubStmt(); + if (!C->body_empty()) { + unsigned x = M->size(); + (*M)[C->body_back()] = x; + } + } + + unsigned x = M->size(); + (*M)[Exp] = x; + } + + // Look at terminators. The condition is a block-level expression. + + Stmt* S = (*I)->getTerminatorCondition(); + + if (S && M->find(S) == M->end()) { + unsigned x = M->size(); + (*M)[S] = x; + } + } + + return M; +} + +CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt* S) { + assert(S != NULL); + if (!BlkExprMap) { BlkExprMap = (void*) PopulateBlkExprMap(*this); } + + BlkExprMapTy* M = reinterpret_cast(BlkExprMap); + BlkExprMapTy::iterator I = M->find(S); + + if (I == M->end()) return CFG::BlkExprNumTy(); + else return CFG::BlkExprNumTy(I->second); +} + +unsigned CFG::getNumBlkExprs() { + if (const BlkExprMapTy* M = reinterpret_cast(BlkExprMap)) + return M->size(); + else { + // We assume callers interested in the number of BlkExprs will want + // the map constructed if it doesn't already exist. + BlkExprMap = (void*) PopulateBlkExprMap(*this); + return reinterpret_cast(BlkExprMap)->size(); + } +} + +//===----------------------------------------------------------------------===// +// Cleanup: CFG dstor. +//===----------------------------------------------------------------------===// + +CFG::~CFG() { + delete reinterpret_cast(BlkExprMap); +} + +//===----------------------------------------------------------------------===// +// CFG pretty printing +//===----------------------------------------------------------------------===// + +namespace { + +class VISIBILITY_HIDDEN StmtPrinterHelper : public PrinterHelper { + + typedef llvm::DenseMap > StmtMapTy; + StmtMapTy StmtMap; + signed CurrentBlock; + unsigned CurrentStmt; + const LangOptions &LangOpts; +public: + + StmtPrinterHelper(const CFG* cfg, const LangOptions &LO) + : CurrentBlock(0), CurrentStmt(0), LangOpts(LO) { + for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) { + unsigned j = 1; + for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ; + BI != BEnd; ++BI, ++j ) + StmtMap[*BI] = std::make_pair((*I)->getBlockID(),j); + } + } + + virtual ~StmtPrinterHelper() {} + + const LangOptions &getLangOpts() const { return LangOpts; } + void setBlockID(signed i) { CurrentBlock = i; } + void setStmtID(unsigned i) { CurrentStmt = i; } + + virtual bool handledStmt(Stmt* Terminator, llvm::raw_ostream& OS) { + + StmtMapTy::iterator I = StmtMap.find(Terminator); + + if (I == StmtMap.end()) + return false; + + if (CurrentBlock >= 0 && I->second.first == (unsigned) CurrentBlock + && I->second.second == CurrentStmt) + return false; + + OS << "[B" << I->second.first << "." << I->second.second << "]"; + return true; + } +}; +} // end anonymous namespace + + +namespace { +class VISIBILITY_HIDDEN CFGBlockTerminatorPrint + : public StmtVisitor { + + llvm::raw_ostream& OS; + StmtPrinterHelper* Helper; + PrintingPolicy Policy; + +public: + CFGBlockTerminatorPrint(llvm::raw_ostream& os, StmtPrinterHelper* helper, + const PrintingPolicy &Policy) + : OS(os), Helper(helper), Policy(Policy) {} + + void VisitIfStmt(IfStmt* I) { + OS << "if "; + I->getCond()->printPretty(OS,Helper,Policy); + } + + // Default case. + void VisitStmt(Stmt* Terminator) { + Terminator->printPretty(OS, Helper, Policy); + } + + void VisitForStmt(ForStmt* F) { + OS << "for (" ; + if (F->getInit()) OS << "..."; + OS << "; "; + if (Stmt* C = F->getCond()) C->printPretty(OS, Helper, Policy); + OS << "; "; + if (F->getInc()) OS << "..."; + OS << ")"; + } + + void VisitWhileStmt(WhileStmt* W) { + OS << "while " ; + if (Stmt* C = W->getCond()) C->printPretty(OS, Helper, Policy); + } + + void VisitDoStmt(DoStmt* D) { + OS << "do ... while "; + if (Stmt* C = D->getCond()) C->printPretty(OS, Helper, Policy); + } + + void VisitSwitchStmt(SwitchStmt* Terminator) { + OS << "switch "; + Terminator->getCond()->printPretty(OS, Helper, Policy); + } + + void VisitConditionalOperator(ConditionalOperator* C) { + C->getCond()->printPretty(OS, Helper, Policy); + OS << " ? ... : ..."; + } + + void VisitChooseExpr(ChooseExpr* C) { + OS << "__builtin_choose_expr( "; + C->getCond()->printPretty(OS, Helper, Policy); + OS << " )"; + } + + void VisitIndirectGotoStmt(IndirectGotoStmt* I) { + OS << "goto *"; + I->getTarget()->printPretty(OS, Helper, Policy); + } + + void VisitBinaryOperator(BinaryOperator* B) { + if (!B->isLogicalOp()) { + VisitExpr(B); + return; + } + + B->getLHS()->printPretty(OS, Helper, Policy); + + switch (B->getOpcode()) { + case BinaryOperator::LOr: + OS << " || ..."; + return; + case BinaryOperator::LAnd: + OS << " && ..."; + return; + default: + assert(false && "Invalid logical operator."); + } + } + + void VisitExpr(Expr* E) { + E->printPretty(OS, Helper, Policy); + } +}; +} // end anonymous namespace + + +static void print_stmt(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, + Stmt* Terminator) { + if (Helper) { + // special printing for statement-expressions. + if (StmtExpr* SE = dyn_cast(Terminator)) { + CompoundStmt* Sub = SE->getSubStmt(); + + if (Sub->child_begin() != Sub->child_end()) { + OS << "({ ... ; "; + Helper->handledStmt(*SE->getSubStmt()->body_rbegin(),OS); + OS << " })\n"; + return; + } + } + + // special printing for comma expressions. + if (BinaryOperator* B = dyn_cast(Terminator)) { + if (B->getOpcode() == BinaryOperator::Comma) { + OS << "... , "; + Helper->handledStmt(B->getRHS(),OS); + OS << '\n'; + return; + } + } + } + + Terminator->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts())); + + // Expressions need a newline. + if (isa(Terminator)) OS << '\n'; +} + +static void print_block(llvm::raw_ostream& OS, const CFG* cfg, + const CFGBlock& B, + StmtPrinterHelper* Helper, bool print_edges) { + + if (Helper) Helper->setBlockID(B.getBlockID()); + + // Print the header. + OS << "\n [ B" << B.getBlockID(); + + if (&B == &cfg->getEntry()) + OS << " (ENTRY) ]\n"; + else if (&B == &cfg->getExit()) + OS << " (EXIT) ]\n"; + else if (&B == cfg->getIndirectGotoBlock()) + OS << " (INDIRECT GOTO DISPATCH) ]\n"; + else + OS << " ]\n"; + + // Print the label of this block. + if (Stmt* Terminator = const_cast(B.getLabel())) { + + if (print_edges) + OS << " "; + + if (LabelStmt* L = dyn_cast(Terminator)) + OS << L->getName(); + else if (CaseStmt* C = dyn_cast(Terminator)) { + OS << "case "; + C->getLHS()->printPretty(OS, Helper, + PrintingPolicy(Helper->getLangOpts())); + if (C->getRHS()) { + OS << " ... "; + C->getRHS()->printPretty(OS, Helper, + PrintingPolicy(Helper->getLangOpts())); + } + } else if (isa(Terminator)) + OS << "default"; + else + assert(false && "Invalid label statement in CFGBlock."); + + OS << ":\n"; + } + + // Iterate through the statements in the block and print them. + unsigned j = 1; + + for (CFGBlock::const_iterator I = B.begin(), E = B.end() ; + I != E ; ++I, ++j ) { + + // Print the statement # in the basic block and the statement itself. + if (print_edges) + OS << " "; + + OS << llvm::format("%3d", j) << ": "; + + if (Helper) + Helper->setStmtID(j); + + print_stmt(OS,Helper,*I); + } + + // Print the terminator of this block. + if (B.getTerminator()) { + if (print_edges) + OS << " "; + + OS << " T: "; + + if (Helper) Helper->setBlockID(-1); + + CFGBlockTerminatorPrint TPrinter(OS, Helper, + PrintingPolicy(Helper->getLangOpts())); + TPrinter.Visit(const_cast(B.getTerminator())); + OS << '\n'; + } + + if (print_edges) { + // Print the predecessors of this block. + OS << " Predecessors (" << B.pred_size() << "):"; + unsigned i = 0; + + for (CFGBlock::const_pred_iterator I = B.pred_begin(), E = B.pred_end(); + I != E; ++I, ++i) { + + if (i == 8 || (i-8) == 0) + OS << "\n "; + + OS << " B" << (*I)->getBlockID(); + } + + OS << '\n'; + + // Print the successors of this block. + OS << " Successors (" << B.succ_size() << "):"; + i = 0; + + for (CFGBlock::const_succ_iterator I = B.succ_begin(), E = B.succ_end(); + I != E; ++I, ++i) { + + if (i == 8 || (i-8) % 10 == 0) + OS << "\n "; + + if (*I) + OS << " B" << (*I)->getBlockID(); + else + OS << " NULL"; + } + + OS << '\n'; + } +} + + +/// dump - A simple pretty printer of a CFG that outputs to stderr. +void CFG::dump(const LangOptions &LO) const { print(llvm::errs(), LO); } + +/// print - A simple pretty printer of a CFG that outputs to an ostream. +void CFG::print(llvm::raw_ostream &OS, const LangOptions &LO) const { + StmtPrinterHelper Helper(this, LO); + + // Print the entry block. + print_block(OS, this, getEntry(), &Helper, true); + + // Iterate through the CFGBlocks and print them one by one. + for (const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) { + // Skip the entry block, because we already printed it. + if (&(**I) == &getEntry() || &(**I) == &getExit()) + continue; + + print_block(OS, this, **I, &Helper, true); + } + + // Print the exit block. + print_block(OS, this, getExit(), &Helper, true); + OS.flush(); +} + +/// dump - A simply pretty printer of a CFGBlock that outputs to stderr. +void CFGBlock::dump(const CFG* cfg, const LangOptions &LO) const { + print(llvm::errs(), cfg, LO); +} + +/// print - A simple pretty printer of a CFGBlock that outputs to an ostream. +/// Generally this will only be called from CFG::print. +void CFGBlock::print(llvm::raw_ostream& OS, const CFG* cfg, + const LangOptions &LO) const { + StmtPrinterHelper Helper(cfg, LO); + print_block(OS, cfg, *this, &Helper, true); +} + +/// printTerminator - A simple pretty printer of the terminator of a CFGBlock. +void CFGBlock::printTerminator(llvm::raw_ostream &OS, + const LangOptions &LO) const { + CFGBlockTerminatorPrint TPrinter(OS, NULL, PrintingPolicy(LO)); + TPrinter.Visit(const_cast(getTerminator())); +} + +Stmt* CFGBlock::getTerminatorCondition() { + + if (!Terminator) + return NULL; + + Expr* E = NULL; + + switch (Terminator->getStmtClass()) { + default: + break; + + case Stmt::ForStmtClass: + E = cast(Terminator)->getCond(); + break; + + case Stmt::WhileStmtClass: + E = cast(Terminator)->getCond(); + break; + + case Stmt::DoStmtClass: + E = cast(Terminator)->getCond(); + break; + + case Stmt::IfStmtClass: + E = cast(Terminator)->getCond(); + break; + + case Stmt::ChooseExprClass: + E = cast(Terminator)->getCond(); + break; + + case Stmt::IndirectGotoStmtClass: + E = cast(Terminator)->getTarget(); + break; + + case Stmt::SwitchStmtClass: + E = cast(Terminator)->getCond(); + break; + + case Stmt::ConditionalOperatorClass: + E = cast(Terminator)->getCond(); + break; + + case Stmt::BinaryOperatorClass: // '&&' and '||' + E = cast(Terminator)->getLHS(); + break; + + case Stmt::ObjCForCollectionStmtClass: + return Terminator; + } + + return E ? E->IgnoreParens() : NULL; +} + +bool CFGBlock::hasBinaryBranchTerminator() const { + + if (!Terminator) + return false; + + Expr* E = NULL; + + switch (Terminator->getStmtClass()) { + default: + return false; + + case Stmt::ForStmtClass: + case Stmt::WhileStmtClass: + case Stmt::DoStmtClass: + case Stmt::IfStmtClass: + case Stmt::ChooseExprClass: + case Stmt::ConditionalOperatorClass: + case Stmt::BinaryOperatorClass: + return true; + } + + return E ? E->IgnoreParens() : NULL; +} + + +//===----------------------------------------------------------------------===// +// CFG Graphviz Visualization +//===----------------------------------------------------------------------===// + + +#ifndef NDEBUG +static StmtPrinterHelper* GraphHelper; +#endif + +void CFG::viewCFG(const LangOptions &LO) const { +#ifndef NDEBUG + StmtPrinterHelper H(this, LO); + GraphHelper = &H; + llvm::ViewGraph(this,"CFG"); + GraphHelper = NULL; +#endif +} + +namespace llvm { +template<> +struct DOTGraphTraits : public DefaultDOTGraphTraits { + static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph, + bool ShortNames) { + +#ifndef NDEBUG + std::string OutSStr; + llvm::raw_string_ostream Out(OutSStr); + print_block(Out,Graph, *Node, GraphHelper, false); + std::string& OutStr = Out.str(); + + if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); + + // Process string output to make it nicer... + for (unsigned i = 0; i != OutStr.length(); ++i) + if (OutStr[i] == '\n') { // Left justify + OutStr[i] = '\\'; + OutStr.insert(OutStr.begin()+i+1, 'l'); + } + + return OutStr; +#else + return ""; +#endif + } +}; +} // end namespace llvm diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 3cca482633ca..9b6125705d9a 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -22,7 +22,7 @@ #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/SymbolManager.h" #include "clang/Analysis/PathSensitive/GRTransferFuncs.h" -#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclObjC.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableMap.h" @@ -44,7 +44,7 @@ using namespace clang; // 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, +// 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 @@ -62,8 +62,8 @@ static inline bool isWordEnd(char ch, char prev, char next) { || (isupper(prev) && isupper(ch) && islower(next)) // XXCreate || !isalpha(ch); } - -static inline const char* parseWord(const char* s) { + +static inline const char* parseWord(const char* s) { char ch = *s, prev = '\0'; assert(ch != '\0'); char next = *(s+1); @@ -77,18 +77,18 @@ static inline const char* parseWord(const char* s) { static NamingConvention deriveNamingConvention(Selector S) { IdentifierInfo *II = S.getIdentifierInfoForSlot(0); - + if (!II) return NoConvention; - + const char *s = II->getName(); - + // 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 == '_') { @@ -103,24 +103,24 @@ static NamingConvention deriveNamingConvention(Selector S) { ++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 && StringsEqualNoCase("new", s, len)) - C = CreateRule; + C = CreateRule; break; case 4: // Methods starting with 'alloc' or contain 'copy' follow the @@ -136,7 +136,7 @@ static NamingConvention deriveNamingConvention(Selector S) { C = CreateRule; break; } - + // If we aren't in the prefix and have a derived convention then just // return it now. if (!InPossiblePrefix && C != NoConvention) @@ -156,10 +156,10 @@ static bool followsFundamentalRule(Selector S) { } static const ObjCMethodDecl* -ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) { +ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) { ObjCInterfaceDecl *ID = const_cast(MD->getClassInterface()); - + return MD->isInstanceMethod() ? ID->lookupInstanceMethod(MD->getSelector()) : ID->lookupClassMethod(MD->getSelector()); @@ -167,22 +167,23 @@ ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) { namespace { class VISIBILITY_HIDDEN GenericNodeBuilder { - GRStmtNodeBuilder *SNB; + GRStmtNodeBuilder *SNB; Stmt *S; const void *tag; - GREndPathNodeBuilder *ENB; + GREndPathNodeBuilder *ENB; public: - GenericNodeBuilder(GRStmtNodeBuilder &snb, Stmt *s, + GenericNodeBuilder(GRStmtNodeBuilder &snb, Stmt *s, const void *t) : SNB(&snb), S(s), tag(t), ENB(0) {} - GenericNodeBuilder(GREndPathNodeBuilder &enb) + + GenericNodeBuilder(GREndPathNodeBuilder &enb) : SNB(0), S(0), tag(0), ENB(&enb) {} - - ExplodedNode *MakeNode(const GRState *state, - ExplodedNode *Pred) { + + ExplodedNode *MakeNode(const GRState *state, ExplodedNode *Pred) { if (SNB) - return SNB->generateNode(PostStmt(S, tag), state, Pred); - + return SNB->generateNode(PostStmt(S, Pred->getLocationContext(), tag), + state, Pred); + assert(ENB); return ENB->generateNode(state, Pred); } @@ -210,16 +211,16 @@ static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) { static bool hasPrefix(const char* s, const char* prefix) { if (!prefix) return true; - + char c = *s; char cP = *prefix; - + while (c != '\0' && cP != '\0') { if (c != cP) break; c = *(++s); cP = *(++prefix); } - + return cP == '\0'; } @@ -230,14 +231,14 @@ static bool hasSuffix(const char* s, const char* suffix) { 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 (1) { if (TypedefType* TD = dyn_cast(RetTy.getTypePtr())) { const char* TDName = TD->getDecl()->getIdentifier()->getName(); if (hasPrefix(TDName, prefix) && hasSuffix(TDName, "Ref")) return true; - + RetTy = TD->getDecl()->getUnderlyingType(); continue; } @@ -248,7 +249,7 @@ static bool isRefType(QualType RetTy, const char* prefix, return false; // Is the type void*? - const PointerType* PT = RetTy->getAsPointerType(); + const PointerType* PT = RetTy->getAs(); if (!(PT->getPointeeType().getUnqualifiedType() == Ctx->VoidTy)) return false; @@ -281,14 +282,14 @@ typedef llvm::ImmutableMap ArgEffects; namespace { /// RetEffect is used to summarize a function/method call's behavior with -/// respect to its return value. +/// respect to its return value. class VISIBILITY_HIDDEN RetEffect { public: enum Kind { NoRet, Alias, OwnedSymbol, OwnedAllocatedSymbol, NotOwnedSymbol, GCNotOwnedSymbol, ReceiverAlias, OwnedWhenTrackedReceiver }; - - enum ObjKind { CF, ObjC, AnyObj }; + + enum ObjKind { CF, ObjC, AnyObj }; private: Kind K; @@ -297,124 +298,124 @@ private: RetEffect(Kind k, unsigned idx = 0) : K(k), O(AnyObj), index(idx) {} RetEffect(Kind k, ObjKind o) : K(k), O(o), index(0) {} - + public: Kind getKind() const { return K; } ObjKind getObjKind() const { return O; } - - unsigned getIndex() const { + + unsigned getIndex() const { assert(getKind() == Alias); return index; } - + bool isOwned() const { return K == OwnedSymbol || K == OwnedAllocatedSymbol || K == OwnedWhenTrackedReceiver; } - + static RetEffect MakeOwnedWhenTrackedReceiver() { return RetEffect(OwnedWhenTrackedReceiver, ObjC); } - + static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); } static RetEffect MakeReceiverAlias() { return RetEffect(ReceiverAlias); - } + } static RetEffect MakeOwned(ObjKind o, bool isAllocated = false) { return RetEffect(isAllocated ? OwnedAllocatedSymbol : OwnedSymbol, o); - } + } static RetEffect MakeNotOwned(ObjKind o) { return RetEffect(NotOwnedSymbol, o); } static RetEffect MakeGCNotOwned() { return RetEffect(GCNotOwnedSymbol, ObjC); } - + static RetEffect MakeNoRet() { return RetEffect(NoRet); } - + void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger((unsigned)K); ID.AddInteger((unsigned)O); ID.AddInteger(index); } }; - - + + class VISIBILITY_HIDDEN RetainSummary { /// Args - an ordered vector of (index, ArgEffect) pairs, where index /// specifies the argument (starting from 0). This can be sparsely /// populated; arguments with no entry in Args use 'DefaultArgEffect'. ArgEffects Args; - + /// DefaultArgEffect - The default ArgEffect to apply to arguments that /// do not have an entry in Args. ArgEffect DefaultArgEffect; - + /// Receiver - If this summary applies to an Objective-C message expression, /// this is the effect applied to the state of the receiver. ArgEffect Receiver; - + /// Ret - The effect on the return value. Used to indicate if the /// function/method call returns a new tracked symbol, returns an /// alias of one of the arguments in the call, and so on. RetEffect Ret; - + /// EndPath - Indicates that execution of this method/function should /// terminate the simulation of a path. bool EndPath; - + public: RetainSummary(ArgEffects A, RetEffect R, ArgEffect defaultEff, ArgEffect ReceiverEff, bool endpath = false) : Args(A), DefaultArgEffect(defaultEff), Receiver(ReceiverEff), Ret(R), - EndPath(endpath) {} - + EndPath(endpath) {} + /// getArg - Return the argument effect on the argument specified by /// idx (starting from 0). ArgEffect getArg(unsigned idx) const { if (const ArgEffect *AE = Args.lookup(idx)) return *AE; - + return DefaultArgEffect; } - + /// setDefaultArgEffect - Set the default argument effect. void setDefaultArgEffect(ArgEffect E) { DefaultArgEffect = E; } - + /// setArg - Set the argument effect on the argument specified by idx. void setArgEffect(ArgEffects::Factory& AF, unsigned idx, ArgEffect E) { Args = AF.Add(Args, idx, E); } - + /// getRetEffect - Returns the effect on the return value of the call. RetEffect getRetEffect() const { return Ret; } - + /// setRetEffect - Set the effect of the return value of the call. void setRetEffect(RetEffect E) { Ret = E; } - + /// isEndPath - Returns true if executing the given method/function should /// terminate the path. bool isEndPath() const { return EndPath; } - + /// getReceiverEffect - Returns the effect on the receiver of the call. /// This is only meaningful if the summary applies to an ObjCMessageExpr*. ArgEffect getReceiverEffect() const { return Receiver; } - + /// setReceiverEffect - Set the effect on the receiver of the call. void setReceiverEffect(ArgEffect E) { Receiver = E; } - + typedef ArgEffects::iterator ExprIterator; - + ExprIterator begin_args() const { return Args.begin(); } ExprIterator end_args() const { return Args.end(); } - + static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects A, RetEffect RetEff, ArgEffect DefaultEff, ArgEffect ReceiverEff, bool EndPath) { @@ -424,7 +425,7 @@ public: ID.AddInteger((unsigned) ReceiverEff); ID.AddInteger((unsigned) EndPath); } - + void Profile(llvm::FoldingSetNodeID& ID) const { Profile(ID, Args, Ret, DefaultArgEffect, Receiver, EndPath); } @@ -439,7 +440,7 @@ namespace { class VISIBILITY_HIDDEN ObjCSummaryKey { IdentifierInfo* II; Selector S; -public: +public: ObjCSummaryKey(IdentifierInfo* ii, Selector s) : II(ii), S(s) {} @@ -448,10 +449,10 @@ public: ObjCSummaryKey(const ObjCInterfaceDecl* d, IdentifierInfo *ii, Selector s) : II(d ? d->getIdentifier() : ii), S(s) {} - + ObjCSummaryKey(Selector s) : II(0), S(s) {} - + IdentifierInfo* getIdentifier() const { return II; } Selector getSelector() const { return S; } }; @@ -463,58 +464,56 @@ template <> struct DenseMapInfo { return ObjCSummaryKey(DenseMapInfo::getEmptyKey(), DenseMapInfo::getEmptyKey()); } - + static inline ObjCSummaryKey getTombstoneKey() { return ObjCSummaryKey(DenseMapInfo::getTombstoneKey(), - DenseMapInfo::getTombstoneKey()); + DenseMapInfo::getTombstoneKey()); } - + static unsigned getHashValue(const ObjCSummaryKey &V) { return (DenseMapInfo::getHashValue(V.getIdentifier()) - & 0x88888888) + & 0x88888888) | (DenseMapInfo::getHashValue(V.getSelector()) & 0x55555555); } - + static bool isEqual(const ObjCSummaryKey& LHS, const ObjCSummaryKey& RHS) { return DenseMapInfo::isEqual(LHS.getIdentifier(), RHS.getIdentifier()) && DenseMapInfo::isEqual(LHS.getSelector(), RHS.getSelector()); } - + static bool isPod() { return DenseMapInfo::isPod() && DenseMapInfo::isPod(); } }; } // end llvm namespace - + namespace { class VISIBILITY_HIDDEN ObjCSummaryCache { typedef llvm::DenseMap MapTy; MapTy M; public: ObjCSummaryCache() {} - - typedef MapTy::iterator iterator; - - iterator find(const ObjCInterfaceDecl* D, IdentifierInfo *ClsName, + + RetainSummary* find(const ObjCInterfaceDecl* D, IdentifierInfo *ClsName, Selector S) { // Lookup the method using the decl for the class @interface. If we // have no decl, lookup using the class name. return D ? find(D, S) : find(ClsName, S); } - - iterator find(const ObjCInterfaceDecl* D, Selector S) { + + RetainSummary* find(const ObjCInterfaceDecl* D, Selector S) { // Do a lookup with the (D,S) pair. If we find a match return // the iterator. ObjCSummaryKey K(D, S); MapTy::iterator I = M.find(K); - + if (I != M.end() || !D) - return I; - + return I->second; + // Walk the super chain. If we find a hit with a parent, we'll end // up returning that summary. We actually allow that key (null,S), as // we cache summaries for the null ObjCInterfaceDecl* to allow us to @@ -524,62 +523,62 @@ public: for (ObjCInterfaceDecl* C=D->getSuperClass() ;; C=C->getSuperClass()) { if ((I = M.find(ObjCSummaryKey(C, S))) != M.end()) break; - + if (!C) - return I; + return NULL; } - - // Cache the summary with original key to make the next lookup faster + + // Cache the summary with original key to make the next lookup faster // and return the iterator. - M[K] = I->second; - return I; + RetainSummary *Summ = I->second; + M[K] = Summ; + return Summ; } - - iterator find(Expr* Receiver, Selector S) { + + RetainSummary* find(Expr* Receiver, Selector S) { return find(getReceiverDecl(Receiver), S); } - - iterator find(IdentifierInfo* II, Selector S) { + + RetainSummary* find(IdentifierInfo* II, Selector S) { // FIXME: Class method lookup. Right now we dont' have a good way // of going between IdentifierInfo* and the class hierarchy. - iterator I = M.find(ObjCSummaryKey(II, S)); - return I == M.end() ? M.find(ObjCSummaryKey(S)) : I; + MapTy::iterator I = M.find(ObjCSummaryKey(II, S)); + + if (I == M.end()) + I = M.find(ObjCSummaryKey(S)); + + return I == M.end() ? NULL : I->second; } - - ObjCInterfaceDecl* getReceiverDecl(Expr* E) { - - const PointerType* PT = E->getType()->getAsPointerType(); - if (!PT) return 0; - - ObjCInterfaceType* OI = dyn_cast(PT->getPointeeType()); - if (!OI) return 0; - - return OI ? OI->getDecl() : 0; + + const ObjCInterfaceDecl* getReceiverDecl(Expr* E) { + if (const ObjCObjectPointerType* PT = + E->getType()->getAs()) + return PT->getInterfaceDecl(); + + return NULL; } - - iterator end() { return M.end(); } - + RetainSummary*& operator[](ObjCMessageExpr* ME) { - + Selector S = ME->getSelector(); - + if (Expr* Receiver = ME->getReceiver()) { - ObjCInterfaceDecl* OD = getReceiverDecl(Receiver); + const ObjCInterfaceDecl* OD = getReceiverDecl(Receiver); return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S]; } - + return M[ObjCSummaryKey(ME->getClassName(), S)]; } - + RetainSummary*& operator[](ObjCSummaryKey K) { return M[K]; } - + RetainSummary*& operator[](Selector S) { return M[ ObjCSummaryKey(S) ]; } -}; +}; } // end anonymous namespace //===----------------------------------------------------------------------===// @@ -592,29 +591,29 @@ class VISIBILITY_HIDDEN RetainSummaryManager { //==-----------------------------------------------------------------==// // Typedefs. //==-----------------------------------------------------------------==// - + typedef llvm::DenseMap FuncSummariesTy; - + typedef ObjCSummaryCache ObjCMethodSummariesTy; - + //==-----------------------------------------------------------------==// // Data. //==-----------------------------------------------------------------==// - + /// Ctx - The ASTContext object for the analyzed ASTs. ASTContext& Ctx; /// CFDictionaryCreateII - An IdentifierInfo* representing the indentifier /// "CFDictionaryCreate". IdentifierInfo* CFDictionaryCreateII; - + /// GCEnabled - Records whether or not the analyzed code runs in GC mode. const bool GCEnabled; - + /// FuncSummaries - A map from FunctionDecls to summaries. - FuncSummariesTy FuncSummaries; - + FuncSummariesTy FuncSummaries; + /// ObjCClassMethodSummaries - A map from selectors (for instance methods) /// to summaries. ObjCMethodSummariesTy ObjCClassMethodSummaries; @@ -625,34 +624,34 @@ class VISIBILITY_HIDDEN RetainSummaryManager { /// BPAlloc - A BumpPtrAllocator used for allocating summaries, ArgEffects, /// and all other data used by the checker. llvm::BumpPtrAllocator BPAlloc; - + /// AF - A factory for ArgEffects objects. - ArgEffects::Factory AF; - + ArgEffects::Factory AF; + /// ScratchArgs - A holding buffer for construct ArgEffects. ArgEffects ScratchArgs; - + /// ObjCAllocRetE - Default return effect for methods returning Objective-C /// objects. RetEffect ObjCAllocRetE; - /// ObjCInitRetE - Default return effect for init methods returning Objective-C - /// objects. + /// ObjCInitRetE - Default return effect for init methods returning + /// Objective-C objects. RetEffect ObjCInitRetE; - + RetainSummary DefaultSummary; RetainSummary* StopSummary; - + //==-----------------------------------------------------------------==// // Methods. //==-----------------------------------------------------------------==// - + /// getArgEffects - Returns a persistent ArgEffects object based on the /// data in ScratchArgs. ArgEffects getArgEffects(); - enum UnaryFuncKind { cfretain, cfrelease, cfmakecollectable }; - + enum UnaryFuncKind { cfretain, cfrelease, cfmakecollectable }; + public: RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; } @@ -660,13 +659,13 @@ public: RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate(); return new (Summ) RetainSummary(DefaultSummary); } - + RetainSummary* getUnarySummary(const FunctionType* FT, UnaryFuncKind func); - + RetainSummary* getCFSummaryCreateRule(FunctionDecl* FD); - RetainSummary* getCFSummaryGetRule(FunctionDecl* FD); + RetainSummary* getCFSummaryGetRule(FunctionDecl* FD); RetainSummary* getCFCreateGetRuleSummary(FunctionDecl* FD, const char* FName); - + RetainSummary* getPersistentSummary(ArgEffects AE, RetEffect RetEff, ArgEffect ReceiverEff = DoNothing, ArgEffect DefaultEff = MayEscape, @@ -677,36 +676,36 @@ public: ArgEffect DefaultEff = MayEscape) { return getPersistentSummary(getArgEffects(), RE, ReceiverEff, DefaultEff); } - + RetainSummary *getPersistentStopSummary() { if (StopSummary) return StopSummary; - + StopSummary = getPersistentSummary(RetEffect::MakeNoRet(), StopTracking, StopTracking); return StopSummary; - } + } RetainSummary *getInitMethodSummary(QualType RetTy); void InitializeClassMethodSummaries(); void InitializeMethodSummaries(); - + bool isTrackedObjCObjectType(QualType T); bool isTrackedCFObjectType(QualType T); - + private: - + void addClsMethSummary(IdentifierInfo* ClsII, Selector S, RetainSummary* Summ) { ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; } - + void addNSObjectClsMethSummary(Selector S, RetainSummary *Summ) { ObjCClassMethodSummaries[S] = Summ; } - + void addNSObjectMethSummary(Selector S, RetainSummary *Summ) { ObjCMethodSummaries[S] = Summ; } @@ -717,43 +716,43 @@ private: Selector S = GetNullarySelector(nullaryName, Ctx); ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; } - + void addInstMethSummary(const char* Cls, const char* nullaryName, RetainSummary *Summ) { IdentifierInfo* ClsII = &Ctx.Idents.get(Cls); Selector S = GetNullarySelector(nullaryName, Ctx); ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; } - + Selector generateSelector(va_list argp) { llvm::SmallVector II; while (const char* s = va_arg(argp, const char*)) II.push_back(&Ctx.Idents.get(s)); - return Ctx.Selectors.getSelector(II.size(), &II[0]); + return Ctx.Selectors.getSelector(II.size(), &II[0]); } - + void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy& Summaries, RetainSummary* Summ, va_list argp) { Selector S = generateSelector(argp); Summaries[ObjCSummaryKey(ClsII, S)] = Summ; } - + void addInstMethSummary(const char* Cls, RetainSummary* Summ, ...) { va_list argp; va_start(argp, Summ); addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp); - va_end(argp); + va_end(argp); } - + void addClsMethSummary(const char* Cls, RetainSummary* Summ, ...) { va_list argp; va_start(argp, Summ); addMethodSummary(&Ctx.Idents.get(Cls),ObjCClassMethodSummaries, Summ, argp); va_end(argp); } - + void addClsMethSummary(IdentifierInfo *II, RetainSummary* Summ, ...) { va_list argp; va_start(argp, Summ); @@ -770,9 +769,9 @@ private: addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp); va_end(argp); } - + public: - + RetainSummaryManager(ASTContext& ctx, bool gcenabled) : Ctx(ctx), CFDictionaryCreateII(&ctx.Idents.get("CFDictionaryCreate")), @@ -790,17 +789,17 @@ public: InitializeClassMethodSummaries(); InitializeMethodSummaries(); } - + ~RetainSummaryManager(); - - RetainSummary* getSummary(FunctionDecl* FD); - + + RetainSummary* getSummary(FunctionDecl* FD); + RetainSummary* getInstanceMethodSummary(ObjCMessageExpr* ME, const ObjCInterfaceDecl* ID) { return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(), - ID, ME->getMethodDecl(), ME->getType()); + ID, ME->getMethodDecl(), ME->getType()); } - + RetainSummary* getInstanceMethodSummary(Selector S, IdentifierInfo *ClsName, const ObjCInterfaceDecl* ID, const ObjCMethodDecl *MD, @@ -810,7 +809,7 @@ public: const ObjCInterfaceDecl *ID, const ObjCMethodDecl *MD, QualType RetTy); - + RetainSummary *getClassMethodSummary(ObjCMessageExpr *ME) { return getClassMethodSummary(ME->getSelector(), ME->getClassName(), ME->getClassInfo().first, @@ -825,17 +824,17 @@ public: Selector S = MD->getSelector(); IdentifierInfo *ClsName = ID->getIdentifier(); QualType ResultTy = MD->getResultType(); - - // Resolve the method decl last. + + // Resolve the method decl last. if (const ObjCMethodDecl *InterfaceMD = ResolveToInterfaceMethodDecl(MD)) MD = InterfaceMD; - + if (MD->isInstanceMethod()) return getInstanceMethodSummary(S, ClsName, ID, MD, ResultTy); else return getClassMethodSummary(S, ClsName, ID, MD, ResultTy); } - + RetainSummary* getCommonMethodSummary(const ObjCMethodDecl* MD, Selector S, QualType RetTy); @@ -846,14 +845,14 @@ public: const FunctionDecl *FD); bool isGCEnabled() const { return GCEnabled; } - + RetainSummary *copySummary(RetainSummary *OldSumm) { RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate(); new (Summ) RetainSummary(*OldSumm); return Summ; - } + } }; - + } // end anonymous namespace //===----------------------------------------------------------------------===// @@ -872,7 +871,7 @@ RetainSummary* RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff, ArgEffect ReceiverEff, ArgEffect DefaultEff, - bool isEndPath) { + bool isEndPath) { // Create the summary and return it. RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate(); new (Summ) RetainSummary(AE, RetEff, DefaultEff, ReceiverEff, isEndPath); @@ -884,36 +883,35 @@ RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff, //===----------------------------------------------------------------------===// bool RetainSummaryManager::isTrackedObjCObjectType(QualType Ty) { - if (!Ctx.isObjCObjectPointerType(Ty)) + if (!Ty->isObjCObjectPointerType()) return false; - // We assume that id<..>, id, and "Class" all represent tracked objects. - const PointerType *PT = Ty->getAsPointerType(); - if (PT == 0) + const ObjCObjectPointerType *PT = Ty->getAs(); + + // Can be true for objects with the 'NSObject' attribute. + if (!PT) return true; - - const ObjCInterfaceType *OT = PT->getPointeeType()->getAsObjCInterfaceType(); // We assume that id<..>, id, and "Class" all represent tracked objects. - if (!OT) + if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() || + PT->isObjCClassType()) return true; - - // Does the interface subclass NSObject? - // FIXME: We can memoize here if this gets too expensive. - ObjCInterfaceDecl* ID = OT->getDecl(); + + // 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"); + IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject"); for ( ; ID ; ID = ID->getSuperClass()) if (ID->getIdentifier() == NSObjectII) return true; - + return false; } @@ -947,38 +945,44 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // No summary? Generate one. RetainSummary *S = 0; - + do { // We generate "stop" summaries for implicitly defined functions. if (FD->isImplicit()) { S = getPersistentStopSummary(); break; } - - // [PR 3337] Use 'getAsFunctionType' to strip away any typedefs on the + + // [PR 3337] Use 'getAs' to strip away any typedefs on the // function's type. - const FunctionType* FT = FD->getType()->getAsFunctionType(); + const FunctionType* FT = FD->getType()->getAs(); const char* FName = FD->getIdentifier()->getName(); - + // Strip away preceding '_'. Doing this here will effect all the checks // down below. while (*FName == '_') ++FName; - + // Inspect the result type. QualType RetTy = FT->getResultType(); - + // FIXME: This should all be refactored into a chain of "summary lookup" // filters. - assert (ScratchArgs.isEmpty()); + assert(ScratchArgs.isEmpty()); switch (strlen(FName)) { default: break; - + case 14: + if (!memcmp(FName, "pthread_create", 14)) { + // Part of: . This will be addressed + // better with IPA. + S = getPersistentStopSummary(); + } + break; case 17: // Handle: id NSMakeCollectable(CFTypeRef) if (!memcmp(FName, "NSMakeCollectable", 17)) { - S = (RetTy == Ctx.getObjCIdType()) + S = (RetTy->isObjCIdType()) ? getUnarySummary(FT, cfmakecollectable) : getPersistentStopSummary(); } @@ -1005,10 +1009,10 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // Part of . (IOKit) // This should be addressed using a API table. ScratchArgs = AF.Add(ScratchArgs, 2, DecRef); - S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); } break; - + case 25: if (!memcmp(FName, "IORegistryEntryIDMatching", 25)) { // Part of . (IOKit) @@ -1017,13 +1021,13 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { DoNothing, DoNothing); } break; - + case 26: if (!memcmp(FName, "IOOpenFirmwarePathMatching", 26)) { // Part of . (IOKit) // This should be addressed using a API table. S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true), - DoNothing, DoNothing); + DoNothing, DoNothing); } break; @@ -1032,7 +1036,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // Part of . // This should be addressed using a API table. ScratchArgs = AF.Add(ScratchArgs, 1, DecRef); - S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); } break; @@ -1042,20 +1046,43 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // 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); + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, + DoNothing); + } + else if (!memcmp(FName, "CVPixelBufferCreateWithBytes", 28)) { + // FIXES: + // 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. + ScratchArgs = AF.Add(ScratchArgs, 7, StopTracking); + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, + DoNothing); } break; - + case 32: if (!memcmp(FName, "IOServiceAddMatchingNotification", 32)) { // Part of . // This should be addressed using a API table. ScratchArgs = AF.Add(ScratchArgs, 2, DecRef); - S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); + } + break; + + case 34: + if (!memcmp(FName, "CVPixelBufferCreateWithPlanarBytes", 34)) { + // FIXES: + // 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; } - + // Did we get a summary? if (S) break; @@ -1065,7 +1092,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { #if 0 // Handle: NSDeallocateObject(id anObject); // This method does allow 'nil' (although we don't check it now). - if (strcmp(FName, "NSDeallocateObject") == 0) { + if (strcmp(FName, "NSDeallocateObject") == 0) { return RetTy == Ctx.VoidTy ? getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, Dealloc) : getPersistentStopSummary(); @@ -1079,7 +1106,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { S = getUnarySummary(FT, cfretain); else if (strstr(FName, "MakeCollectable")) S = getUnarySummary(FT, cfmakecollectable); - else + else S = getCFCreateGetRuleSummary(FD, FName); break; @@ -1102,7 +1129,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { S = getCFCreateGetRuleSummary(FD, FName); break; } - + break; } @@ -1114,7 +1141,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { FName += 4; else FName += 2; - + if (isRelease(FD, FName)) S = getUnarySummary(FT, cfrelease); else { @@ -1124,48 +1151,50 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // and that ownership cannot be transferred. While this is technically // correct, many methods allow a tracked object to escape. For example: // - // CFMutableDictionaryRef x = CFDictionaryCreateMutable(...); + // CFMutableDictionaryRef x = CFDictionaryCreateMutable(...); // CFDictionaryAddValue(y, key, x); - // CFRelease(x); + // CFRelease(x); // ... it is okay to use 'x' since 'y' has a reference to it // // We handle this and similar cases with the follow heuristic. If the - // function name contains "InsertValue", "SetValue" or "AddValue" then - // we assume that arguments may "escape." - // + // function name contains "InsertValue", "SetValue", "AddValue", + // "AppendValue", or "SetAttribute", then we assume that arguments may + // "escape." This means that something else holds on to the object, + // allowing it be used even after its local retain count drops to 0. ArgEffect E = (CStrInCStrNoCase(FName, "InsertValue") || CStrInCStrNoCase(FName, "AddValue") || CStrInCStrNoCase(FName, "SetValue") || - CStrInCStrNoCase(FName, "AppendValue")) + CStrInCStrNoCase(FName, "AppendValue") || + CStrInCStrNoCase(FName, "SetAttribute")) ? MayEscape : DoNothing; - + S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, E); } } } while (0); - + if (!S) S = getDefaultSummary(); // Annotations override defaults. assert(S); updateSummaryFromAnnotations(*S, FD); - + FuncSummaries[FD] = S; - return S; + return S; } RetainSummary* RetainSummaryManager::getCFCreateGetRuleSummary(FunctionDecl* FD, const char* FName) { - + if (strstr(FName, "Create") || strstr(FName, "Copy")) return getCFSummaryCreateRule(FD); - + if (strstr(FName, "Get")) return getCFSummaryGetRule(FD); - + return getDefaultSummary(); } @@ -1178,27 +1207,27 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT, const FunctionProtoType* FTP = dyn_cast(FT); if (!FTP || FTP->getNumArgs() != 1) return getPersistentStopSummary(); - + assert (ScratchArgs.isEmpty()); - + switch (func) { case cfretain: { ScratchArgs = AF.Add(ScratchArgs, 0, IncRef); return getPersistentSummary(RetEffect::MakeAlias(0), DoNothing, DoNothing); } - + case cfrelease: { ScratchArgs = AF.Add(ScratchArgs, 0, DecRef); return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); } - + case cfmakecollectable: { ScratchArgs = AF.Add(ScratchArgs, 0, MakeCollectable); - return getPersistentSummary(RetEffect::MakeAlias(0),DoNothing, DoNothing); + return getPersistentSummary(RetEffect::MakeAlias(0),DoNothing, DoNothing); } - + default: assert (false && "Not a supported unary function."); return getDefaultSummary(); @@ -1207,17 +1236,17 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT, RetainSummary* RetainSummaryManager::getCFSummaryCreateRule(FunctionDecl* FD) { assert (ScratchArgs.isEmpty()); - + if (FD->getIdentifier() == CFDictionaryCreateII) { ScratchArgs = AF.Add(ScratchArgs, 1, DoNothingByRef); ScratchArgs = AF.Add(ScratchArgs, 2, DoNothingByRef); } - + return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true)); } RetainSummary* RetainSummaryManager::getCFSummaryGetRule(FunctionDecl* FD) { - assert (ScratchArgs.isEmpty()); + assert (ScratchArgs.isEmpty()); return getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::CF), DoNothing, DoNothing); } @@ -1228,12 +1257,12 @@ RetainSummary* RetainSummaryManager::getCFSummaryGetRule(FunctionDecl* FD) { RetainSummary* RetainSummaryManager::getInitMethodSummary(QualType RetTy) { - assert(ScratchArgs.isEmpty()); + assert(ScratchArgs.isEmpty()); // 'init' methods conceptually return a newly allocated object and claim - // the receiver. + // the receiver. if (isTrackedObjCObjectType(RetTy) || isTrackedCFObjectType(RetTy)) return getPersistentSummary(ObjCInitRetE, DecRefMsg); - + return getDefaultSummary(); } @@ -1244,7 +1273,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, return; QualType RetTy = FD->getResultType(); - + // Determine if there is a special return effect for this method. if (isTrackedObjCObjectType(RetTy)) { if (FD->getAttr()) { @@ -1254,7 +1283,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); } } - else if (RetTy->getAsPointerType()) { + else if (RetTy->getAs()) { if (FD->getAttr()) { Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); } @@ -1267,15 +1296,23 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, if (!MD) return; + bool isTrackedLoc = false; + // Determine if there is a special return effect for this method. if (isTrackedObjCObjectType(MD->getResultType())) { if (MD->getAttr()) { Summ.setRetEffect(ObjCAllocRetE); + return; } - else if (MD->getAttr()) { - Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); - } + + isTrackedLoc = true; } + + if (!isTrackedLoc) + isTrackedLoc = MD->getResultType()->getAs() != NULL; + + if (isTrackedLoc && MD->getAttr()) + Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); } RetainSummary* @@ -1296,10 +1333,10 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD, ScratchArgs = AF.Add(ScratchArgs, i, StopTracking); } } - + // Any special effect for the receiver? ArgEffect ReceiverEff = DoNothing; - + // If one of the arguments in the selector has the keyword 'delegate' we // should stop tracking the reference count for the receiver. This is // because the reference count is quite possibly handled by a delegate @@ -1309,29 +1346,29 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD, assert(!str.empty()); if (CStrInCStrNoCase(&str[0], "delegate:")) ReceiverEff = StopTracking; } - + // Look for methods that return an owned object. - if (isTrackedObjCObjectType(RetTy)) { + if (isTrackedObjCObjectType(RetTy)) { // EXPERIMENTAL: Assume the Cocoa conventions for all objects returned // by instance methods. RetEffect E = followsFundamentalRule(S) ? ObjCAllocRetE : RetEffect::MakeNotOwned(RetEffect::ObjC); - - return getPersistentSummary(E, ReceiverEff, MayEscape); + + return getPersistentSummary(E, ReceiverEff, MayEscape); } - + // Look for methods that return an owned core foundation object. if (isTrackedCFObjectType(RetTy)) { RetEffect E = followsFundamentalRule(S) ? RetEffect::MakeOwned(RetEffect::CF, true) : RetEffect::MakeNotOwned(RetEffect::CF); - + return getPersistentSummary(E, ReceiverEff, MayEscape); } - + if (ScratchArgs.isEmpty() && ReceiverEff == DoNothing) return getDefaultSummary(); - + return getPersistentSummary(RetEffect::MakeNoRet(), ReceiverEff, MayEscape); } @@ -1343,25 +1380,24 @@ RetainSummaryManager::getInstanceMethodSummary(Selector S, QualType RetTy) { // Look up a summary in our summary cache. - ObjCMethodSummariesTy::iterator I = ObjCMethodSummaries.find(ID, ClsName, S); - - if (I != ObjCMethodSummaries.end()) - return I->second; + RetainSummary *Summ = ObjCMethodSummaries.find(ID, ClsName, S); + + if (!Summ) { + assert(ScratchArgs.isEmpty()); + + // "initXXX": pass-through for receiver. + if (deriveNamingConvention(S) == InitRule) + Summ = getInitMethodSummary(RetTy); + else + Summ = getCommonMethodSummary(MD, S, RetTy); + + // Annotations override defaults. + updateSummaryFromAnnotations(*Summ, MD); + + // Memoize the summary. + ObjCMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ; + } - assert(ScratchArgs.isEmpty()); - RetainSummary *Summ = 0; - - // "initXXX": pass-through for receiver. - if (deriveNamingConvention(S) == InitRule) - Summ = getInitMethodSummary(RetTy); - else - Summ = getCommonMethodSummary(MD, S, RetTy); - - // Annotations override defaults. - updateSummaryFromAnnotations(*Summ, MD); - - // Memoize the summary. - ObjCMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ; return Summ; } @@ -1372,44 +1408,41 @@ RetainSummaryManager::getClassMethodSummary(Selector S, IdentifierInfo *ClsName, QualType RetTy) { assert(ClsName && "Class name must be specified."); - ObjCMethodSummariesTy::iterator I = - ObjCClassMethodSummaries.find(ID, ClsName, S); - - if (I != ObjCClassMethodSummaries.end()) - return I->second; - - RetainSummary *Summ = getCommonMethodSummary(MD, S, RetTy); - - // Annotations override defaults. - updateSummaryFromAnnotations(*Summ, MD); + RetainSummary *Summ = ObjCClassMethodSummaries.find(ID, ClsName, S); + + if (!Summ) { + Summ = getCommonMethodSummary(MD, S, RetTy); + // Annotations override defaults. + updateSummaryFromAnnotations(*Summ, MD); + // Memoize the summary. + ObjCClassMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ; + } - // Memoize the summary. - ObjCClassMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ; return Summ; } -void RetainSummaryManager::InitializeClassMethodSummaries() { +void RetainSummaryManager::InitializeClassMethodSummaries() { assert(ScratchArgs.isEmpty()); RetainSummary* Summ = getPersistentSummary(ObjCAllocRetE); - + // Create the summaries for "alloc", "new", and "allocWithZone:" for // NSObject and its derivatives. addNSObjectClsMethSummary(GetNullarySelector("alloc", Ctx), Summ); addNSObjectClsMethSummary(GetNullarySelector("new", Ctx), Summ); addNSObjectClsMethSummary(GetUnarySelector("allocWithZone", Ctx), Summ); - - // Create the [NSAssertionHandler currentHander] summary. + + // Create the [NSAssertionHandler currentHander] summary. addClsMethSummary(&Ctx.Idents.get("NSAssertionHandler"), GetNullarySelector("currentHandler", Ctx), getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::ObjC))); - + // Create the [NSAutoreleasePool addObject:] summary. ScratchArgs = AF.Add(ScratchArgs, 0, Autorelease); addClsMethSummary(&Ctx.Idents.get("NSAutoreleasePool"), GetUnarySelector("addObject", Ctx), getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, Autorelease)); - + // Create the summaries for [NSObject performSelector...]. We treat // these as 'stop tracking' for the arguments because they are often // used for delegates that can release the object. When we have better @@ -1431,7 +1464,7 @@ void RetainSummaryManager::InitializeClassMethodSummaries() { "withObject", "waitUntilDone", "modes", NULL); addClsMethSummary(NSObjectII, Summ, "performSelectorInBackground", "withObject", NULL); - + // Specially handle NSData. RetainSummary *dataWithBytesNoCopySumm = getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::ObjC), DoNothing, @@ -1443,36 +1476,43 @@ void RetainSummaryManager::InitializeClassMethodSummaries() { } void RetainSummaryManager::InitializeMethodSummaries() { - - assert (ScratchArgs.isEmpty()); - + + assert (ScratchArgs.isEmpty()); + // Create the "init" selector. It just acts as a pass-through for the // receiver. - addNSObjectMethSummary(GetNullarySelector("init", Ctx), - getPersistentSummary(ObjCInitRetE, DecRefMsg)); - + RetainSummary *InitSumm = getPersistentSummary(ObjCInitRetE, DecRefMsg); + addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm); + + // awakeAfterUsingCoder: behaves basically like an 'init' method. It + // claims the receiver and returns a retained object. + addNSObjectMethSummary(GetUnarySelector("awakeAfterUsingCoder", Ctx), + InitSumm); + // The next methods are allocators. - RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE); - - // Create the "copy" selector. - addNSObjectMethSummary(GetNullarySelector("copy", Ctx), AllocSumm); + RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE); + RetainSummary *CFAllocSumm = + getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true)); + + // Create the "copy" selector. + addNSObjectMethSummary(GetNullarySelector("copy", Ctx), AllocSumm); // Create the "mutableCopy" selector. addNSObjectMethSummary(GetNullarySelector("mutableCopy", Ctx), AllocSumm); - + // Create the "retain" selector. RetEffect E = RetEffect::MakeReceiverAlias(); RetainSummary *Summ = getPersistentSummary(E, IncRefMsg); addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ); - + // Create the "release" selector. Summ = getPersistentSummary(E, DecRefMsg); addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ); - + // Create the "drain" selector. Summ = getPersistentSummary(E, isGCEnabled() ? DoNothing : DecRef); addNSObjectMethSummary(GetNullarySelector("drain", Ctx), Summ); - + // Create the -dealloc summary. Summ = getPersistentSummary(RetEffect::MakeNoRet(), Dealloc); addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ); @@ -1480,13 +1520,13 @@ void RetainSummaryManager::InitializeMethodSummaries() { // Create the "autorelease" selector. Summ = getPersistentSummary(E, Autorelease); addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ); - + // Specially handle NSAutoreleasePool. addInstMethSummary("NSAutoreleasePool", "init", getPersistentSummary(RetEffect::MakeReceiverAlias(), NewAutoreleasePool)); - - // For NSWindow, allocated objects are (initially) self-owned. + + // For NSWindow, allocated objects are (initially) self-owned. // FIXME: For now we opt for false negatives with NSWindow, as these objects // self-own themselves. However, they only do this once they are displayed. // Thus, we need to track an NSWindow's display status. @@ -1495,42 +1535,42 @@ void RetainSummaryManager::InitializeMethodSummaries() { RetainSummary *NoTrackYet = getPersistentSummary(RetEffect::MakeNoRet(), StopTracking, StopTracking); - + addClassMethSummary("NSWindow", "alloc", NoTrackYet); #if 0 addInstMethSummary("NSWindow", NoTrackYet, "initWithContentRect", "styleMask", "backing", "defer", NULL); - + addInstMethSummary("NSWindow", NoTrackYet, "initWithContentRect", "styleMask", "backing", "defer", "screen", NULL); #endif - + // For NSPanel (which subclasses NSWindow), allocated objects are not // self-owned. // FIXME: For now we don't track NSPanels. object for the same reason // as for NSWindow objects. addClassMethSummary("NSPanel", "alloc", NoTrackYet); - + #if 0 addInstMethSummary("NSPanel", NoTrackYet, "initWithContentRect", "styleMask", "backing", "defer", NULL); - + addInstMethSummary("NSPanel", NoTrackYet, "initWithContentRect", "styleMask", "backing", "defer", "screen", NULL); #endif - + // Don't track allocated autorelease pools yet, as it is okay to prematurely // exit a method. addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet); // Create NSAssertionHandler summaries. addPanicSummary("NSAssertionHandler", "handleFailureInFunction", "file", - "lineNumber", "description", NULL); - + "lineNumber", "description", NULL); + addPanicSummary("NSAssertionHandler", "handleFailureInMethod", "object", "file", "lineNumber", "description", NULL); - + // Create summaries QCRenderer/QCView -createSnapShotImageOfType: addInstMethSummary("QCRenderer", AllocSumm, "createSnapshotImageOfType", NULL); @@ -1538,12 +1578,13 @@ void RetainSummaryManager::InitializeMethodSummaries() { "createSnapshotImageOfType", NULL); // Create summaries for CIContext, 'createCGImage' and - // 'createCGLayerWithSize'. - addInstMethSummary("CIContext", AllocSumm, + // 'createCGLayerWithSize'. These objects are CF objects, and are not + // automatically garbage collected. + addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect", NULL); - addInstMethSummary("CIContext", AllocSumm, - "createCGImage", "fromRect", "format", "colorSpace", NULL); - addInstMethSummary("CIContext", AllocSumm, "createCGLayerWithSize", + addInstMethSummary("CIContext", CFAllocSumm, + "createCGImage", "fromRect", "format", "colorSpace", NULL); + addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info", NULL); } @@ -1552,19 +1593,19 @@ void RetainSummaryManager::InitializeMethodSummaries() { //===----------------------------------------------------------------------===// namespace { - + class VISIBILITY_HIDDEN RefVal { -public: +public: enum Kind { - Owned = 0, // Owning reference. - NotOwned, // Reference is not owned by still valid (not freed). + Owned = 0, // Owning reference. + NotOwned, // Reference is not owned by still valid (not freed). Released, // Object has been released. ReturnedOwned, // Returned object passes ownership to caller. ReturnedNotOwned, // Return object does not pass ownership to caller. ERROR_START, ErrorDeallocNotOwned, // -dealloc called on non-owned object. ErrorDeallocGC, // Calling -dealloc with GC enabled. - ErrorUseAfterRelease, // Object used after released. + ErrorUseAfterRelease, // Object used after released. ErrorReleaseNotOwned, // Release of an object that was not owned. ERROR_LEAK_START, ErrorLeak, // A memory leak due to excessive reference counts. @@ -1575,7 +1616,7 @@ public: ErrorReturnedNotOwned }; -private: +private: Kind kind; RetEffect::ObjKind okind; unsigned Cnt; @@ -1588,9 +1629,9 @@ private: RefVal(Kind k, unsigned cnt = 0) : kind(k), okind(RetEffect::AnyObj), Cnt(cnt), ACnt(0) {} -public: +public: Kind getKind() const { return kind; } - + RetEffect::ObjKind getObjKind() const { return okind; } unsigned getCount() const { return Cnt; } @@ -1599,72 +1640,72 @@ public: void clearCounts() { Cnt = 0; ACnt = 0; } void setCount(unsigned i) { Cnt = i; } void setAutoreleaseCount(unsigned i) { ACnt = i; } - + QualType getType() const { return T; } - + // Useful predicates. - + static bool isError(Kind k) { return k >= ERROR_START; } - + static bool isLeak(Kind k) { return k >= ERROR_LEAK_START; } - + bool isOwned() const { return getKind() == Owned; } - + bool isNotOwned() const { return getKind() == NotOwned; } - + bool isReturnedOwned() const { return getKind() == ReturnedOwned; } - + bool isReturnedNotOwned() const { return getKind() == ReturnedNotOwned; } - + bool isNonLeakError() const { Kind k = getKind(); return isError(k) && !isLeak(k); } - + static RefVal makeOwned(RetEffect::ObjKind o, QualType t, unsigned Count = 1) { return RefVal(Owned, o, Count, 0, t); } - + static RefVal makeNotOwned(RetEffect::ObjKind o, QualType t, unsigned Count = 0) { return RefVal(NotOwned, o, Count, 0, t); } - + // Comparison, profiling, and pretty-printing. - + bool operator==(const RefVal& X) const { return kind == X.kind && Cnt == X.Cnt && T == X.T && ACnt == X.ACnt; } - + RefVal operator-(size_t i) const { return RefVal(getKind(), getObjKind(), getCount() - i, getAutoreleaseCount(), getType()); } - + RefVal operator+(size_t i) const { return RefVal(getKind(), getObjKind(), getCount() + i, getAutoreleaseCount(), getType()); } - + RefVal operator^(Kind k) const { return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(), getType()); } - + RefVal autorelease() const { return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1, getType()); } - + void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger((unsigned) kind); ID.AddInteger(Cnt); @@ -1674,41 +1715,41 @@ public: void print(llvm::raw_ostream& Out) const; }; - + void RefVal::print(llvm::raw_ostream& Out) const { if (!T.isNull()) Out << "Tracked Type:" << T.getAsString() << '\n'; - + switch (getKind()) { default: assert(false); - case Owned: { + case Owned: { Out << "Owned"; unsigned cnt = getCount(); if (cnt) Out << " (+ " << cnt << ")"; break; } - + case NotOwned: { Out << "NotOwned"; unsigned cnt = getCount(); if (cnt) Out << " (+ " << cnt << ")"; break; } - - case ReturnedOwned: { + + case ReturnedOwned: { Out << "ReturnedOwned"; unsigned cnt = getCount(); if (cnt) Out << " (+ " << cnt << ")"; break; } - + case ReturnedNotOwned: { Out << "ReturnedNotOwned"; unsigned cnt = getCount(); if (cnt) Out << " (+ " << cnt << ")"; break; } - + case Released: Out << "Released"; break; @@ -1716,19 +1757,19 @@ void RefVal::print(llvm::raw_ostream& Out) const { case ErrorDeallocGC: Out << "-dealloc (GC)"; break; - + case ErrorDeallocNotOwned: Out << "-dealloc (not-owned)"; break; - + case ErrorLeak: Out << "Leaked"; - break; - + break; + case ErrorLeakReturned: Out << "Leaked (Bad naming)"; break; - + case ErrorGCLeakReturned: Out << "Leaked (GC-ed at return)"; break; @@ -1736,38 +1777,38 @@ void RefVal::print(llvm::raw_ostream& Out) const { case ErrorUseAfterRelease: Out << "Use-After-Release [ERROR]"; break; - + case ErrorReleaseNotOwned: Out << "Release of Not-Owned [ERROR]"; break; - + case RefVal::ErrorOverAutorelease: Out << "Over autoreleased"; break; - + case RefVal::ErrorReturnedNotOwned: Out << "Non-owned object returned instead of owned"; break; } - + if (ACnt) { Out << " [ARC +" << ACnt << ']'; } } - + } // end anonymous namespace //===----------------------------------------------------------------------===// // RefBindings - State used to track object reference counts. //===----------------------------------------------------------------------===// - + typedef llvm::ImmutableMap RefBindings; static int RefBIndex = 0; namespace clang { template<> struct GRStateTrait : public GRStatePartialTrait { - static inline void* GDMIndex() { return &RefBIndex; } + static inline void* GDMIndex() { return &RefBIndex; } }; } @@ -1788,12 +1829,12 @@ namespace { class VISIBILITY_HIDDEN AutoreleaseStack {}; } namespace clang { template<> struct GRStateTrait : public GRStatePartialTrait { - static inline void* GDMIndex() { return &AutoRBIndex; } + static inline void* GDMIndex() { return &AutoRBIndex; } }; template<> struct GRStateTrait : public GRStatePartialTrait { - static inline void* GDMIndex() { return &AutoRCIndex; } + static inline void* GDMIndex() { return &AutoRCIndex; } }; } // end clang namespace @@ -1808,14 +1849,14 @@ static const GRState * SendAutorelease(const GRState *state, SymbolRef pool = GetCurrentAutoreleasePool(state); const ARCounts *cnts = state->get(pool); ARCounts newCnts(0); - + if (cnts) { const unsigned *cnt = (*cnts).lookup(sym); newCnts = F.Add(*cnts, sym, cnt ? *cnt + 1 : 1); } else newCnts = F.Add(F.GetEmptyMap(), sym, 1); - + return state->set(pool, newCnts); } @@ -1824,7 +1865,7 @@ static const GRState * SendAutorelease(const GRState *state, //===----------------------------------------------------------------------===// namespace { - + class VISIBILITY_HIDDEN CFRefCount : public GRTransferFuncs { public: class BindingsPrinter : public GRState::Printer { @@ -1834,10 +1875,10 @@ public: }; private: - typedef llvm::DenseMap - SummaryLogTy; + typedef llvm::DenseMap + SummaryLogTy; - RetainSummaryManager Summaries; + RetainSummaryManager Summaries; SummaryLogTy SummaryLog; const LangOptions& LOpts; ARCounts::Factory ARCountFactory; @@ -1848,106 +1889,106 @@ private: BugType *overAutorelease; BugType *returnNotOwnedForOwned; BugReporter *BR; - + const GRState * Update(const GRState * state, SymbolRef sym, RefVal V, ArgEffect E, RefVal::Kind& hasErr); - void ProcessNonLeakError(ExplodedNodeSet& Dst, - GRStmtNodeBuilder& Builder, + void ProcessNonLeakError(ExplodedNodeSet& Dst, + GRStmtNodeBuilder& Builder, Expr* NodeExpr, Expr* ErrorExpr, - ExplodedNode* Pred, + ExplodedNode* Pred, const GRState* St, RefVal::Kind hasErr, SymbolRef Sym); - + const GRState * HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V, llvm::SmallVectorImpl &Leaked); - - ExplodedNode* ProcessLeaks(const GRState * state, + + ExplodedNode* ProcessLeaks(const GRState * state, llvm::SmallVectorImpl &Leaked, GenericNodeBuilder &Builder, GRExprEngine &Eng, - ExplodedNode *Pred = 0); - -public: + ExplodedNode *Pred = 0); + +public: CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts) : Summaries(Ctx, gcenabled), LOpts(lopts), useAfterRelease(0), releaseNotOwned(0), deallocGC(0), deallocNotOwned(0), leakWithinFunction(0), leakAtReturn(0), overAutorelease(0), returnNotOwnedForOwned(0), BR(0) {} - + virtual ~CFRefCount() {} - + void RegisterChecks(BugReporter &BR); - + virtual void RegisterPrinters(std::vector& Printers) { Printers.push_back(new BindingsPrinter()); } - + bool isGCEnabled() const { return Summaries.isGCEnabled(); } const LangOptions& getLangOptions() const { return LOpts; } - - const RetainSummary *getSummaryOfNode(const ExplodedNode *N) const { + + const RetainSummary *getSummaryOfNode(const ExplodedNode *N) const { SummaryLogTy::const_iterator I = SummaryLog.find(N); return I == SummaryLog.end() ? 0 : I->second; } - + // Calls. - void EvalSummary(ExplodedNodeSet& Dst, + void EvalSummary(ExplodedNodeSet& Dst, GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, Expr* Ex, Expr* Receiver, const RetainSummary& Summ, ExprIterator arg_beg, ExprIterator arg_end, - ExplodedNode* Pred); - - virtual void EvalCall(ExplodedNodeSet& Dst, + ExplodedNode* Pred); + + virtual void EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, - ExplodedNode* Pred); - - - virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst, + ExplodedNode* Pred); + + + virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, - ExplodedNode* Pred); - - bool EvalObjCMessageExprAux(ExplodedNodeSet& Dst, + ExplodedNode* Pred); + + bool EvalObjCMessageExprAux(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, - ExplodedNode* Pred); + ExplodedNode* Pred); - // Stores. + // Stores. virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val); // End-of-path. - + virtual void EvalEndPath(GRExprEngine& Engine, - GREndPathNodeBuilder& Builder); - - virtual void EvalDeadSymbols(ExplodedNodeSet& Dst, + GREndPathNodeBuilder& Builder); + + virtual void EvalDeadSymbols(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - ExplodedNode* Pred, + GRStmtNodeBuilder& Builder, + ExplodedNode* Pred, Stmt* S, const GRState* state, SymbolReaper& SymReaper); - - std::pair*, const GRState *> + + std::pair HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd, - ExplodedNode* Pred, GRExprEngine &Eng, + ExplodedNode* Pred, GRExprEngine &Eng, SymbolRef Sym, RefVal V, bool &stop); // Return statements. - - virtual void EvalReturn(ExplodedNodeSet& Dst, + + virtual void EvalReturn(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, ReturnStmt* S, - ExplodedNode* Pred); + ExplodedNode* Pred); // Assumptions. @@ -1965,34 +2006,34 @@ static void PrintPool(llvm::raw_ostream &Out, SymbolRef Sym, else Out << ""; Out << ":{"; - + // Get the contents of the pool. if (const ARCounts *cnts = state->get(Sym)) for (ARCounts::iterator J=cnts->begin(), EJ=cnts->end(); J != EJ; ++J) Out << '(' << J.getKey() << ',' << J.getData() << ')'; - Out << '}'; + Out << '}'; } void CFRefCount::BindingsPrinter::Print(llvm::raw_ostream& Out, const GRState* state, const char* nl, const char* sep) { - + RefBindings B = state->get(); - + if (!B.isEmpty()) Out << sep << nl; - + for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) { Out << (*I).first << " : "; (*I).second.print(Out); Out << nl; } - + // Print the autorelease stack. Out << sep << nl << "AR pool stack:"; ARStack stack = state->get(); - + PrintPool(Out, SymbolRef(), state); // Print the caller's pool. for (ARStack::iterator I=stack.begin(), E=stack.end(); I!=E; ++I) PrintPool(Out, *I, state); @@ -2005,157 +2046,155 @@ void CFRefCount::BindingsPrinter::Print(llvm::raw_ostream& Out, //===----------------------------------------------------------------------===// namespace { - + //===-------------===// // Bug Descriptions. // - //===-------------===// - + //===-------------===// + class VISIBILITY_HIDDEN CFRefBug : public BugType { protected: CFRefCount& TF; - - CFRefBug(CFRefCount* tf, const char* name) - : BugType(name, "Memory (Core Foundation/Objective-C)"), TF(*tf) {} + + CFRefBug(CFRefCount* tf, const char* name) + : BugType(name, "Memory (Core Foundation/Objective-C)"), TF(*tf) {} public: - + CFRefCount& getTF() { return TF; } const CFRefCount& getTF() const { return TF; } - + // FIXME: Eventually remove. virtual const char* getDescription() const = 0; - + virtual bool isLeak() const { return false; } }; - + class VISIBILITY_HIDDEN UseAfterRelease : public CFRefBug { public: UseAfterRelease(CFRefCount* tf) : CFRefBug(tf, "Use-after-release") {} - + const char* getDescription() const { return "Reference-counted object is used after it is released"; - } + } }; - + class VISIBILITY_HIDDEN BadRelease : public CFRefBug { public: BadRelease(CFRefCount* tf) : CFRefBug(tf, "Bad release") {} - + const char* getDescription() const { - return "Incorrect decrement of the reference count of an " - "object is not owned at this point by the caller"; + return "Incorrect decrement of the reference count of an object that is " + "not owned at this point by the caller"; } }; - + class VISIBILITY_HIDDEN DeallocGC : public CFRefBug { public: DeallocGC(CFRefCount *tf) : CFRefBug(tf, "-dealloc called while using garbage collection") {} - + const char *getDescription() const { return "-dealloc called while using garbage collection"; } }; - + class VISIBILITY_HIDDEN DeallocNotOwned : public CFRefBug { public: DeallocNotOwned(CFRefCount *tf) : CFRefBug(tf, "-dealloc sent to non-exclusively owned object") {} - + const char *getDescription() const { return "-dealloc sent to object that may be referenced elsewhere"; } - }; - + }; + class VISIBILITY_HIDDEN OverAutorelease : public CFRefBug { public: - OverAutorelease(CFRefCount *tf) : + OverAutorelease(CFRefCount *tf) : CFRefBug(tf, "Object sent -autorelease too many times") {} - + const char *getDescription() const { return "Object sent -autorelease too many times"; } }; - + class VISIBILITY_HIDDEN ReturnedNotOwnedForOwned : public CFRefBug { public: ReturnedNotOwnedForOwned(CFRefCount *tf) : CFRefBug(tf, "Method should return an owned object") {} - + const char *getDescription() const { return "Object with +0 retain counts returned to caller where a +1 " "(owning) retain count is expected"; } }; - + class VISIBILITY_HIDDEN Leak : public CFRefBug { const bool isReturn; protected: Leak(CFRefCount* tf, const char* name, bool isRet) : CFRefBug(tf, name), isReturn(isRet) {} public: - + const char* getDescription() const { return ""; } - + bool isLeak() const { return true; } }; - + class VISIBILITY_HIDDEN LeakAtReturn : public Leak { public: LeakAtReturn(CFRefCount* tf, const char* name) : Leak(tf, name, true) {} }; - + class VISIBILITY_HIDDEN LeakWithinFunction : public Leak { public: LeakWithinFunction(CFRefCount* tf, const char* name) : Leak(tf, name, false) {} - }; - + }; + //===---------===// // Bug Reports. // //===---------===// - + class VISIBILITY_HIDDEN CFRefReport : public RangedBugReport { protected: SymbolRef Sym; const CFRefCount &TF; public: CFRefReport(CFRefBug& D, const CFRefCount &tf, - ExplodedNode *n, SymbolRef sym) + ExplodedNode *n, SymbolRef sym) : RangedBugReport(D, D.getDescription(), n), Sym(sym), TF(tf) {} CFRefReport(CFRefBug& D, const CFRefCount &tf, - ExplodedNode *n, SymbolRef sym, const char* endText) + ExplodedNode *n, SymbolRef sym, const char* endText) : RangedBugReport(D, D.getDescription(), endText, n), Sym(sym), TF(tf) {} - + virtual ~CFRefReport() {} - + CFRefBug& getBugType() { return (CFRefBug&) RangedBugReport::getBugType(); } const CFRefBug& getBugType() const { return (const CFRefBug&) RangedBugReport::getBugType(); } - - virtual void getRanges(BugReporter& BR, const SourceRange*& beg, - const SourceRange*& end) { - + + virtual void getRanges(const SourceRange*& beg, const SourceRange*& end) { if (!getBugType().isLeak()) - RangedBugReport::getRanges(BR, beg, end); + RangedBugReport::getRanges(beg, end); else beg = end = 0; } - + SymbolRef getSymbol() const { return Sym; } - + PathDiagnosticPiece* getEndPath(BugReporterContext& BRC, - const ExplodedNode* N); - + const ExplodedNode* N); + std::pair getExtraDescriptiveText(); - - PathDiagnosticPiece* VisitNode(const ExplodedNode* N, - const ExplodedNode* PrevN, + + PathDiagnosticPiece* VisitNode(const ExplodedNode* N, + const ExplodedNode* PrevN, BugReporterContext& BRC); }; @@ -2164,38 +2203,38 @@ namespace { const MemRegion* AllocBinding; public: CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, - ExplodedNode *n, SymbolRef sym, + ExplodedNode *n, SymbolRef sym, GRExprEngine& Eng); - + PathDiagnosticPiece* getEndPath(BugReporterContext& BRC, - const ExplodedNode* N); - + const ExplodedNode* N); + SourceLocation getLocation() const { return AllocSite; } - }; + }; } // end anonymous namespace void CFRefCount::RegisterChecks(BugReporter& BR) { useAfterRelease = new UseAfterRelease(this); BR.Register(useAfterRelease); - + releaseNotOwned = new BadRelease(this); BR.Register(releaseNotOwned); - + deallocGC = new DeallocGC(this); BR.Register(deallocGC); - + deallocNotOwned = new DeallocNotOwned(this); BR.Register(deallocNotOwned); - + overAutorelease = new OverAutorelease(this); BR.Register(overAutorelease); - + returnNotOwnedForOwned = new ReturnedNotOwnedForOwned(this); BR.Register(returnNotOwnedForOwned); - + // First register "return" leaks. const char* name = 0; - + if (isGCEnabled()) name = "Leak of returned object when using garbage collection"; else if (getLangOptions().getGCMode() == LangOptions::HybridGC) @@ -2205,13 +2244,15 @@ void CFRefCount::RegisterChecks(BugReporter& BR) { assert(getLangOptions().getGCMode() == LangOptions::NonGC); name = "Leak of returned object"; } - + + // Leaks should not be reported if they are post-dominated by a sink. leakAtReturn = new LeakAtReturn(this, name); + leakAtReturn->setSuppressOnSink(true); BR.Register(leakAtReturn); - + // Second, register leaks within a function/method. if (isGCEnabled()) - name = "Leak of object when using garbage collection"; + name = "Leak of object when using garbage collection"; else if (getLangOptions().getGCMode() == LangOptions::HybridGC) name = "Leak of object when not using garbage collection (GC) in " "dual GC/non-GC code"; @@ -2219,22 +2260,24 @@ void CFRefCount::RegisterChecks(BugReporter& BR) { assert(getLangOptions().getGCMode() == LangOptions::NonGC); name = "Leak"; } - + + // Leaks should not be reported if they are post-dominated by sinks. leakWithinFunction = new LeakWithinFunction(this, name); + leakWithinFunction->setSuppressOnSink(true); BR.Register(leakWithinFunction); - + // Save the reference to the BugReporter. this->BR = &BR; } static const char* Msgs[] = { // GC only - "Code is compiled to only use garbage collection", + "Code is compiled to only use garbage collection", // No GC. "Code is compiled to use reference counts", // Hybrid, with GC. "Code is compiled to use either garbage collection (GC) or reference counts" - " (non-GC). The bug occurs with GC enabled", + " (non-GC). The bug occurs with GC enabled", // Hybrid, without GC "Code is compiled to use either garbage collection (GC) or reference counts" " (non-GC). The bug occurs in non-GC mode" @@ -2242,19 +2285,19 @@ static const char* Msgs[] = { std::pair CFRefReport::getExtraDescriptiveText() { CFRefCount& TF = static_cast(getBugType()).getTF(); - + switch (TF.getLangOptions().getGCMode()) { default: assert(false); - + case LangOptions::GCOnly: assert (TF.isGCEnabled()); - return std::make_pair(&Msgs[0], &Msgs[0]+1); - + return std::make_pair(&Msgs[0], &Msgs[0]+1); + case LangOptions::NonGC: assert (!TF.isGCEnabled()); return std::make_pair(&Msgs[1], &Msgs[1]+1); - + case LangOptions::HybridGC: if (TF.isGCEnabled()) return std::make_pair(&Msgs[2], &Msgs[2]+1); @@ -2268,50 +2311,50 @@ static inline bool contains(const llvm::SmallVectorImpl& V, for (llvm::SmallVectorImpl::const_iterator I=V.begin(), E=V.end(); I!=E; ++I) if (*I == X) return true; - + return false; } -PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, - const ExplodedNode* PrevN, +PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, + const ExplodedNode* PrevN, BugReporterContext& BRC) { - + if (!isa(N->getLocation())) return NULL; - + // Check if the type state has changed. const GRState *PrevSt = PrevN->getState(); const GRState *CurrSt = N->getState(); - - const RefVal* CurrT = CurrSt->get(Sym); + + const RefVal* CurrT = CurrSt->get(Sym); if (!CurrT) return NULL; - + const RefVal &CurrV = *CurrT; const RefVal *PrevT = PrevSt->get(Sym); - + // Create a string buffer to constain all the useful things we want // to tell the user. std::string sbuf; llvm::raw_string_ostream os(sbuf); - + // This is the allocation site since the previous node had no bindings // for this symbol. if (!PrevT) { - Stmt* S = cast(N->getLocation()).getStmt(); - - if (CallExpr *CE = dyn_cast(S)) { + const Stmt* S = cast(N->getLocation()).getStmt(); + + if (const CallExpr *CE = dyn_cast(S)) { // Get the name of the callee (if it is available). SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee()); if (const FunctionDecl* FD = X.getAsFunctionDecl()) os << "Call to function '" << FD->getNameAsString() <<'\''; else - os << "function call"; - } + os << "function call"; + } else { assert (isa(S)); os << "Method"; } - + if (CurrV.getObjKind() == RetEffect::CF) { os << " returns a Core Foundation object with a "; } @@ -2319,10 +2362,10 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, assert (CurrV.getObjKind() == RetEffect::ObjC); os << " returns an Objective-C object with a "; } - + if (CurrV.isOwned()) { os << "+1 retain count (owning reference)."; - + if (static_cast(getBugType()).getTF().isGCEnabled()) { assert(CurrV.getObjKind() == RetEffect::CF); os << " " @@ -2333,51 +2376,51 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, assert (CurrV.isNotOwned()); os << "+0 retain count (non-owning reference)."; } - + PathDiagnosticLocation Pos(S, BRC.getSourceManager()); return new PathDiagnosticEventPiece(Pos, os.str()); } - + // Gather up the effects that were performed on the object at this // program point llvm::SmallVector AEffects; - + if (const RetainSummary *Summ = TF.getSummaryOfNode(BRC.getNodeResolver().getOriginalNode(N))) { // We only have summaries attached to nodes after evaluating CallExpr and // ObjCMessageExprs. - Stmt* S = cast(N->getLocation()).getStmt(); - - if (CallExpr *CE = dyn_cast(S)) { + const Stmt* S = cast(N->getLocation()).getStmt(); + + if (const CallExpr *CE = dyn_cast(S)) { // Iterate through the parameter expressions and see if the symbol // was ever passed as an argument. unsigned i = 0; - - for (CallExpr::arg_iterator AI=CE->arg_begin(), AE=CE->arg_end(); + + for (CallExpr::const_arg_iterator AI=CE->arg_begin(), AE=CE->arg_end(); AI!=AE; ++AI, ++i) { - + // Retrieve the value of the argument. Is it the symbol // we are interested in? if (CurrSt->getSValAsScalarOrLoc(*AI).getAsLocSymbol() != Sym) continue; - + // We have an argument. Get the effect! AEffects.push_back(Summ->getArg(i)); } } - else if (ObjCMessageExpr *ME = dyn_cast(S)) { - if (Expr *receiver = ME->getReceiver()) + else if (const ObjCMessageExpr *ME = dyn_cast(S)) { + if (const Expr *receiver = ME->getReceiver()) if (CurrSt->getSValAsScalarOrLoc(receiver).getAsLocSymbol() == Sym) { // The symbol we are tracking is the receiver. AEffects.push_back(Summ->getReceiverEffect()); } } } - + do { // Get the previous type state. RefVal PrevV = *PrevT; - + // Specially handle -dealloc. if (!TF.isGCEnabled() && contains(AEffects, Dealloc)) { // Determine if the object's reference count was pushed to zero. @@ -2390,23 +2433,23 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, break; } } - + // Specially handle CFMakeCollectable and friends. if (contains(AEffects, MakeCollectable)) { // Get the name of the function. - Stmt* S = cast(N->getLocation()).getStmt(); + const Stmt* S = cast(N->getLocation()).getStmt(); SVal X = CurrSt->getSValAsScalarOrLoc(cast(S)->getCallee()); const FunctionDecl* FD = X.getAsFunctionDecl(); const std::string& FName = FD->getNameAsString(); - + if (TF.isGCEnabled()) { // Determine if the object's reference count was pushed to zero. assert(!(PrevV == CurrV) && "The typestate *must* have changed."); - + os << "In GC mode a call to '" << FName << "' decrements an object's retain count and registers the " "object with the garbage collector. "; - + if (CurrV.getKind() == RefVal::Released) { assert(CurrV.getCount() == 0); os << "Since it now has a 0 retain count the object can be " @@ -2417,67 +2460,67 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, "After this call its retain count is +" << CurrV.getCount() << '.'; } - else + else os << "When GC is not enabled a call to '" << FName << "' has no effect on its argument."; - + // Nothing more to say. break; } - - // Determine if the typestate has changed. + + // Determine if the typestate has changed. if (!(PrevV == CurrV)) switch (CurrV.getKind()) { case RefVal::Owned: case RefVal::NotOwned: - + if (PrevV.getCount() == CurrV.getCount()) { // Did an autorelease message get sent? if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount()) return 0; - + assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount()); os << "Object sent -autorelease message"; break; } - + if (PrevV.getCount() > CurrV.getCount()) os << "Reference count decremented."; else os << "Reference count incremented."; - + if (unsigned Count = CurrV.getCount()) os << " The object now has a +" << Count << " retain count."; - + if (PrevV.getKind() == RefVal::Released) { assert(TF.isGCEnabled() && CurrV.getCount() > 0); os << " The object is not eligible for garbage collection until the " "retain count reaches 0 again."; } - + break; - + case RefVal::Released: os << "Object released."; break; - + case RefVal::ReturnedOwned: os << "Object returned to caller as an owning reference (single retain " "count transferred to caller)."; break; - + case RefVal::ReturnedNotOwned: os << "Object returned to caller with a +0 (non-owning) retain count."; break; - + default: return NULL; } - + // Emit any remaining diagnostics for the argument effects (if any). for (llvm::SmallVectorImpl::iterator I=AEffects.begin(), E=AEffects.end(); I != E; ++I) { - + // A bunch of things have alternate behavior under GC. if (TF.isGCEnabled()) switch (*I) { @@ -2493,24 +2536,25 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, continue; } } - } while(0); - + } while (0); + if (os.str().empty()) return 0; // We have nothing to say! - Stmt* S = cast(N->getLocation()).getStmt(); + const Stmt* S = cast(N->getLocation()).getStmt(); PathDiagnosticLocation Pos(S, BRC.getSourceManager()); PathDiagnosticPiece* P = new PathDiagnosticEventPiece(Pos, os.str()); - + // Add the range by scanning the children of the statement for any bindings // to Sym. - for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I) - if (Expr* Exp = dyn_cast_or_null(*I)) + for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); + I!=E; ++I) + if (const Expr* Exp = dyn_cast_or_null(*I)) if (CurrSt->getSValAsScalarOrLoc(Exp).getAsLocSymbol() == Sym) { P->addRange(Exp->getSourceRange()); break; } - + return P; } @@ -2520,62 +2564,62 @@ namespace { SymbolRef Sym; const MemRegion* Binding; bool First; - + public: FindUniqueBinding(SymbolRef sym) : Sym(sym), Binding(0), First(true) {} - + bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R, SVal val) { - - SymbolRef SymV = val.getAsSymbol(); + + SymbolRef SymV = val.getAsSymbol(); if (!SymV || SymV != Sym) return true; - + if (Binding) { First = false; return false; } else Binding = R; - - return true; + + return true; } - + operator bool() { return First && Binding; } const MemRegion* getRegion() { return Binding; } - }; + }; } -static std::pair*,const MemRegion*> -GetAllocationSite(GRStateManager& StateMgr, const ExplodedNode* N, +static std::pair +GetAllocationSite(GRStateManager& StateMgr, const ExplodedNode* N, SymbolRef Sym) { - + // Find both first node that referred to the tracked symbol and the // memory location that value was store to. - const ExplodedNode* Last = N; - const MemRegion* FirstBinding = 0; - + const ExplodedNode* Last = N; + const MemRegion* FirstBinding = 0; + while (N) { const GRState* St = N->getState(); RefBindings B = St->get(); - + if (!B.lookup(Sym)) break; - + FindUniqueBinding FB(Sym); - StateMgr.iterBindings(St, FB); - if (FB) FirstBinding = FB.getRegion(); - + StateMgr.iterBindings(St, FB); + if (FB) FirstBinding = FB.getRegion(); + Last = N; - N = N->pred_empty() ? NULL : *(N->pred_begin()); + N = N->pred_empty() ? NULL : *(N->pred_begin()); } - + return std::make_pair(Last, FirstBinding); } PathDiagnosticPiece* CFRefReport::getEndPath(BugReporterContext& BRC, - const ExplodedNode* EndN) { + const ExplodedNode* EndN) { // Tell the BugReporterContext to report cases when the tracked symbol is // assigned to different variables, etc. BRC.addNotableSymbol(Sym); @@ -2584,37 +2628,37 @@ CFRefReport::getEndPath(BugReporterContext& BRC, PathDiagnosticPiece* CFRefLeakReport::getEndPath(BugReporterContext& BRC, - const ExplodedNode* EndN){ - + const ExplodedNode* EndN){ + // Tell the BugReporterContext to report cases when the tracked symbol is // assigned to different variables, etc. BRC.addNotableSymbol(Sym); - + // We are reporting a leak. Walk up the graph to get to the first node where // the symbol appeared, and also get the first VarDecl that tracked object // is stored to. - const ExplodedNode* AllocNode = 0; + const ExplodedNode* AllocNode = 0; const MemRegion* FirstBinding = 0; - + llvm::tie(AllocNode, FirstBinding) = GetAllocationSite(BRC.getStateManager(), EndN, Sym); - - // Get the allocate site. + + // Get the allocate site. assert(AllocNode); - Stmt* FirstStmt = cast(AllocNode->getLocation()).getStmt(); - + const Stmt* FirstStmt = cast(AllocNode->getLocation()).getStmt(); + SourceManager& SMgr = BRC.getSourceManager(); unsigned AllocLine =SMgr.getInstantiationLineNumber(FirstStmt->getLocStart()); - + // Compute an actual location for the leak. Sometimes a leak doesn't // occur at an actual statement (e.g., transition between blocks; end // of function) so we need to walk the graph and compute a real location. - const ExplodedNode* LeakN = EndN; + const ExplodedNode* LeakN = EndN; PathDiagnosticLocation L; - + while (LeakN) { ProgramPoint P = LeakN->getLocation(); - + if (const PostStmt *PS = dyn_cast(&P)) { L = PathDiagnosticLocation(PS->getStmt()->getLocStart(), SMgr); break; @@ -2625,31 +2669,31 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC, break; } } - + LeakN = LeakN->succ_empty() ? 0 : *(LeakN->succ_begin()); } - + if (!L.isValid()) { - const Decl &D = BRC.getCodeDecl(); + const Decl &D = EndN->getCodeDecl(); L = PathDiagnosticLocation(D.getBodyRBrace(), SMgr); } - + std::string sbuf; llvm::raw_string_ostream os(sbuf); - + os << "Object allocated on line " << AllocLine; - + if (FirstBinding) - os << " and stored into '" << FirstBinding->getString() << '\''; - + os << " and stored into '" << FirstBinding->getString() << '\''; + // Get the retain count. const RefVal* RV = EndN->getState()->get(Sym); - + if (RV->getKind() == RefVal::ErrorLeakReturned) { // FIXME: Per comments in rdar://6320065, "create" only applies to CF // ojbects. Only "copy", "alloc", "retain" and "new" transfer ownership // to the caller for NS objects. - ObjCMethodDecl& MD = cast(BRC.getCodeDecl()); + ObjCMethodDecl& MD = cast(EndN->getCodeDecl()); os << " is returned from a method whose name ('" << MD.getSelector().getAsString() << "') does not contain 'copy' or otherwise starts with" @@ -2657,7 +2701,7 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC, " in the Memory Management Guide for Cocoa (object leaked)"; } else if (RV->getKind() == RefVal::ErrorGCLeakReturned) { - ObjCMethodDecl& MD = cast(BRC.getCodeDecl()); + ObjCMethodDecl& MD = cast(EndN->getCodeDecl()); os << " and returned from method '" << MD.getSelector().getAsString() << "' is potentially leaked when using garbage collection. Callers " "of this method do not expect a returned object with a +1 retain " @@ -2667,16 +2711,15 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC, else os << " is no longer referenced after this point and has a retain count of" " +" << RV->getCount() << " (object leaked)"; - + return new PathDiagnosticEventPiece(L, os.str()); } CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, - ExplodedNode *n, + ExplodedNode *n, SymbolRef sym, GRExprEngine& Eng) -: CFRefReport(D, tf, n, sym) -{ - +: CFRefReport(D, tf, n, sym) { + // Most bug reports are cached at the location where they occured. // With leaks, we want to unique them by the location where they were // allocated, and only report a single path. To do this, we need to find @@ -2685,15 +2728,15 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, // Note that this is *not* the trimmed graph; we are guaranteed, however, // that all ancestor nodes that represent the allocation site have the // same SourceLocation. - const ExplodedNode* AllocNode = 0; - + const ExplodedNode* AllocNode = 0; + llvm::tie(AllocNode, AllocBinding) = // Set AllocBinding. GetAllocationSite(Eng.getStateManager(), getEndNode(), getSymbol()); - + // Get the SourceLocation for the allocation site. ProgramPoint P = AllocNode->getLocation(); AllocSite = cast(P).getStmt()->getLocStart(); - + // Fill in the description of the bug. Description.clear(); llvm::raw_string_ostream os(Description); @@ -2702,9 +2745,9 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, os << "Potential leak "; if (tf.isGCEnabled()) { os << "(when using garbage collection) "; - } + } os << "of an object allocated on line " << AllocLine; - + // FIXME: AllocBinding doesn't get populated for RegionStore yet. if (AllocBinding) os << " and stored into '" << AllocBinding->getString() << '\''; @@ -2719,57 +2762,46 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, /// While the the return type can be queried directly from RetEx, when /// invoking class methods we augment to the return type to be that of /// a pointer to the class (as opposed it just being id). -static QualType GetReturnType(Expr* RetE, ASTContext& Ctx) { - +static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) { QualType RetTy = RetE->getType(); - - // FIXME: We aren't handling id<...>. - const PointerType* PT = RetTy->getAsPointerType(); - if (!PT) - return RetTy; - - // If RetEx is not a message expression just return its type. - // If RetEx is a message expression, return its types if it is something + // If RetE is not a message expression just return its type. + // If RetE is a message expression, return its types if it is something /// more specific than id. - - ObjCMessageExpr* ME = dyn_cast(RetE); - - if (!ME || !Ctx.isObjCIdStructType(PT->getPointeeType())) - return RetTy; - - ObjCInterfaceDecl* D = ME->getClassInfo().first; - - // At this point we know the return type of the message expression is id. - // If we have an ObjCInterceDecl, we know this is a call to a class method - // whose type we can resolve. In such cases, promote the return type to - // Class*. - return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D)); -} + if (const ObjCMessageExpr *ME = dyn_cast(RetE)) + if (const ObjCObjectPointerType *PT = RetTy->getAs()) + if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() || + PT->isObjCClassType()) { + // At this point we know the return type of the message expression is + // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this + // is a call to a class method whose type we can resolve. In such + // cases, promote the return type to XXX* (where XXX is the class). + const ObjCInterfaceDecl *D = ME->getClassInfo().first; + return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D)); + } + return RetTy; +} -void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, +void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, Expr* Ex, Expr* Receiver, const RetainSummary& Summ, ExprIterator arg_beg, ExprIterator arg_end, - ExplodedNode* Pred) { - + ExplodedNode* Pred) { + // Get the state. - GRStateManager& StateMgr = Eng.getStateManager(); const GRState *state = Builder.GetState(Pred); - ASTContext& Ctx = StateMgr.getContext(); - ValueManager &ValMgr = Eng.getValueManager(); // Evaluate the effect of the arguments. RefVal::Kind hasErr = (RefVal::Kind) 0; unsigned idx = 0; Expr* ErrorExpr = NULL; - SymbolRef ErrorSym = 0; - - for (ExprIterator I = arg_beg; I != arg_end; ++I, ++idx) { - SVal V = state->getSValAsScalarOrLoc(*I); + SymbolRef ErrorSym = 0; + + for (ExprIterator I = arg_beg; I != arg_end; ++I, ++idx) { + SVal V = state->getSValAsScalarOrLoc(*I); SymbolRef Sym = V.getAsLocSymbol(); if (Sym) @@ -2779,143 +2811,76 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, ErrorExpr = *I; ErrorSym = Sym; break; - } + } continue; } + tryAgain: if (isa(V)) { if (loc::MemRegionVal* MR = dyn_cast(&V)) { if (Summ.getArg(idx) == DoNothingByRef) continue; - - // Invalidate the value of the variable passed by reference. - + + // Invalidate the value of the variable passed by reference. + // FIXME: We can have collisions on the conjured symbol if the // expression *I also creates conjured symbols. We probably want // to identify conjured symbols by an expression pair: the enclosing // expression (the context) and the expression itself. This should - // disambiguate conjured symbols. + // disambiguate conjured symbols. unsigned Count = Builder.getCurrentBlockCount(); - const TypedRegion* R = dyn_cast(MR->getRegion()); - - if (R) { - // Are we dealing with an ElementRegion? If the element type is - // a basic integer type (e.g., char, int) and the underying region - // is a variable region then strip off the ElementRegion. - // FIXME: We really need to think about this for the general case - // as sometimes we are reasoning about arrays and other times - // about (char*), etc., is just a form of passing raw bytes. - // e.g., void *p = alloca(); foo((char*)p); - if (const ElementRegion *ER = dyn_cast(R)) { - // Checking for 'integral type' is probably too promiscuous, but - // we'll leave it in for now until we have a systematic way of - // handling all of these cases. Eventually we need to come up - // with an interface to StoreManager so that this logic can be - // approriately delegated to the respective StoreManagers while - // still allowing us to do checker-specific logic (e.g., - // invalidating reference counts), probably via callbacks. - if (ER->getElementType()->isIntegralType()) { - const MemRegion *superReg = ER->getSuperRegion(); - if (isa(superReg) || isa(superReg) || - isa(superReg)) - R = cast(superReg); - } - - // FIXME: What about layers of ElementRegions? - } - - // Is the invalidated variable something that we were tracking? - SymbolRef Sym = state->getSValAsScalarOrLoc(R).getAsLocSymbol(); - - // Remove any existing reference-count binding. - if (Sym) state = state->remove(Sym); - - if (R->isBoundable()) { - // Set the value of the variable to be a conjured symbol. - - QualType T = R->getValueType(Ctx); - - if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())){ - ValueManager &ValMgr = Eng.getValueManager(); - SVal V = ValMgr.getConjuredSymbolVal(*I, T, Count); - state = state->bindLoc(ValMgr.makeLoc(R), V); - } - else if (const RecordType *RT = T->getAsStructureType()) { - // Handle structs in a not so awesome way. Here we just - // eagerly bind new symbols to the fields. In reality we - // should have the store manager handle this. The idea is just - // to prototype some basic functionality here. All of this logic - // should one day soon just go away. - const RecordDecl *RD = RT->getDecl()->getDefinition(Ctx); - - // No record definition. There is nothing we can do. - if (!RD) - continue; - - MemRegionManager &MRMgr = - state->getStateManager().getRegionManager(); - - // Iterate through the fields and construct new symbols. - for (RecordDecl::field_iterator FI=RD->field_begin(), - FE=RD->field_end(); FI!=FE; ++FI) { - - // For now just handle scalar fields. - FieldDecl *FD = *FI; - QualType FT = FD->getType(); - const FieldRegion* FR = MRMgr.getFieldRegion(FD, R); - - if (Loc::IsLocType(FT) || - (FT->isIntegerType() && FT->isScalarType())) { - SVal V = ValMgr.getConjuredSymbolVal(*I, FT, Count); - state = state->bindLoc(ValMgr.makeLoc(FR), V); - } - else if (FT->isStructureType()) { - // set the default value of the struct field to conjured - // symbol. Note that the type of the symbol is irrelavant. - // We cannot use the type of the struct otherwise ValMgr won't - // give us the conjured symbol. - StoreManager& StoreMgr = - Eng.getStateManager().getStoreManager(); - SVal V = ValMgr.getConjuredSymbolVal(*I, - Eng.getContext().IntTy, - Count); - state = StoreMgr.setDefaultValue(state, FR, V); - } - } - } else if (const ArrayType *AT = Ctx.getAsArrayType(T)) { - // Set the default value of the array to conjured symbol. - StoreManager& StoreMgr = Eng.getStateManager().getStoreManager(); - SVal V = ValMgr.getConjuredSymbolVal(*I, AT->getElementType(), - Count); - state = StoreMgr.setDefaultValue(state, R, V); - } else { - // Just blast away other values. - state = state->bindLoc(*MR, UnknownVal()); - } + StoreManager& StoreMgr = Eng.getStateManager().getStoreManager(); + + const MemRegion *R = MR->getRegion(); + // Are we dealing with an ElementRegion? If the element type is + // a basic integer type (e.g., char, int) and the underying region + // is a variable region then strip off the ElementRegion. + // FIXME: We really need to think about this for the general case + // as sometimes we are reasoning about arrays and other times + // about (char*), etc., is just a form of passing raw bytes. + // e.g., void *p = alloca(); foo((char*)p); + if (const ElementRegion *ER = dyn_cast(R)) { + // Checking for 'integral type' is probably too promiscuous, but + // we'll leave it in for now until we have a systematic way of + // handling all of these cases. Eventually we need to come up + // with an interface to StoreManager so that this logic can be + // approriately delegated to the respective StoreManagers while + // still allowing us to do checker-specific logic (e.g., + // invalidating reference counts), probably via callbacks. + if (ER->getElementType()->isIntegralType()) { + const MemRegion *superReg = ER->getSuperRegion(); + if (isa(superReg) || isa(superReg) || + isa(superReg)) + R = cast(superReg); } + // FIXME: What about layers of ElementRegions? } - else if (isa(MR->getRegion())) { - // Invalidate the alloca region by setting its default value to - // conjured symbol. The type of the symbol is irrelavant. - SVal V = ValMgr.getConjuredSymbolVal(*I, Eng.getContext().IntTy, - Count); - StoreManager& StoreMgr = - Eng.getStateManager().getStoreManager(); - state = StoreMgr.setDefaultValue(state, MR->getRegion(), V); - } - else - state = state->bindLoc(*MR, UnknownVal()); + + // Is the invalidated variable something that we were tracking? + SymbolRef Sym = state->getSValAsScalarOrLoc(R).getAsLocSymbol(); + + // Remove any existing reference-count binding. + if (Sym) + state = state->remove(Sym); + + state = StoreMgr.InvalidateRegion(state, R, *I, Count); } else { // Nuke all other arguments passed by reference. + // FIXME: is this necessary or correct? This handles the non-Region + // cases. Is it ever valid to store to these? state = state->unbindLoc(cast(V)); } } - else if (isa(V)) - state = state->unbindLoc(cast(V).getLoc()); - } - - // Evaluate the effect on the message receiver. + else if (isa(V)) { + // If we are passing a location wrapped as an integer, unwrap it and + // invalidate the values referred by the location. + V = cast(V).getLoc(); + goto tryAgain; + } + } + + // Evaluate the effect on the message receiver. if (!ErrorExpr && Receiver) { SymbolRef Sym = state->getSValAsScalarOrLoc(Receiver).getAsLocSymbol(); if (Sym) { @@ -2928,17 +2893,17 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, } } } - - // Process any errors. + + // Process any errors. if (hasErr) { ProcessNonLeakError(Dst, Builder, Ex, ErrorExpr, Pred, state, hasErr, ErrorSym); return; } - - // Consult the summary for the return value. + + // Consult the summary for the return value. RetEffect RE = Summ.getRetEffect(); - + if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) { assert(Receiver); SVal V = state->getSValAsScalarOrLoc(Receiver); @@ -2951,57 +2916,57 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, if (!found) RE = RetEffect::MakeNoRet(); - } - + } + switch (RE.getKind()) { default: assert (false && "Unhandled RetEffect."); break; - - case RetEffect::NoRet: { + + case RetEffect::NoRet: { // Make up a symbol for the return value (not reference counted). // FIXME: Most of this logic is not specific to the retain/release // checker. - + // FIXME: We eventually should handle structs and other compound types // that are returned by value. - + QualType T = Ex->getType(); - + if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) { unsigned Count = Builder.getCurrentBlockCount(); ValueManager &ValMgr = Eng.getValueManager(); - SVal X = ValMgr.getConjuredSymbolVal(Ex, T, Count); - state = state->bindExpr(Ex, X, false); - } - + SVal X = ValMgr.getConjuredSymbolVal(NULL, Ex, T, Count); + state = state->BindExpr(Ex, X, false); + } + break; } - + case RetEffect::Alias: { unsigned idx = RE.getIndex(); assert (arg_end >= arg_beg); assert (idx < (unsigned) (arg_end - arg_beg)); SVal V = state->getSValAsScalarOrLoc(*(arg_beg+idx)); - state = state->bindExpr(Ex, V, false); + state = state->BindExpr(Ex, V, false); break; } - + case RetEffect::ReceiverAlias: { assert (Receiver); SVal V = state->getSValAsScalarOrLoc(Receiver); - state = state->bindExpr(Ex, V, false); + state = state->BindExpr(Ex, V, false); break; } - + case RetEffect::OwnedAllocatedSymbol: case RetEffect::OwnedSymbol: { unsigned Count = Builder.getCurrentBlockCount(); - ValueManager &ValMgr = Eng.getValueManager(); + ValueManager &ValMgr = Eng.getValueManager(); SymbolRef Sym = ValMgr.getConjuredSymbol(Ex, Count); - QualType RetT = GetReturnType(Ex, ValMgr.getContext()); + QualType RetT = GetReturnType(Ex, ValMgr.getContext()); state = state->set(Sym, RefVal::makeOwned(RE.getObjKind(), RetT)); - state = state->bindExpr(Ex, ValMgr.makeLoc(Sym), false); + state = state->BindExpr(Ex, ValMgr.makeLoc(Sym), false); // FIXME: Add a flag to the checker where allocations are assumed to // *not fail. @@ -3009,57 +2974,57 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, if (RE.getKind() == RetEffect::OwnedAllocatedSymbol) { bool isFeasible; state = state.Assume(loc::SymbolVal(Sym), true, isFeasible); - assert(isFeasible && "Cannot assume fresh symbol is non-null."); + assert(isFeasible && "Cannot assume fresh symbol is non-null."); } #endif - + break; } - + case RetEffect::GCNotOwnedSymbol: case RetEffect::NotOwnedSymbol: { unsigned Count = Builder.getCurrentBlockCount(); ValueManager &ValMgr = Eng.getValueManager(); SymbolRef Sym = ValMgr.getConjuredSymbol(Ex, Count); - QualType RetT = GetReturnType(Ex, ValMgr.getContext()); + QualType RetT = GetReturnType(Ex, ValMgr.getContext()); state = state->set(Sym, RefVal::makeNotOwned(RE.getObjKind(), RetT)); - state = state->bindExpr(Ex, ValMgr.makeLoc(Sym), false); + state = state->BindExpr(Ex, ValMgr.makeLoc(Sym), false); break; } } - + // Generate a sink node if we are at the end of a path. - GRExprEngine::NodeTy *NewNode = + ExplodedNode *NewNode = Summ.isEndPath() ? Builder.MakeSinkNode(Dst, Ex, Pred, state) : Builder.MakeNode(Dst, Ex, Pred, state); - + // Annotate the edge with summary we used. if (NewNode) SummaryLog[NewNode] = &Summ; } -void CFRefCount::EvalCall(ExplodedNodeSet& Dst, +void CFRefCount::EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, - ExplodedNode* Pred) { + ExplodedNode* Pred) { const FunctionDecl* FD = L.getAsFunctionDecl(); - RetainSummary* Summ = !FD ? Summaries.getDefaultSummary() + RetainSummary* Summ = !FD ? Summaries.getDefaultSummary() : Summaries.getSummary(const_cast(FD)); - + assert(Summ); EvalSummary(Dst, Eng, Builder, CE, 0, *Summ, CE->arg_begin(), CE->arg_end(), Pred); } -void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, +void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, - ExplodedNode* Pred) { + ExplodedNode* Pred) { RetainSummary* Summ = 0; - + if (Expr* Receiver = ME->getReceiver()) { // We need the type-information of the tracked receiver object // Retrieve it from the state. @@ -3073,26 +3038,21 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, SVal V = St->getSValAsScalarOrLoc(Receiver); SymbolRef Sym = V.getAsLocSymbol(); + if (Sym) { if (const RefVal* T = St->get(Sym)) { - QualType Ty = T->getType(); - - if (const PointerType* PT = Ty->getAsPointerType()) { - QualType PointeeTy = PT->getPointeeType(); - - if (ObjCInterfaceType* IT = dyn_cast(PointeeTy)) - ID = IT->getDecl(); - } + if (const ObjCObjectPointerType* PT = + T->getType()->getAs()) + ID = PT->getInterfaceDecl(); } } // FIXME: this is a hack. This may or may not be the actual method // that is called. if (!ID) { - if (const PointerType *PT = Receiver->getType()->getAsPointerType()) - if (const ObjCInterfaceType *p = - PT->getPointeeType()->getAsObjCInterfaceType()) - ID = p->getDecl(); + if (const ObjCObjectPointerType *PT = + Receiver->getType()->getAs()) + ID = PT->getInterfaceDecl(); } // FIXME: The receiver could be a reference to a class, meaning that @@ -3101,16 +3061,22 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, // Special-case: are we sending a mesage to "self"? // This is a hack. When we have full-IP this should be removed. - if (isa(&Eng.getGraph().getCodeDecl())) { + if (isa(Pred->getLocationContext()->getDecl())) { if (Expr* Receiver = ME->getReceiver()) { SVal X = St->getSValAsScalarOrLoc(Receiver); - if (loc::MemRegionVal* L = dyn_cast(&X)) - if (L->getRegion() == St->getSelfRegion()) { - // Update the summary to make the default argument effect - // 'StopTracking'. - Summ = Summaries.copySummary(Summ); - Summ->setDefaultArgEffect(StopTracking); + if (loc::MemRegionVal* L = dyn_cast(&X)) { + // Get the region associated with 'self'. + const LocationContext *LC = Pred->getLocationContext(); + if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) { + SVal SelfVal = St->getSVal(St->getRegion(SelfDecl, LC)); + if (L->getBaseRegion() == SelfVal.getAsRegion()) { + // Update the summary to make the default argument effect + // 'StopTracking'. + Summ = Summaries.copySummary(Summ); + Summ->setDefaultArgEffect(StopTracking); + } } + } } } } @@ -3137,18 +3103,18 @@ public: } }; } // end anonymous namespace - -void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { - // Are we storing to something that causes the value to "escape"? + +void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { + // Are we storing to something that causes the value to "escape"? bool escapes = false; - + // A value escapes in three possible cases (this may change): // // (1) we are binding to something that is not a memory region. // (2) we are binding to a memregion that does not have stack storage // (3) we are binding to a memregion with stack storage that the store - // does not understand. + // does not understand. const GRState *state = B.getState(); if (!isa(location)) @@ -3156,7 +3122,7 @@ void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { else { const MemRegion* R = cast(location).getRegion(); escapes = !R->hasStackStorage(); - + if (!escapes) { // To test (3), generate a new state with the binding removed. If it is // the same state, then it escapes (since the store cannot represent @@ -3178,40 +3144,40 @@ void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { // Return statements. -void CFRefCount::EvalReturn(ExplodedNodeSet& Dst, +void CFRefCount::EvalReturn(ExplodedNodeSet& Dst, GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, ReturnStmt* S, - ExplodedNode* Pred) { - + ExplodedNode* Pred) { + Expr* RetE = S->getRetValue(); if (!RetE) return; - + const GRState *state = Builder.GetState(Pred); SymbolRef Sym = state->getSValAsScalarOrLoc(RetE).getAsLocSymbol(); - + if (!Sym) return; - + // Get the reference count binding (if any). const RefVal* T = state->get(Sym); - + if (!T) return; - - // Change the reference count. - RefVal X = *T; - - switch (X.getKind()) { - case RefVal::Owned: { + + // Change the reference count. + RefVal X = *T; + + switch (X.getKind()) { + case RefVal::Owned: { unsigned cnt = X.getCount(); assert (cnt > 0); X.setCount(cnt - 1); X = X ^ RefVal::ReturnedOwned; break; } - + case RefVal::NotOwned: { unsigned cnt = X.getCount(); if (cnt) { @@ -3223,39 +3189,39 @@ void CFRefCount::EvalReturn(ExplodedNodeSet& Dst, } break; } - - default: + + default: return; } - + // Update the binding. state = state->set(Sym, X); Pred = Builder.MakeNode(Dst, S, Pred, state); - + // Did we cache out? if (!Pred) return; - + // Update the autorelease counts. static unsigned autoreleasetag = 0; GenericNodeBuilder Bd(Builder, S, &autoreleasetag); bool stop = false; llvm::tie(Pred, state) = HandleAutoreleaseCounts(state , Bd, Pred, Eng, Sym, X, stop); - + // Did we cache out? if (!Pred || stop) return; - + // Get the updated binding. T = state->get(Sym); assert(T); X = *T; - + // Any leaks or other errors? if (X.isReturnedOwned() && X.getCount() == 0) { - const Decl *CD = &Eng.getStateManager().getCodeDecl(); - if (const ObjCMethodDecl* MD = dyn_cast(CD)) { + Decl const *CD = &Pred->getCodeDecl(); + if (const ObjCMethodDecl* MD = dyn_cast(CD)) { const RetainSummary &Summ = *Summaries.getMethodSummary(MD); RetEffect RE = Summ.getRetEffect(); bool hasError = false; @@ -3267,25 +3233,26 @@ void CFRefCount::EvalReturn(ExplodedNodeSet& Dst, // a leak (as the caller expects a GC'ed object) because no // method should return ownership unless it returns a CF object. X = X ^ RefVal::ErrorGCLeakReturned; - + // Keep this false until this is properly tested. hasError = true; } else if (!RE.isOwned()) { // Either we are using GC and the returned object is a CF type // or we aren't using GC. In either case, we expect that the - // enclosing method is expected to return ownership. + // enclosing method is expected to return ownership. hasError = true; X = X ^ RefVal::ErrorLeakReturned; } } - - if (hasError) { + + if (hasError) { // Generate an error node. static int ReturnOwnLeakTag = 0; state = state->set(Sym, X); - ExplodedNode *N = - Builder.generateNode(PostStmt(S, &ReturnOwnLeakTag), state, Pred); + ExplodedNode *N = + Builder.generateNode(PostStmt(S, Pred->getLocationContext(), + &ReturnOwnLeakTag), state, Pred); if (N) { CFRefReport *report = new CFRefLeakReport(*static_cast(leakAtReturn), *this, @@ -3293,21 +3260,22 @@ void CFRefCount::EvalReturn(ExplodedNodeSet& Dst, BR->EmitReport(report); } } - } + } } else if (X.isReturnedNotOwned()) { - const Decl *CD = &Eng.getStateManager().getCodeDecl(); + Decl const *CD = &Pred->getCodeDecl(); if (const ObjCMethodDecl* MD = dyn_cast(CD)) { const RetainSummary &Summ = *Summaries.getMethodSummary(MD); if (Summ.getRetEffect().isOwned()) { // Trying to return a not owned object to a caller expecting an // owned object. - + static int ReturnNotOwnedForOwnedTag = 0; state = state->set(Sym, X ^ RefVal::ErrorReturnedNotOwned); - if (ExplodedNode *N = - Builder.generateNode(PostStmt(S, &ReturnNotOwnedForOwnedTag), - state, Pred)) { + if (ExplodedNode *N = + Builder.generateNode(PostStmt(S, Pred->getLocationContext(), + &ReturnNotOwnedForOwnedTag), + state, Pred)) { CFRefReport *report = new CFRefReport(*static_cast(returnNotOwnedForOwned), *this, N, Sym); @@ -3326,18 +3294,18 @@ const GRState* CFRefCount::EvalAssume(const GRState *state, // FIXME: We may add to the interface of EvalAssume the list of symbols // whose assumptions have changed. For now we just iterate through the // bindings and check if any of the tracked symbols are NULL. This isn't - // too bad since the number of symbols we will track in practice are + // too bad since the number of symbols we will track in practice are // probably small and EvalAssume is only called at branches and a few // other places. RefBindings B = state->get(); - + if (B.isEmpty()) return state; - - bool changed = false; + + bool changed = false; RefBindings::Factory& RefBFactory = state->get_context(); - for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) { + for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) { // Check if the symbol is null (or equal to any constant). // If this is the case, stop tracking the symbol. if (state->getSymVal(I.getKey())) { @@ -3345,10 +3313,10 @@ const GRState* CFRefCount::EvalAssume(const GRState *state, B = RefBFactory.Remove(B, I.getKey()); } } - + if (changed) state = state->set(B); - + return state; } @@ -3362,21 +3330,21 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, case IncRefMsg: E = isGCEnabled() ? DoNothing : IncRef; break; case DecRefMsg: E = isGCEnabled() ? DoNothing : DecRef; break; case MakeCollectable: E = isGCEnabled() ? DecRef : DoNothing; break; - case NewAutoreleasePool: E = isGCEnabled() ? DoNothing : + case NewAutoreleasePool: E = isGCEnabled() ? DoNothing : NewAutoreleasePool; break; } - + // Handle all use-after-releases. if (!isGCEnabled() && V.getKind() == RefVal::Released) { V = V ^ RefVal::ErrorUseAfterRelease; hasErr = V.getKind(); return state->set(sym, V); - } - + } + switch (E) { default: assert (false && "Unhandled CFRef transition."); - + case Dealloc: // Any use of -dealloc in GC is *bad*. if (isGCEnabled()) { @@ -3384,7 +3352,7 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, hasErr = V.getKind(); break; } - + switch (V.getKind()) { default: assert(false && "Invalid case."); @@ -3397,13 +3365,13 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, V = V ^ RefVal::ErrorDeallocNotOwned; hasErr = V.getKind(); break; - } + } break; case NewAutoreleasePool: assert(!isGCEnabled()); return state->add(sym); - + case MayEscape: if (V.getKind() == RefVal::Owned) { V = V ^ RefVal::NotOwned; @@ -3411,7 +3379,7 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, } // Fall-through. - + case DoNothingByRef: case DoNothing: return state; @@ -3419,7 +3387,7 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, case Autorelease: if (isGCEnabled()) return state; - + // Update the autorelease counts. state = SendAutorelease(state, ARCountFactory, sym); V = V.autorelease(); @@ -3428,7 +3396,7 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, case StopTracking: return state->remove(sym); - case IncRef: + case IncRef: switch (V.getKind()) { default: assert(false); @@ -3436,15 +3404,15 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, case RefVal::Owned: case RefVal::NotOwned: V = V + 1; - break; + break; case RefVal::Released: // Non-GC cases are handled above. assert(isGCEnabled()); V = (V ^ RefVal::Owned) + 1; break; - } + } break; - + case SelfOwn: V = V ^ RefVal::NotOwned; // Fall-through. @@ -3459,23 +3427,23 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, if (V.getCount() == 1) V = V ^ RefVal::Released; V = V - 1; break; - + case RefVal::NotOwned: if (V.getCount() > 0) V = V - 1; else { V = V ^ RefVal::ErrorReleaseNotOwned; hasErr = V.getKind(); - } + } break; - + case RefVal::Released: // Non-GC cases are handled above. assert(isGCEnabled()); V = V ^ RefVal::ErrorUseAfterRelease; hasErr = V.getKind(); - break; - } + break; + } break; } return state->set(sym, V); @@ -3485,27 +3453,27 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym, // Handle dead symbols and end-of-path. //===----------------------------------------------------------------------===// -std::pair*, const GRState *> +std::pair CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd, - ExplodedNode* Pred, + ExplodedNode* Pred, GRExprEngine &Eng, SymbolRef Sym, RefVal V, bool &stop) { - + unsigned ACnt = V.getAutoreleaseCount(); stop = false; // No autorelease counts? Nothing to be done. if (!ACnt) return std::make_pair(Pred, state); - - assert(!isGCEnabled() && "Autorelease counts in GC mode?"); + + assert(!isGCEnabled() && "Autorelease counts in GC mode?"); unsigned Cnt = V.getCount(); - + // FIXME: Handle sending 'autorelease' to already released object. if (V.getKind() == RefVal::ReturnedOwned) ++Cnt; - + if (ACnt <= Cnt) { if (ACnt == Cnt) { V.clearCounts(); @@ -3519,10 +3487,10 @@ CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd V.setAutoreleaseCount(0); } state = state->set(Sym, V); - ExplodedNode *N = Bd.MakeNode(state, Pred); + ExplodedNode *N = Bd.MakeNode(state, Pred); stop = (N == 0); return std::make_pair(N, state); - } + } // Woah! More autorelease counts then retain counts left. // Emit hard error. @@ -3530,9 +3498,9 @@ CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd V = V ^ RefVal::ErrorOverAutorelease; state = state->set(Sym, V); - if (ExplodedNode *N = Bd.MakeNode(state, Pred)) { + if (ExplodedNode *N = Bd.MakeNode(state, Pred)) { N->markAsSink(); - + std::string sbuf; llvm::raw_string_ostream os(sbuf); os << "Object over-autoreleased: object was sent -autorelease"; @@ -3544,95 +3512,95 @@ CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd else os << "+" << V.getCount(); os << " retain counts"; - + CFRefReport *report = new CFRefReport(*static_cast(overAutorelease), *this, N, Sym, os.str().c_str()); BR->EmitReport(report); } - - return std::make_pair((ExplodedNode*)0, state); + + return std::make_pair((ExplodedNode*)0, state); } const GRState * CFRefCount::HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V, llvm::SmallVectorImpl &Leaked) { - - bool hasLeak = V.isOwned() || + + bool hasLeak = V.isOwned() || ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0); - + if (!hasLeak) return state->remove(sid); - + Leaked.push_back(sid); return state->set(sid, V ^ RefVal::ErrorLeak); } -ExplodedNode* +ExplodedNode* CFRefCount::ProcessLeaks(const GRState * state, llvm::SmallVectorImpl &Leaked, GenericNodeBuilder &Builder, GRExprEngine& Eng, - ExplodedNode *Pred) { - + ExplodedNode *Pred) { + if (Leaked.empty()) return Pred; - + // Generate an intermediate node representing the leak point. - ExplodedNode *N = Builder.MakeNode(state, Pred); - + ExplodedNode *N = Builder.MakeNode(state, Pred); + if (N) { for (llvm::SmallVectorImpl::iterator I = Leaked.begin(), E = Leaked.end(); I != E; ++I) { - - CFRefBug *BT = static_cast(Pred ? leakWithinFunction + + CFRefBug *BT = static_cast(Pred ? leakWithinFunction : leakAtReturn); assert(BT && "BugType not initialized."); CFRefLeakReport* report = new CFRefLeakReport(*BT, *this, N, *I, Eng); BR->EmitReport(report); } } - + return N; } void CFRefCount::EvalEndPath(GRExprEngine& Eng, - GREndPathNodeBuilder& Builder) { - + GREndPathNodeBuilder& Builder) { + const GRState *state = Builder.getState(); GenericNodeBuilder Bd(Builder); - RefBindings B = state->get(); - ExplodedNode *Pred = 0; + RefBindings B = state->get(); + ExplodedNode *Pred = 0; for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { bool stop = false; llvm::tie(Pred, state) = HandleAutoreleaseCounts(state, Bd, Pred, Eng, (*I).first, - (*I).second, stop); + (*I).second, stop); if (stop) return; } - - B = state->get(); - llvm::SmallVector Leaked; - + + B = state->get(); + llvm::SmallVector Leaked; + for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) state = HandleSymbolDeath(state, (*I).first, (*I).second, Leaked); ProcessLeaks(state, Leaked, Bd, Eng, Pred); } -void CFRefCount::EvalDeadSymbols(ExplodedNodeSet& Dst, +void CFRefCount::EvalDeadSymbols(ExplodedNodeSet& Dst, GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, - ExplodedNode* Pred, + GRStmtNodeBuilder& Builder, + ExplodedNode* Pred, Stmt* S, const GRState* state, SymbolReaper& SymReaper) { RefBindings B = state->get(); - + // Update counts from autorelease pools for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), E = SymReaper.dead_end(); I != E; ++I) { @@ -3648,57 +3616,57 @@ void CFRefCount::EvalDeadSymbols(ExplodedNodeSet& Dst, return; } } - + B = state->get(); llvm::SmallVector Leaked; - + for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), - E = SymReaper.dead_end(); I != E; ++I) { + E = SymReaper.dead_end(); I != E; ++I) { if (const RefVal* T = B.lookup(*I)) state = HandleSymbolDeath(state, *I, *T, Leaked); - } - + } + static unsigned LeakPPTag = 0; { GenericNodeBuilder Bd(Builder, S, &LeakPPTag); Pred = ProcessLeaks(state, Leaked, Bd, Eng, Pred); } - + // Did we cache out? if (!Pred) return; - + // Now generate a new node that nukes the old bindings. RefBindings::Factory& F = state->get_context(); - + for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), E = SymReaper.dead_end(); I!=E; ++I) B = F.Remove(B, *I); - + state = state->set(B); Builder.MakeNode(Dst, S, Pred, state); } -void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, - GRStmtNodeBuilder& Builder, - Expr* NodeExpr, Expr* ErrorExpr, - ExplodedNode* Pred, +void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, + GRStmtNodeBuilder& Builder, + Expr* NodeExpr, Expr* ErrorExpr, + ExplodedNode* Pred, const GRState* St, RefVal::Kind hasErr, SymbolRef Sym) { Builder.BuildSinks = true; - GRExprEngine::NodeTy* N = Builder.MakeNode(Dst, NodeExpr, Pred, St); - + ExplodedNode *N = Builder.MakeNode(Dst, NodeExpr, Pred, St); + if (!N) return; - + CFRefBug *BT = 0; - + switch (hasErr) { default: assert(false && "Unhandled error."); return; case RefVal::ErrorUseAfterRelease: BT = static_cast(useAfterRelease); - break; + break; case RefVal::ErrorReleaseNotOwned: BT = static_cast(releaseNotOwned); break; @@ -3709,7 +3677,7 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, BT = static_cast(deallocNotOwned); break; } - + CFRefReport *report = new CFRefReport(*BT, *this, N, Sym); report->addRange(ErrorExpr->getSourceRange()); BR->EmitReport(report); @@ -3722,4 +3690,4 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, const LangOptions& lopts) { return new CFRefCount(Ctx, GCEnabled, lopts); -} +} diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 7d6a619736e0..89c1783cc2f5 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -1,17 +1,24 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangAnalysis + AnalysisContext.cpp + AnalysisManager.cpp BasicConstraintManager.cpp BasicObjCFoundationChecks.cpp BasicStore.cpp BasicValueFactory.cpp BugReporter.cpp + BugReporterVisitors.cpp + CFG.cpp CFRefCount.cpp + CallGraph.cpp + CallInliner.cpp CheckDeadStores.cpp CheckNSError.cpp CheckObjCDealloc.cpp CheckObjCInstMethSignature.cpp CheckObjCUnusedIVars.cpp + CheckSecuritySyntaxOnly.cpp Environment.cpp ExplodedGraph.cpp GRBlockCounter.cpp @@ -24,10 +31,11 @@ add_clang_library(clangAnalysis PathDiagnostic.cpp RangeConstraintManager.cpp RegionStore.cpp + SVals.cpp + SValuator.cpp SimpleConstraintManager.cpp SimpleSValuator.cpp Store.cpp - SVals.cpp SymbolManager.cpp UninitializedValues.cpp ValueManager.cpp diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp new file mode 100644 index 000000000000..ae8845db63ae --- /dev/null +++ b/lib/Analysis/CallGraph.cpp @@ -0,0 +1,150 @@ +//== CallGraph.cpp - Call graph building ------------------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defined the CallGraph and CGBuilder classes. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/CallGraph.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/StmtVisitor.h" + +#include "llvm/Support/GraphWriter.h" + +using namespace clang; +using namespace idx; + +namespace { +class CGBuilder : public StmtVisitor { + + CallGraph &G; + FunctionDecl *FD; + + Entity CallerEnt; + + CallGraphNode *CallerNode; + +public: + CGBuilder(CallGraph &g, FunctionDecl *fd, Entity E, CallGraphNode *N) + : G(g), FD(fd), CallerEnt(E), CallerNode(N) {} + + void VisitStmt(Stmt *S) { VisitChildren(S); } + + void VisitCallExpr(CallExpr *CE); + + void VisitChildren(Stmt *S) { + for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I) + if (*I) + static_cast(this)->Visit(*I); + } +}; +} + +void CGBuilder::VisitCallExpr(CallExpr *CE) { + if (FunctionDecl *CalleeDecl = CE->getDirectCallee()) { + Entity Ent = Entity::get(CalleeDecl, G.getProgram()); + CallGraphNode *CalleeNode = G.getOrInsertFunction(Ent); + CallerNode->addCallee(ASTLocation(FD, CE), CalleeNode); + } +} + +CallGraph::CallGraph() : Root(0) { + ExternalCallingNode = getOrInsertFunction(Entity()); +} + +CallGraph::~CallGraph() { + if (!FunctionMap.empty()) { + for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end(); + I != E; ++I) + delete I->second; + FunctionMap.clear(); + } +} + +void CallGraph::addTU(ASTUnit &AST) { + ASTContext &Ctx = AST.getASTContext(); + DeclContext *DC = Ctx.getTranslationUnitDecl(); + + for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); + I != E; ++I) { + + if (FunctionDecl *FD = dyn_cast(*I)) { + if (FD->isThisDeclarationADefinition()) { + // Set caller's ASTContext. + Entity Ent = Entity::get(FD, Prog); + CallGraphNode *Node = getOrInsertFunction(Ent); + CallerCtx[Node] = &Ctx; + + // If this function has external linkage, anything could call it. + if (FD->isGlobal()) + ExternalCallingNode->addCallee(idx::ASTLocation(), Node); + + // Set root node to 'main' function. + if (FD->getNameAsString() == "main") + Root = Node; + + CGBuilder builder(*this, FD, Ent, Node); + builder.Visit(FD->getBody()); + } + } + } +} + +CallGraphNode *CallGraph::getOrInsertFunction(Entity F) { + CallGraphNode *&Node = FunctionMap[F]; + if (Node) + return Node; + + return Node = new CallGraphNode(F); +} + +Decl *CallGraph::getDecl(CallGraphNode *Node) { + // Get the function's context. + ASTContext *Ctx = CallerCtx[Node]; + + return Node->getDecl(*Ctx); +} + +void CallGraph::print(llvm::raw_ostream &os) { + for (iterator I = begin(), E = end(); I != E; ++I) { + if (I->second->hasCallee()) { + os << "function: " << I->first.getPrintableName() + << " calls:\n"; + for (CallGraphNode::iterator CI = I->second->begin(), + CE = I->second->end(); CI != CE; ++CI) { + os << " " << CI->second->getName().c_str(); + } + os << '\n'; + } + } +} + +void CallGraph::dump() { + print(llvm::errs()); +} + +void CallGraph::ViewCallGraph() const { + llvm::ViewGraph(*this, "CallGraph"); +} + +namespace llvm { + +template <> +struct DOTGraphTraits : public DefaultDOTGraphTraits { + + static std::string getNodeLabel(const CallGraphNode *Node, + const CallGraph &CG, bool ShortNames) { + return Node->getName(); + + } + +}; + +} diff --git a/lib/Analysis/CallInliner.cpp b/lib/Analysis/CallInliner.cpp new file mode 100644 index 000000000000..cca8584a61fa --- /dev/null +++ b/lib/Analysis/CallInliner.cpp @@ -0,0 +1,75 @@ +//===--- CallInliner.cpp - Transfer function that inlines callee ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the callee inlining transfer function. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" + +using namespace clang; + +namespace { + +class VISIBILITY_HIDDEN CallInliner : public GRTransferFuncs { + ASTContext &Ctx; +public: + CallInliner(ASTContext &ctx) : Ctx(ctx) {} + + void EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Engine, + GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, + ExplodedNode* Pred); + +}; + +} + +void CallInliner::EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Engine, + GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, + ExplodedNode* Pred) { + FunctionDecl const *FD = L.getAsFunctionDecl(); + if (!FD) + return; // GRExprEngine is responsible for the autotransition. + + // Make a new LocationContext. + StackFrameContext const *LocCtx = + Engine.getAnalysisManager().getStackFrame(FD, Pred->getLocationContext(), CE); + + CFGBlock const *Entry = &(LocCtx->getCFG()->getEntry()); + + assert (Entry->empty() && "Entry block must be empty."); + + assert (Entry->succ_size() == 1 && "Entry block must have 1 successor."); + + // Get the solitary successor. + CFGBlock const *SuccB = *(Entry->succ_begin()); + + // Construct an edge representing the starting location in the function. + BlockEdge Loc(Entry, SuccB, LocCtx); + + GRState const *state = Builder.GetState(Pred); + state = Engine.getStoreManager().EnterStackFrame(state, LocCtx); + + bool isNew; + ExplodedNode *SuccN = Engine.getGraph().getNode(Loc, state, &isNew); + SuccN->addPredecessor(Pred, Engine.getGraph()); + + Builder.Deferred.erase(Pred); + + // This is a hack. We really should not use the GRStmtNodeBuilder. + if (isNew) + Builder.getWorkList()->Enqueue(SuccN); + + Builder.HasGeneratedNode = true; +} + +GRTransferFuncs *clang::CreateCallInliner(ASTContext &ctx) { + return new CallInliner(ctx); +} diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Analysis/CheckDeadStores.cpp index 69433d6396a5..d5cb7ca7fdd3 100644 --- a/lib/Analysis/CheckDeadStores.cpp +++ b/lib/Analysis/CheckDeadStores.cpp @@ -33,14 +33,14 @@ class VISIBILITY_HIDDEN DeadStoreObs : public LiveVariables::ObserverTy { BugReporter& BR; ParentMap& Parents; llvm::SmallPtrSet Escaped; - + enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit }; - + public: DeadStoreObs(ASTContext &ctx, BugReporter& br, ParentMap& parents, llvm::SmallPtrSet &escaped) : Ctx(ctx), BR(br), Parents(parents), Escaped(escaped) {} - + virtual ~DeadStoreObs() {} void Report(VarDecl* V, DeadStoreKind dsk, SourceLocation L, SourceRange R) { @@ -48,27 +48,27 @@ public: return; std::string name = V->getNameAsString(); - + const char* BugType = 0; std::string msg; - + switch (dsk) { default: assert(false && "Impossible dead store type."); - + case DeadInit: BugType = "Dead initialization"; msg = "Value stored to '" + name + "' during its initialization is never read"; break; - + case DeadIncrement: BugType = "Dead increment"; case Standard: if (!BugType) BugType = "Dead assignment"; msg = "Value stored to '" + name + "' is never read"; break; - + case Enclosing: BugType = "Dead nested assignment"; msg = "Although the value stored to '" + name + @@ -76,10 +76,10 @@ public: " read from '" + name + "'"; break; } - - BR.EmitBasicReport(BugType, "Dead store", msg.c_str(), L, R); + + BR.EmitBasicReport(BugType, "Dead store", msg.c_str(), L, R); } - + void CheckVarDecl(VarDecl* VD, Expr* Ex, Expr* Val, DeadStoreKind dsk, const LiveVariables::AnalysisDataTy& AD, @@ -87,60 +87,60 @@ public: if (VD->hasLocalStorage() && !Live(VD, AD) && !VD->getAttr()) Report(VD, dsk, Ex->getSourceRange().getBegin(), - Val->getSourceRange()); + Val->getSourceRange()); } - + void CheckDeclRef(DeclRefExpr* DR, Expr* Val, DeadStoreKind dsk, const LiveVariables::AnalysisDataTy& AD, const LiveVariables::ValTy& Live) { - + if (VarDecl* VD = dyn_cast(DR->getDecl())) CheckVarDecl(VD, DR, Val, dsk, AD, Live); } - + bool isIncrement(VarDecl* VD, BinaryOperator* B) { if (B->isCompoundAssignmentOp()) return true; - + Expr* RHS = B->getRHS()->IgnoreParenCasts(); BinaryOperator* BRHS = dyn_cast(RHS); - + if (!BRHS) return false; - + DeclRefExpr *DR; - + if ((DR = dyn_cast(BRHS->getLHS()->IgnoreParenCasts()))) if (DR->getDecl() == VD) return true; - + if ((DR = dyn_cast(BRHS->getRHS()->IgnoreParenCasts()))) if (DR->getDecl() == VD) return true; - + return false; } - + virtual void ObserveStmt(Stmt* S, const LiveVariables::AnalysisDataTy& AD, const LiveVariables::ValTy& Live) { - + // Skip statements in macros. if (S->getLocStart().isMacroID()) return; - - if (BinaryOperator* B = dyn_cast(S)) { + + if (BinaryOperator* B = dyn_cast(S)) { if (!B->isAssignmentOp()) return; // Skip non-assignments. - + if (DeclRefExpr* DR = dyn_cast(B->getLHS())) if (VarDecl *VD = dyn_cast(DR->getDecl())) { Expr* RHS = B->getRHS()->IgnoreParenCasts(); - + // Special case: check for assigning null to a pointer. - // This is a common form of defensive programming. + // This is a common form of defensive programming. if (VD->getType()->isPointerType()) { if (IntegerLiteral* L = dyn_cast(RHS)) - // FIXME: Probably should have an Expr::isNullPointerConstant. + // FIXME: Probably should have an Expr::isNullPointerConstant. if (L->getValue() == 0) return; } @@ -149,19 +149,19 @@ public: if (DeclRefExpr* RhsDR = dyn_cast(RHS)) if (VD == dyn_cast(RhsDR->getDecl())) return; - + // Otherwise, issue a warning. DeadStoreKind dsk = Parents.isConsumedExpr(B) - ? Enclosing + ? Enclosing : (isIncrement(VD,B) ? DeadIncrement : Standard); - + CheckVarDecl(VD, DR, B->getRHS(), dsk, AD, Live); - } + } } else if (UnaryOperator* U = dyn_cast(S)) { if (!U->isIncrementOp()) return; - + // Handle: ++x within a subexpression. The solution is not warn // about preincrements to dead variables when the preincrement occurs // as a subexpression. This can lead to false negatives, e.g. "(++x);" @@ -170,21 +170,21 @@ public: return; Expr *Ex = U->getSubExpr()->IgnoreParenCasts(); - + if (DeclRefExpr* DR = dyn_cast(Ex)) CheckDeclRef(DR, U, DeadIncrement, AD, Live); - } + } else if (DeclStmt* DS = dyn_cast(S)) // Iterate through the decls. Warn if any initializers are complex // expressions that are not live (never used). for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE=DS->decl_end(); DI != DE; ++DI) { - + VarDecl* V = dyn_cast(*DI); if (!V) continue; - + if (V->hasLocalStorage()) if (Expr* E = V->getInit()) { // A dead initialization is a variable that is dead after it @@ -200,7 +200,7 @@ public: // due to defensive programming. if (E->isConstantInitializer(Ctx)) return; - + // Special case: check for initializations from constant // variables. // @@ -211,14 +211,14 @@ public: if (VarDecl *VD = dyn_cast(DRE->getDecl())) if (VD->hasGlobalStorage() && VD->getType().isConstQualified()) return; - + Report(V, DeadInit, V->getLocation(), E->getSourceRange()); } } } } }; - + } // end anonymous namespace //===----------------------------------------------------------------------===// @@ -230,9 +230,9 @@ class VISIBILITY_HIDDEN FindEscaped : public CFGRecStmtDeclVisitor{ CFG *cfg; public: FindEscaped(CFG *c) : cfg(c) {} - + CFG& getCFG() { return *cfg; } - + llvm::SmallPtrSet Escaped; void VisitUnaryOperator(UnaryOperator* U) { @@ -249,11 +249,12 @@ public: } }; } // end anonymous namespace - -void clang::CheckDeadStores(LiveVariables& L, BugReporter& BR) { - FindEscaped FS(BR.getCFG()); - FS.getCFG().VisitBlockStmts(FS); - DeadStoreObs A(BR.getContext(), BR, BR.getParentMap(), FS.Escaped); - L.runOnAllBlocks(*BR.getCFG(), &A); + +void clang::CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &pmap, + BugReporter& BR) { + FindEscaped FS(&cfg); + FS.getCFG().VisitBlockStmts(FS); + DeadStoreObs A(BR.getContext(), BR, pmap, FS.Escaped); + L.runOnAllBlocks(cfg, &A); } diff --git a/lib/Analysis/CheckNSError.cpp b/lib/Analysis/CheckNSError.cpp index c91442b5e829..8086da588264 100644 --- a/lib/Analysis/CheckNSError.cpp +++ b/lib/Analysis/CheckNSError.cpp @@ -28,91 +28,91 @@ using namespace clang; namespace { class VISIBILITY_HIDDEN NSErrorCheck : public BugType { + const Decl &CodeDecl; const bool isNSErrorWarning; IdentifierInfo * const II; GRExprEngine &Eng; - - void CheckSignature(ObjCMethodDecl& MD, QualType& ResultTy, + + void CheckSignature(const ObjCMethodDecl& MD, QualType& ResultTy, llvm::SmallVectorImpl& ErrorParams); - - void CheckSignature(FunctionDecl& MD, QualType& ResultTy, + + void CheckSignature(const FunctionDecl& MD, QualType& ResultTy, llvm::SmallVectorImpl& ErrorParams); bool CheckNSErrorArgument(QualType ArgTy); bool CheckCFErrorArgument(QualType ArgTy); - - void CheckParamDeref(VarDecl* V, const GRState *state, BugReporter& BR); - - void EmitRetTyWarning(BugReporter& BR, Decl& CodeDecl); - + + void CheckParamDeref(const VarDecl *V, const LocationContext *LC, + const GRState *state, BugReporter& BR); + + void EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl); + public: - NSErrorCheck(bool isNSError, GRExprEngine& eng) - : BugType(isNSError ? "NSError** null dereference" - : "CFErrorRef* null dereference", - "Coding Conventions (Apple)"), - isNSErrorWarning(isNSError), + NSErrorCheck(const Decl &D, bool isNSError, GRExprEngine& eng) + : BugType(isNSError ? "NSError** null dereference" + : "CFErrorRef* null dereference", + "Coding conventions (Apple)"), + CodeDecl(D), + isNSErrorWarning(isNSError), II(&eng.getContext().Idents.get(isNSErrorWarning ? "NSError":"CFErrorRef")), Eng(eng) {} - + void FlushReports(BugReporter& BR); -}; - +}; + } // end anonymous namespace -void clang::RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng) { - BR.Register(new NSErrorCheck(true, Eng)); - BR.Register(new NSErrorCheck(false, Eng)); +void clang::RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng, + const Decl &D) { + BR.Register(new NSErrorCheck(D, true, Eng)); + BR.Register(new NSErrorCheck(D, false, Eng)); } void NSErrorCheck::FlushReports(BugReporter& BR) { // Get the analysis engine and the exploded analysis graph. - GRExprEngine::GraphTy& G = Eng.getGraph(); - - // Get the declaration of the method/function that was analyzed. - Decl& CodeDecl = G.getCodeDecl(); - + ExplodedGraph& G = Eng.getGraph(); + // Get the ASTContext, which is useful for querying type information. ASTContext &Ctx = BR.getContext(); QualType ResultTy; llvm::SmallVector ErrorParams; - if (ObjCMethodDecl* MD = dyn_cast(&CodeDecl)) + if (const ObjCMethodDecl* MD = dyn_cast(&CodeDecl)) CheckSignature(*MD, ResultTy, ErrorParams); - else if (FunctionDecl* FD = dyn_cast(&CodeDecl)) + else if (const FunctionDecl* FD = dyn_cast(&CodeDecl)) CheckSignature(*FD, ResultTy, ErrorParams); else return; - + if (ErrorParams.empty()) return; - + if (ResultTy == Ctx.VoidTy) EmitRetTyWarning(BR, CodeDecl); - - for (GRExprEngine::GraphTy::roots_iterator RI=G.roots_begin(), - RE=G.roots_end(); RI!=RE; ++RI) { + + for (ExplodedGraph::roots_iterator RI=G.roots_begin(), RE=G.roots_end(); + RI!=RE; ++RI) { // Scan the parameters for an implicit null dereference. for (llvm::SmallVectorImpl::iterator I=ErrorParams.begin(), - E=ErrorParams.end(); I!=E; ++I) - CheckParamDeref(*I, (*RI)->getState(), BR); - + E=ErrorParams.end(); I!=E; ++I) + CheckParamDeref(*I, (*RI)->getLocationContext(), (*RI)->getState(), BR); } } -void NSErrorCheck::EmitRetTyWarning(BugReporter& BR, Decl& CodeDecl) { +void NSErrorCheck::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) { std::string sbuf; llvm::raw_string_ostream os(sbuf); - + if (isa(CodeDecl)) os << "Method"; else - os << "Function"; - + os << "Function"; + os << " accepting "; os << (isNSErrorWarning ? "NSError**" : "CFErrorRef*"); os << " should have a non-void return value to indicate whether or not an " - "error occured."; - + "error occurred"; + BR.EmitBasicReport(isNSErrorWarning ? "Bad return type when passing NSError**" : "Bad return type when passing CFError*", @@ -121,15 +121,15 @@ void NSErrorCheck::EmitRetTyWarning(BugReporter& BR, Decl& CodeDecl) { } void -NSErrorCheck::CheckSignature(ObjCMethodDecl& M, QualType& ResultTy, +NSErrorCheck::CheckSignature(const ObjCMethodDecl& M, QualType& ResultTy, llvm::SmallVectorImpl& ErrorParams) { ResultTy = M.getResultType(); - - for (ObjCMethodDecl::param_iterator I=M.param_begin(), + + for (ObjCMethodDecl::param_iterator I=M.param_begin(), E=M.param_end(); I!=E; ++I) { - QualType T = (*I)->getType(); + QualType T = (*I)->getType(); if (isNSErrorWarning) { if (CheckNSErrorArgument(T)) ErrorParams.push_back(*I); @@ -140,16 +140,16 @@ NSErrorCheck::CheckSignature(ObjCMethodDecl& M, QualType& ResultTy, } void -NSErrorCheck::CheckSignature(FunctionDecl& F, QualType& ResultTy, +NSErrorCheck::CheckSignature(const FunctionDecl& F, QualType& ResultTy, llvm::SmallVectorImpl& ErrorParams) { - + ResultTy = F.getResultType(); - - for (FunctionDecl::param_iterator I=F.param_begin(), - E=F.param_end(); I!=E; ++I) { - - QualType T = (*I)->getType(); - + + for (FunctionDecl::param_const_iterator I = F.param_begin(), + E = F.param_end(); I != E; ++I) { + + QualType T = (*I)->getType(); + if (isNSErrorWarning) { if (CheckNSErrorArgument(T)) ErrorParams.push_back(*I); } @@ -160,51 +160,59 @@ NSErrorCheck::CheckSignature(FunctionDecl& F, QualType& ResultTy, bool NSErrorCheck::CheckNSErrorArgument(QualType ArgTy) { - - const PointerType* PPT = ArgTy->getAsPointerType(); - if (!PPT) return false; - - const PointerType* PT = PPT->getPointeeType()->getAsPointerType(); - if (!PT) return false; - - const ObjCInterfaceType *IT = - PT->getPointeeType()->getAsObjCInterfaceType(); - - if (!IT) return false; - return IT->getDecl()->getIdentifier() == II; + + const PointerType* PPT = ArgTy->getAs(); + if (!PPT) + return false; + + const ObjCObjectPointerType* PT = + PPT->getPointeeType()->getAs(); + + if (!PT) + return false; + + const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); + + // FIXME: Can ID ever be NULL? + if (ID) + return II == ID->getIdentifier(); + + return false; } bool NSErrorCheck::CheckCFErrorArgument(QualType ArgTy) { - - const PointerType* PPT = ArgTy->getAsPointerType(); + + const PointerType* PPT = ArgTy->getAs(); if (!PPT) return false; - - const TypedefType* TT = PPT->getPointeeType()->getAsTypedefType(); + + const TypedefType* TT = PPT->getPointeeType()->getAs(); if (!TT) return false; return TT->getDecl()->getIdentifier() == II; } -void NSErrorCheck::CheckParamDeref(VarDecl* Param, const GRState *rootState, +void NSErrorCheck::CheckParamDeref(const VarDecl *Param, + const LocationContext *LC, + const GRState *rootState, BugReporter& BR) { - - SVal ParamL = rootState->getLValue(Param); + + SVal ParamL = rootState->getLValue(Param, LC); const MemRegion* ParamR = cast(ParamL).getRegionAs(); assert (ParamR && "Parameters always have VarRegions."); SVal ParamSVal = rootState->getSVal(ParamR); - + // FIXME: For now assume that ParamSVal is symbolic. We need to generalize // this later. SymbolRef ParamSym = ParamSVal.getAsLocSymbol(); if (!ParamSym) return; - + // Iterate over the implicit-null dereferences. for (GRExprEngine::null_deref_iterator I=Eng.implicit_null_derefs_begin(), E=Eng.implicit_null_derefs_end(); I!=E; ++I) { - + const GRState *state = (*I)->getState(); - const SVal* X = state->get(); + const SVal* X = state->get(); if (!X || X->getAsSymbol() != ParamSym) continue; @@ -213,14 +221,14 @@ void NSErrorCheck::CheckParamDeref(VarDecl* Param, const GRState *rootState, std::string sbuf; llvm::raw_string_ostream os(sbuf); os << "Potential null dereference. According to coding standards "; - + if (isNSErrorWarning) os << "in 'Creating and Returning NSError Objects' the parameter '"; else os << "documented in CoreFoundation/CFError.h the parameter '"; - + os << Param->getNameAsString() << "' may be null."; - + BugReport *report = new BugReport(*this, os.str().c_str(), *I); // FIXME: Notable symbols are now part of the report. We should // add support for notable symbols in BugReport. diff --git a/lib/Analysis/CheckObjCDealloc.cpp b/lib/Analysis/CheckObjCDealloc.cpp index a14ae265128b..92e3e112d9f1 100644 --- a/lib/Analysis/CheckObjCDealloc.cpp +++ b/lib/Analysis/CheckObjCDealloc.cpp @@ -24,11 +24,11 @@ using namespace clang; -static bool scan_dealloc(Stmt* S, Selector Dealloc) { - +static bool scan_dealloc(Stmt* S, Selector Dealloc) { + if (ObjCMessageExpr* ME = dyn_cast(S)) if (ME->getSelector() == Dealloc) - if(ME->getReceiver()) + if (ME->getReceiver()) if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts()) return isa(Receiver); @@ -37,20 +37,20 @@ static bool scan_dealloc(Stmt* S, Selector Dealloc) { for (Stmt::child_iterator I = S->child_begin(), E= S->child_end(); I!=E; ++I) if (*I && scan_dealloc(*I, Dealloc)) return true; - + return false; } -static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID, - const ObjCPropertyDecl* PD, - Selector Release, +static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID, + const ObjCPropertyDecl* PD, + Selector Release, IdentifierInfo* SelfII, - ASTContext& Ctx) { - + ASTContext& Ctx) { + // [mMyIvar release] if (ObjCMessageExpr* ME = dyn_cast(S)) if (ME->getSelector() == Release) - if(ME->getReceiver()) + if (ME->getReceiver()) if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts()) if (ObjCIvarRefExpr* E = dyn_cast(Receiver)) if (E->getDecl() == ID) @@ -58,27 +58,29 @@ static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID, // [self setMyIvar:nil]; if (ObjCMessageExpr* ME = dyn_cast(S)) - if(ME->getReceiver()) + if (ME->getReceiver()) if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts()) if (DeclRefExpr* E = dyn_cast(Receiver)) if (E->getDecl()->getIdentifier() == SelfII) if (ME->getMethodDecl() == PD->getSetterMethodDecl() && ME->getNumArgs() == 1 && - ME->getArg(0)->isNullPointerConstant(Ctx)) + ME->getArg(0)->isNullPointerConstant(Ctx, + Expr::NPC_ValueDependentIsNull)) return true; - + // self.myIvar = nil; if (BinaryOperator* BO = dyn_cast(S)) if (BO->isAssignmentOp()) - if(ObjCPropertyRefExpr* PRE = + if (ObjCPropertyRefExpr* PRE = dyn_cast(BO->getLHS()->IgnoreParenCasts())) - if(PRE->getProperty() == PD) - if(BO->getRHS()->isNullPointerConstant(Ctx)) { + if (PRE->getProperty() == PD) + if (BO->getRHS()->isNullPointerConstant(Ctx, + Expr::NPC_ValueDependentIsNull)) { // This is only a 'release' if the property kind is not // 'assign'. return PD->getSetterKind() != ObjCPropertyDecl::Assign;; } - + // Recurse to children. for (Stmt::child_iterator I = S->child_begin(), E= S->child_end(); I!=E; ++I) if (*I && scan_ivar_release(*I, ID, PD, Release, SelfII, Ctx)) @@ -87,43 +89,43 @@ static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID, return false; } -void clang::CheckObjCDealloc(ObjCImplementationDecl* D, +void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, const LangOptions& LOpts, BugReporter& BR) { assert (LOpts.getGCMode() != LangOptions::GCOnly); - + ASTContext& Ctx = BR.getContext(); - ObjCInterfaceDecl* ID = D->getClassInterface(); - + const ObjCInterfaceDecl* ID = D->getClassInterface(); + // Does the class contain any ivars that are pointers (or id<...>)? // If not, skip the check entirely. // NOTE: This is motivated by PR 2517: // http://llvm.org/bugs/show_bug.cgi?id=2517 - + bool containsPointerIvar = false; - + for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end(); I!=E; ++I) { - + ObjCIvarDecl* ID = *I; QualType T = ID->getType(); - - if (!Ctx.isObjCObjectPointerType(T) || + + if (!T->isObjCObjectPointerType() || ID->getAttr()) // Skip IBOutlets. continue; - + containsPointerIvar = true; break; } - + if (!containsPointerIvar) return; - + // Determine if the class subclasses NSObject. IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject"); IdentifierInfo* SenTestCaseII = &Ctx.Idents.get("SenTestCase"); - + for ( ; ID ; ID = ID->getSuperClass()) { IdentifierInfo *II = ID->getIdentifier(); @@ -137,118 +139,118 @@ void clang::CheckObjCDealloc(ObjCImplementationDecl* D, if (II == SenTestCaseII) return; } - + if (!ID) return; - + // Get the "dealloc" selector. IdentifierInfo* II = &Ctx.Idents.get("dealloc"); - Selector S = Ctx.Selectors.getSelector(0, &II); + Selector S = Ctx.Selectors.getSelector(0, &II); ObjCMethodDecl* MD = 0; - + // Scan the instance methods for "dealloc". for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(), E = D->instmeth_end(); I!=E; ++I) { - + if ((*I)->getSelector() == S) { MD = *I; break; - } + } } - + if (!MD) { // No dealloc found. - - const char* name = LOpts.getGCMode() == LangOptions::NonGC - ? "missing -dealloc" + + const char* name = LOpts.getGCMode() == LangOptions::NonGC + ? "missing -dealloc" : "missing -dealloc (Hybrid MM, non-GC)"; - + std::string buf; llvm::raw_string_ostream os(buf); os << "Objective-C class '" << D->getNameAsString() << "' lacks a 'dealloc' instance method"; - + BR.EmitBasicReport(name, os.str().c_str(), D->getLocStart()); return; } - + // dealloc found. Scan for missing [super dealloc]. if (MD->getBody() && !scan_dealloc(MD->getBody(), S)) { - + const char* name = LOpts.getGCMode() == LangOptions::NonGC ? "missing [super dealloc]" : "missing [super dealloc] (Hybrid MM, non-GC)"; - + std::string buf; llvm::raw_string_ostream os(buf); os << "The 'dealloc' instance method in Objective-C class '" << D->getNameAsString() << "' does not send a 'dealloc' message to its super class" " (missing [super dealloc])"; - + BR.EmitBasicReport(name, os.str().c_str(), D->getLocStart()); return; - } - + } + // Get the "release" selector. IdentifierInfo* RII = &Ctx.Idents.get("release"); - Selector RS = Ctx.Selectors.getSelector(0, &RII); - + Selector RS = Ctx.Selectors.getSelector(0, &RII); + // Get the "self" identifier IdentifierInfo* SelfII = &Ctx.Idents.get("self"); - + // Scan for missing and extra releases of ivars used by implementations // of synthesized properties for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(), E = D->propimpl_end(); I!=E; ++I) { // We can only check the synthesized properties - if((*I)->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize) + if ((*I)->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize) continue; - + ObjCIvarDecl* ID = (*I)->getPropertyIvarDecl(); if (!ID) continue; - + QualType T = ID->getType(); - if (!Ctx.isObjCObjectPointerType(T)) // Skip non-pointer ivars + if (!T->isObjCObjectPointerType()) // Skip non-pointer ivars continue; const ObjCPropertyDecl* PD = (*I)->getPropertyDecl(); - if(!PD) + if (!PD) continue; - + // ivars cannot be set via read-only properties, so we'll skip them - if(PD->isReadOnly()) + if (PD->isReadOnly()) continue; - + // ivar must be released if and only if the kind of setter was not 'assign' bool requiresRelease = PD->getSetterKind() != ObjCPropertyDecl::Assign; - if(scan_ivar_release(MD->getBody(), ID, PD, RS, SelfII, Ctx) + if (scan_ivar_release(MD->getBody(), ID, PD, RS, SelfII, Ctx) != requiresRelease) { const char *name; const char* category = "Memory (Core Foundation/Objective-C)"; - + std::string buf; llvm::raw_string_ostream os(buf); - if(requiresRelease) { + if (requiresRelease) { name = LOpts.getGCMode() == LangOptions::NonGC ? "missing ivar release (leak)" : "missing ivar release (Hybrid MM, non-GC)"; - + os << "The '" << ID->getNameAsString() << "' instance variable was retained by a synthesized property but " - "wasn't released in 'dealloc'"; + "wasn't released in 'dealloc'"; } else { name = LOpts.getGCMode() == LangOptions::NonGC ? "extra ivar release (use-after-release)" : "extra ivar release (Hybrid MM, non-GC)"; - + os << "The '" << ID->getNameAsString() << "' instance variable was not retained by a synthesized property " "but was released in 'dealloc'"; } - + BR.EmitBasicReport(name, category, os.str().c_str(), (*I)->getLocation()); } diff --git a/lib/Analysis/CheckObjCInstMethSignature.cpp b/lib/Analysis/CheckObjCInstMethSignature.cpp index 28814867bd58..8c0d39629d50 100644 --- a/lib/Analysis/CheckObjCInstMethSignature.cpp +++ b/lib/Analysis/CheckObjCInstMethSignature.cpp @@ -30,25 +30,24 @@ static bool AreTypesCompatible(QualType Derived, QualType Ancestor, // Right now don't compare the compatibility of pointers. That involves // looking at subtyping relationships. FIXME: Future patch. - if ((Derived->isPointerType() || Derived->isObjCQualifiedIdType()) && - (Ancestor->isPointerType() || Ancestor->isObjCQualifiedIdType())) + if (Derived->isAnyPointerType() && Ancestor->isAnyPointerType()) return true; return C.typesAreCompatible(Derived, Ancestor); } -static void CompareReturnTypes(ObjCMethodDecl* MethDerived, - ObjCMethodDecl* MethAncestor, - BugReporter& BR, ASTContext& Ctx, - ObjCImplementationDecl* ID) { - +static void CompareReturnTypes(const ObjCMethodDecl *MethDerived, + const ObjCMethodDecl *MethAncestor, + BugReporter &BR, ASTContext &Ctx, + const ObjCImplementationDecl *ID) { + QualType ResDerived = MethDerived->getResultType(); - QualType ResAncestor = MethAncestor->getResultType(); - + QualType ResAncestor = MethAncestor->getResultType(); + if (!AreTypesCompatible(ResDerived, ResAncestor, Ctx)) { std::string sbuf; llvm::raw_string_ostream os(sbuf); - + os << "The Objective-C class '" << MethDerived->getClassInterface()->getNameAsString() << "', which is derived from class '" @@ -64,31 +63,31 @@ static void CompareReturnTypes(ObjCMethodDecl* MethDerived, << ResAncestor.getAsString() << "'. These two types are incompatible, and may result in undefined " "behavior for clients of these classes."; - + BR.EmitBasicReport("Incompatible instance method return type", os.str().c_str(), MethDerived->getLocStart()); } } -void clang::CheckObjCInstMethSignature(ObjCImplementationDecl* ID, +void clang::CheckObjCInstMethSignature(const ObjCImplementationDecl* ID, BugReporter& BR) { - - ObjCInterfaceDecl* D = ID->getClassInterface(); - ObjCInterfaceDecl* C = D->getSuperClass(); + + const ObjCInterfaceDecl* D = ID->getClassInterface(); + const ObjCInterfaceDecl* C = D->getSuperClass(); if (!C) return; - + ASTContext& Ctx = BR.getContext(); - + // Build a DenseMap of the methods for quick querying. typedef llvm::DenseMap MapTy; MapTy IMeths; unsigned NumMethods = 0; - + for (ObjCImplementationDecl::instmeth_iterator I=ID->instmeth_begin(), - E=ID->instmeth_end(); I!=E; ++I) { - + E=ID->instmeth_end(); I!=E; ++I) { + ObjCMethodDecl* M = *I; IMeths[M->getSelector()] = M; ++NumMethods; @@ -102,19 +101,19 @@ void clang::CheckObjCInstMethSignature(ObjCImplementationDecl* ID, ObjCMethodDecl* M = *I; Selector S = M->getSelector(); - + MapTy::iterator MI = IMeths.find(S); if (MI == IMeths.end() || MI->second == 0) continue; - + --NumMethods; ObjCMethodDecl* MethDerived = MI->second; MI->second = 0; - + CompareReturnTypes(MethDerived, M, BR, Ctx, ID); } - + C = C->getSuperClass(); } } diff --git a/lib/Analysis/CheckObjCUnusedIVars.cpp b/lib/Analysis/CheckObjCUnusedIVars.cpp index 0063c40482a0..1a900f897678 100644 --- a/lib/Analysis/CheckObjCUnusedIVars.cpp +++ b/lib/Analysis/CheckObjCUnusedIVars.cpp @@ -24,47 +24,56 @@ using namespace clang; enum IVarState { Unused, Used }; -typedef llvm::DenseMap IvarUsageMap; +typedef llvm::DenseMap IvarUsageMap; -static void Scan(IvarUsageMap& M, Stmt* S) { +static void Scan(IvarUsageMap& M, const Stmt* S) { if (!S) return; - - if (ObjCIvarRefExpr* Ex = dyn_cast(S)) { - ObjCIvarDecl* D = Ex->getDecl(); + + if (const ObjCIvarRefExpr *Ex = dyn_cast(S)) { + const ObjCIvarDecl *D = Ex->getDecl(); IvarUsageMap::iterator I = M.find(D); - if (I != M.end()) I->second = Used; + if (I != M.end()) + I->second = Used; + return; + } + + // Blocks can reference an instance variable of a class. + if (const BlockExpr *BE = dyn_cast(S)) { + Scan(M, BE->getBody()); return; } - - for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E;++I) + + for (Stmt::const_child_iterator I=S->child_begin(),E=S->child_end(); I!=E;++I) Scan(M, *I); } -static void Scan(IvarUsageMap& M, ObjCPropertyImplDecl* D) { +static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl* D) { if (!D) return; - - ObjCIvarDecl* ID = D->getPropertyIvarDecl(); + + const ObjCIvarDecl* ID = D->getPropertyIvarDecl(); if (!ID) return; - + IvarUsageMap::iterator I = M.find(ID); - if (I != M.end()) I->second = Used; + if (I != M.end()) + I->second = Used; } -void clang::CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR) { +void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, + BugReporter &BR) { - ObjCInterfaceDecl* ID = D->getClassInterface(); + const ObjCInterfaceDecl* ID = D->getClassInterface(); IvarUsageMap M; // Iterate over the ivars. - for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end(); - I!=E; ++I) { - - ObjCIvarDecl* ID = *I; - + for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), + E=ID->ivar_end(); I!=E; ++I) { + + const ObjCIvarDecl* ID = *I; + // Ignore ivars that aren't private. if (ID->getAccessControl() != ObjCIvarDecl::Private) continue; @@ -72,31 +81,31 @@ void clang::CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR) { // Skip IB Outlets. if (ID->getAttr()) continue; - + M[ID] = Unused; } if (M.empty()) return; - + // Now scan the methods for accesses. for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(), - E = D->instmeth_end(); I!=E; ++I) + E = D->instmeth_end(); I!=E; ++I) Scan(M, (*I)->getBody()); - + // Scan for @synthesized property methods that act as setters/getters // to an ivar. for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(), E = D->propimpl_end(); I!=E; ++I) - Scan(M, *I); - + Scan(M, *I); + // Find ivars that are unused. for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I) if (I->second == Unused) { std::string sbuf; llvm::raw_string_ostream os(sbuf); os << "Instance variable '" << I->first->getNameAsString() - << "' in class '" << ID->getNameAsString() + << "' in class '" << ID->getNameAsString() << "' is never used by the methods in its @implementation " "(although it may be used by category methods)."; @@ -104,4 +113,3 @@ void clang::CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR) { os.str().c_str(), I->first->getLocation()); } } - diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp new file mode 100644 index 000000000000..9f0d059cb66e --- /dev/null +++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp @@ -0,0 +1,409 @@ +//==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a set of flow-insensitive security checks. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Analysis/LocalCheckers.h" +#include "clang/AST/StmtVisitor.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +namespace { +class VISIBILITY_HIDDEN WalkAST : public StmtVisitor { + BugReporter &BR; + IdentifierInfo *II_gets; + enum { num_rands = 9 }; + IdentifierInfo *II_rand[num_rands]; + IdentifierInfo *II_random; + enum { num_setids = 6 }; + IdentifierInfo *II_setid[num_setids]; + +public: + WalkAST(BugReporter &br) : BR(br), + II_gets(0), II_rand(), II_random(0), II_setid() {} + + // Statement visitor methods. + void VisitCallExpr(CallExpr *CE); + void VisitForStmt(ForStmt *S); + void VisitCompoundStmt (CompoundStmt *S); + void VisitStmt(Stmt *S) { VisitChildren(S); } + + void VisitChildren(Stmt *S); + + // Helpers. + IdentifierInfo *GetIdentifier(IdentifierInfo *& II, const char *str); + + // Checker-specific methods. + void CheckLoopConditionForFloat(const ForStmt *FS); + void CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD); + void CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD); + void CheckCall_random(const CallExpr *CE, const FunctionDecl *FD); + void CheckUncheckedReturnValue(CallExpr *CE); +}; +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Helper methods. +//===----------------------------------------------------------------------===// + +IdentifierInfo *WalkAST::GetIdentifier(IdentifierInfo *& II, const char *str) { + if (!II) + II = &BR.getContext().Idents.get(str); + + return II; +} + +//===----------------------------------------------------------------------===// +// AST walking. +//===----------------------------------------------------------------------===// + +void WalkAST::VisitChildren(Stmt *S) { + for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I) + if (Stmt *child = *I) + Visit(child); +} + +void WalkAST::VisitCallExpr(CallExpr *CE) { + if (const FunctionDecl *FD = CE->getDirectCallee()) { + CheckCall_gets(CE, FD); + CheckCall_rand(CE, FD); + CheckCall_random(CE, FD); + } + + // Recurse and check children. + VisitChildren(CE); +} + +void WalkAST::VisitCompoundStmt(CompoundStmt *S) { + for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I) + if (Stmt *child = *I) { + if (CallExpr *CE = dyn_cast(child)) + CheckUncheckedReturnValue(CE); + Visit(child); + } +} + +void WalkAST::VisitForStmt(ForStmt *FS) { + CheckLoopConditionForFloat(FS); + + // Recurse and check children. + VisitChildren(FS); +} + +//===----------------------------------------------------------------------===// +// Check: floating poing variable used as loop counter. +// Originally: +// Implements: CERT security coding advisory FLP-30. +//===----------------------------------------------------------------------===// + +static const DeclRefExpr* +GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) { + expr = expr->IgnoreParenCasts(); + + if (const BinaryOperator *B = dyn_cast(expr)) { + if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() || + B->getOpcode() == BinaryOperator::Comma)) + return NULL; + + if (const DeclRefExpr *lhs = GetIncrementedVar(B->getLHS(), x, y)) + return lhs; + + if (const DeclRefExpr *rhs = GetIncrementedVar(B->getRHS(), x, y)) + return rhs; + + return NULL; + } + + if (const DeclRefExpr *DR = dyn_cast(expr)) { + const NamedDecl *ND = DR->getDecl(); + return ND == x || ND == y ? DR : NULL; + } + + if (const UnaryOperator *U = dyn_cast(expr)) + return U->isIncrementDecrementOp() + ? GetIncrementedVar(U->getSubExpr(), x, y) : NULL; + + return NULL; +} + +/// CheckLoopConditionForFloat - This check looks for 'for' statements that +/// use a floating point variable as a loop counter. +/// CERT: FLP30-C, FLP30-CPP. +/// +void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) { + // Does the loop have a condition? + const Expr *condition = FS->getCond(); + + if (!condition) + return; + + // Does the loop have an increment? + const Expr *increment = FS->getInc(); + + if (!increment) + return; + + // Strip away '()' and casts. + condition = condition->IgnoreParenCasts(); + increment = increment->IgnoreParenCasts(); + + // Is the loop condition a comparison? + const BinaryOperator *B = dyn_cast(condition); + + if (!B) + return; + + // Is this a comparison? + if (!(B->isRelationalOp() || B->isEqualityOp())) + return; + + // Are we comparing variables? + const DeclRefExpr *drLHS = dyn_cast(B->getLHS()->IgnoreParens()); + const DeclRefExpr *drRHS = dyn_cast(B->getRHS()->IgnoreParens()); + + // Does at least one of the variables have a floating point type? + drLHS = drLHS && drLHS->getType()->isFloatingType() ? drLHS : NULL; + drRHS = drRHS && drRHS->getType()->isFloatingType() ? drRHS : NULL; + + if (!drLHS && !drRHS) + return; + + const VarDecl *vdLHS = drLHS ? dyn_cast(drLHS->getDecl()) : NULL; + const VarDecl *vdRHS = drRHS ? dyn_cast(drRHS->getDecl()) : NULL; + + if (!vdLHS && !vdRHS) + return; + + // Does either variable appear in increment? + const DeclRefExpr *drInc = GetIncrementedVar(increment, vdLHS, vdRHS); + + if (!drInc) + return; + + // Emit the error. First figure out which DeclRefExpr in the condition + // referenced the compared variable. + const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS; + + llvm::SmallVector ranges; + std::string sbuf; + llvm::raw_string_ostream os(sbuf); + + os << "Variable '" << drCond->getDecl()->getNameAsCString() + << "' with floating point type '" << drCond->getType().getAsString() + << "' should not be used as a loop counter"; + + ranges.push_back(drCond->getSourceRange()); + ranges.push_back(drInc->getSourceRange()); + + const char *bugType = "Floating point variable used as loop counter"; + BR.EmitBasicReport(bugType, "Security", os.str().c_str(), + FS->getLocStart(), ranges.data(), ranges.size()); +} + +//===----------------------------------------------------------------------===// +// Check: Any use of 'gets' is insecure. +// Originally: +// Implements (part of): 300-BSI (buildsecurityin.us-cert.gov) +//===----------------------------------------------------------------------===// + +void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) { + if (FD->getIdentifier() != GetIdentifier(II_gets, "gets")) + return; + + const FunctionProtoType *FTP = dyn_cast(FD->getType()); + if (!FTP) + return; + + // Verify that the function takes a single argument. + if (FTP->getNumArgs() != 1) + return; + + // Is the argument a 'char*'? + const PointerType *PT = dyn_cast(FTP->getArgType(0)); + if (!PT) + return; + + if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy) + return; + + // Issue a warning. + SourceRange R = CE->getCallee()->getSourceRange(); + BR.EmitBasicReport("Potential buffer overflow in call to 'gets'", + "Security", + "Call to function 'gets' is extremely insecure as it can " + "always result in a buffer overflow", + CE->getLocStart(), &R, 1); +} + +//===----------------------------------------------------------------------===// +// Check: Linear congruent random number generators should not be used +// Originally: +// CWE-338: Use of cryptographically weak prng +//===----------------------------------------------------------------------===// + +void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) { + if (II_rand[0] == NULL) { + // This check applies to these functions + static const char * const identifiers[num_rands] = { + "drand48", "erand48", "jrand48", "lrand48", "mrand48", "nrand48", + "lcong48", + "rand", "rand_r" + }; + + for (size_t i = 0; i < num_rands; i++) + II_rand[i] = &BR.getContext().Idents.get(identifiers[i]); + } + + const IdentifierInfo *id = FD->getIdentifier(); + size_t identifierid; + + for (identifierid = 0; identifierid < num_rands; identifierid++) + if (id == II_rand[identifierid]) + break; + + if (identifierid >= num_rands) + return; + + const FunctionProtoType *FTP = dyn_cast(FD->getType()); + if (!FTP) + return; + + if (FTP->getNumArgs() == 1) { + // Is the argument an 'unsigned short *'? + // (Actually any integer type is allowed.) + const PointerType *PT = dyn_cast(FTP->getArgType(0)); + if (!PT) + return; + + if (! PT->getPointeeType()->isIntegerType()) + return; + } + else if (FTP->getNumArgs() != 0) + return; + + // Issue a warning. + std::string buf1; + llvm::raw_string_ostream os1(buf1); + os1 << "'" << FD->getNameAsString() << "' is a poor random number generator"; + + std::string buf2; + llvm::raw_string_ostream os2(buf2); + os2 << "Function '" << FD->getNameAsString() + << "' is obsolete because it implements a poor random number generator." + << " Use 'arc4random' instead"; + + SourceRange R = CE->getCallee()->getSourceRange(); + + BR.EmitBasicReport(os1.str().c_str(), "Security", os2.str().c_str(), + CE->getLocStart(), &R, 1); +} + +//===----------------------------------------------------------------------===// +// Check: 'random' should not be used +// Originally: +//===----------------------------------------------------------------------===// + +void WalkAST::CheckCall_random(const CallExpr *CE, const FunctionDecl *FD) { + if (FD->getIdentifier() != GetIdentifier(II_random, "random")) + return; + + const FunctionProtoType *FTP = dyn_cast(FD->getType()); + if (!FTP) + return; + + // Verify that the function takes no argument. + if (FTP->getNumArgs() != 0) + return; + + // Issue a warning. + SourceRange R = CE->getCallee()->getSourceRange(); + BR.EmitBasicReport("'random' is not a secure random number generator", + "Security", + "The 'random' function produces a sequence of values that " + "an adversary may be able to predict. Use 'arc4random' " + "instead", + CE->getLocStart(), &R, 1); +} + +//===----------------------------------------------------------------------===// +// Check: Should check whether privileges are dropped successfully. +// Originally: +//===----------------------------------------------------------------------===// + +void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) { + const FunctionDecl *FD = CE->getDirectCallee(); + if (!FD) + return; + + if (II_setid[0] == NULL) { + static const char * const identifiers[num_setids] = { + "setuid", "setgid", "seteuid", "setegid", + "setreuid", "setregid" + }; + + for (size_t i = 0; i < num_setids; i++) + II_setid[i] = &BR.getContext().Idents.get(identifiers[i]); + } + + const IdentifierInfo *id = FD->getIdentifier(); + size_t identifierid; + + for (identifierid = 0; identifierid < num_setids; identifierid++) + if (id == II_setid[identifierid]) + break; + + if (identifierid >= num_setids) + return; + + const FunctionProtoType *FTP = dyn_cast(FD->getType()); + if (!FTP) + return; + + // Verify that the function takes one or two arguments (depending on + // the function). + if (FTP->getNumArgs() != (identifierid < 4 ? 1 : 2)) + return; + + // The arguments must be integers. + for (unsigned i = 0; i < FTP->getNumArgs(); i++) + if (! FTP->getArgType(i)->isIntegerType()) + return; + + // Issue a warning. + std::string buf1; + llvm::raw_string_ostream os1(buf1); + os1 << "Return value is not checked in call to '" << FD->getNameAsString() + << "'"; + + std::string buf2; + llvm::raw_string_ostream os2(buf2); + os2 << "The return value from the call to '" << FD->getNameAsString() + << "' is not checked. If an error occurs in '" + << FD->getNameAsString() + << "', the following code may execute with unexpected privileges"; + + SourceRange R = CE->getCallee()->getSourceRange(); + + BR.EmitBasicReport(os1.str().c_str(), "Security", os2.str().c_str(), + CE->getLocStart(), &R, 1); +} + +//===----------------------------------------------------------------------===// +// Entry point for check. +//===----------------------------------------------------------------------===// + +void clang::CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR) { + WalkAST walker(BR); + walker.Visit(D->getBody()); +} diff --git a/lib/Analysis/Environment.cpp b/lib/Analysis/Environment.cpp index 3f8f14dcb0b4..1610ad4d271d 100644 --- a/lib/Analysis/Environment.cpp +++ b/lib/Analysis/Environment.cpp @@ -12,106 +12,81 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/PathSensitive/GRState.h" #include "clang/Analysis/Analyses/LiveVariables.h" -#include "llvm/ADT/ImmutableMap.h" -#include "llvm/Support/Streams.h" #include "llvm/Support/Compiler.h" +#include "llvm/ADT/ImmutableMap.h" using namespace clang; SVal Environment::GetSVal(const Stmt *E, ValueManager& ValMgr) const { - + for (;;) { - + switch (E->getStmtClass()) { - - case Stmt::AddrLabelExprClass: + + case Stmt::AddrLabelExprClass: return ValMgr.makeLoc(cast(E)); - + // ParenExprs are no-ops. - - case Stmt::ParenExprClass: + + case Stmt::ParenExprClass: E = cast(E)->getSubExpr(); continue; - + case Stmt::CharacterLiteralClass: { const CharacterLiteral* C = cast(E); return ValMgr.makeIntVal(C->getValue(), C->getType()); } - + case Stmt::IntegerLiteralClass: { return ValMgr.makeIntVal(cast(E)); } - + // Casts where the source and target type are the same // are no-ops. We blast through these to get the descendant // subexpression that has a value. - + case Stmt::ImplicitCastExprClass: case Stmt::CStyleCastExprClass: { const CastExpr* C = cast(E); QualType CT = C->getType(); - + if (CT->isVoidType()) return UnknownVal(); - + break; } - + // Handle all other Stmt* using a lookup. - + default: break; }; - + break; } - + return LookupExpr(E); } -SVal Environment::GetBlkExprSVal(const Stmt *E, ValueManager& ValMgr) const { - - while (1) { - switch (E->getStmtClass()) { - case Stmt::ParenExprClass: - E = cast(E)->getSubExpr(); - continue; - - case Stmt::CharacterLiteralClass: { - const CharacterLiteral* C = cast(E); - return ValMgr.makeIntVal(C->getValue(), C->getType()); - } - - case Stmt::IntegerLiteralClass: { - return ValMgr.makeIntVal(cast(E)); - } - - default: - return LookupBlkExpr(E); - } - } -} +Environment EnvironmentManager::BindExpr(Environment Env, const Stmt *S, + SVal V, bool Invalidate) { + assert(S); -Environment EnvironmentManager::BindExpr(const Environment& Env, const Stmt* E, - SVal V, bool isBlkExpr, - bool Invalidate) { - assert (E); - - if (V.isUnknown()) { + if (V.isUnknown()) { if (Invalidate) - return isBlkExpr ? RemoveBlkExpr(Env, E) : RemoveSubExpr(Env, E); + return Environment(F.Remove(Env.ExprBindings, S), Env.ACtx); else return Env; } - return isBlkExpr ? AddBlkExpr(Env, E, V) : AddSubExpr(Env, E, V); + return Environment(F.Add(Env.ExprBindings, S, V), Env.ACtx); } namespace { class VISIBILITY_HIDDEN MarkLiveCallback : public SymbolVisitor { SymbolReaper &SymReaper; public: - MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {} + MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {} bool VisitSymbol(SymbolRef sym) { SymReaper.markLive(sym); return true; } }; } // end anonymous namespace @@ -120,60 +95,66 @@ public: // - Remove subexpression bindings. // - Remove dead block expression bindings. // - Keep live block expression bindings: -// - Mark their reachable symbols live in SymbolReaper, +// - Mark their reachable symbols live in SymbolReaper, // see ScanReachableSymbols. // - Mark the region in DRoots if the binding is a loc::MemRegionVal. -Environment -EnvironmentManager::RemoveDeadBindings(Environment Env, Stmt* Loc, - SymbolReaper& SymReaper, - GRStateManager& StateMgr, - const GRState *state, - llvm::SmallVectorImpl& DRoots) { - - // Drop bindings for subexpressions. - Env = RemoveSubExprBindings(Env); +Environment +EnvironmentManager::RemoveDeadBindings(Environment Env, const Stmt *S, + SymbolReaper &SymReaper, + const GRState *ST, + llvm::SmallVectorImpl &DRoots) { + + CFG &C = *Env.getAnalysisContext().getCFG(); + + // We construct a new Environment object entirely, as this is cheaper than + // individually removing all the subexpression bindings (which will greatly + // outnumber block-level expression bindings). + Environment NewEnv = getInitialEnvironment(&Env.getAnalysisContext()); // Iterate over the block-expr bindings. - for (Environment::beb_iterator I = Env.beb_begin(), E = Env.beb_end(); + for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) { + const Stmt *BlkExpr = I.getKey(); - if (SymReaper.isLive(Loc, BlkExpr)) { - SVal X = I.getData(); + // Not a block-level expression? + if (!C.isBlkExpr(BlkExpr)) + continue; + + const SVal &X = I.getData(); + + if (SymReaper.isLive(S, BlkExpr)) { + // Copy the binding to the new map. + NewEnv.ExprBindings = F.Add(NewEnv.ExprBindings, BlkExpr, X); // If the block expr's value is a memory region, then mark that region. if (isa(X)) { const MemRegion* R = cast(X).getRegion(); DRoots.push_back(R); // Mark the super region of the RX as live. - // e.g.: int x; char *y = (char*) &x; if (*y) ... + // e.g.: int x; char *y = (char*) &x; if (*y) ... // 'y' => element region. 'x' is its super region. // We only add one level super region for now. // FIXME: maybe multiple level of super regions should be added. - if (const SubRegion *SR = dyn_cast(R)) { + if (const SubRegion *SR = dyn_cast(R)) DRoots.push_back(SR->getSuperRegion()); - } } // Mark all symbols in the block expr's value live. MarkLiveCallback cb(SymReaper); - state->scanReachableSymbols(X, cb); - } else { - // The block expr is dead. - SVal X = I.getData(); - - // Do not misclean LogicalExpr or ConditionalOperator. It is dead at the - // beginning of itself, but we need its UndefinedVal to determine its - // SVal. - - if (X.isUndef() && cast(X).getData()) - continue; - - Env = RemoveBlkExpr(Env, BlkExpr); + ST->scanReachableSymbols(X, cb); + continue; } + + // Otherwise the expression is dead with a couple exceptions. + // Do not misclean LogicalExpr or ConditionalOperator. It is dead at the + // beginning of itself, but we need its UndefinedVal to determine its + // SVal. + if (X.isUndef() && cast(X).getData()) + NewEnv.ExprBindings = F.Add(NewEnv.ExprBindings, BlkExpr, X); } - return Env; + return NewEnv; } diff --git a/lib/Analysis/ExplodedGraph.cpp b/lib/Analysis/ExplodedGraph.cpp index 20de6c48c387..0dc81a4225a8 100644 --- a/lib/Analysis/ExplodedGraph.cpp +++ b/lib/Analysis/ExplodedGraph.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/PathSensitive/ExplodedGraph.h" +#include "clang/Analysis/PathSensitive/GRState.h" #include "clang/AST/Stmt.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/DenseMap.h" @@ -26,193 +27,234 @@ using namespace clang; //===----------------------------------------------------------------------===// // An out of line virtual method to provide a home for the class vtable. -ExplodedNodeImpl::Auditor::~Auditor() {} +ExplodedNode::Auditor::~Auditor() {} #ifndef NDEBUG -static ExplodedNodeImpl::Auditor* NodeAuditor = 0; +static ExplodedNode::Auditor* NodeAuditor = 0; #endif -void ExplodedNodeImpl::SetAuditor(ExplodedNodeImpl::Auditor* A) { +void ExplodedNode::SetAuditor(ExplodedNode::Auditor* A) { #ifndef NDEBUG NodeAuditor = A; #endif } //===----------------------------------------------------------------------===// -// ExplodedNodeImpl. +// ExplodedNode. //===----------------------------------------------------------------------===// -static inline std::vector& getVector(void* P) { - return *reinterpret_cast*>(P); +static inline BumpVector& getVector(void* P) { + return *reinterpret_cast*>(P); } -void ExplodedNodeImpl::addPredecessor(ExplodedNodeImpl* V) { +void ExplodedNode::addPredecessor(ExplodedNode* V, ExplodedGraph &G) { assert (!V->isSink()); - Preds.addNode(V); - V->Succs.addNode(this); + Preds.addNode(V, G); + V->Succs.addNode(this, G); #ifndef NDEBUG if (NodeAuditor) NodeAuditor->AddEdge(V, this); #endif } -void ExplodedNodeImpl::NodeGroup::addNode(ExplodedNodeImpl* N) { - - assert ((reinterpret_cast(N) & Mask) == 0x0); - assert (!getFlag()); - +void ExplodedNode::NodeGroup::addNode(ExplodedNode* N, ExplodedGraph &G) { + assert((reinterpret_cast(N) & Mask) == 0x0); + assert(!getFlag()); + if (getKind() == Size1) { - if (ExplodedNodeImpl* NOld = getNode()) { - std::vector* V = new std::vector(); - assert ((reinterpret_cast(V) & Mask) == 0x0); - V->push_back(NOld); - V->push_back(N); + if (ExplodedNode* NOld = getNode()) { + BumpVectorContext &Ctx = G.getNodeAllocator(); + BumpVector *V = + G.getAllocator().Allocate >(); + new (V) BumpVector(Ctx, 4); + + assert((reinterpret_cast(V) & Mask) == 0x0); + V->push_back(NOld, Ctx); + V->push_back(N, Ctx); P = reinterpret_cast(V) | SizeOther; - assert (getPtr() == (void*) V); - assert (getKind() == SizeOther); + assert(getPtr() == (void*) V); + assert(getKind() == SizeOther); } else { P = reinterpret_cast(N); - assert (getKind() == Size1); + assert(getKind() == Size1); } } else { - assert (getKind() == SizeOther); - getVector(getPtr()).push_back(N); + assert(getKind() == SizeOther); + getVector(getPtr()).push_back(N, G.getNodeAllocator()); } } - -unsigned ExplodedNodeImpl::NodeGroup::size() const { +unsigned ExplodedNode::NodeGroup::size() const { if (getFlag()) return 0; - + if (getKind() == Size1) return getNode() ? 1 : 0; else return getVector(getPtr()).size(); } -ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::begin() const { +ExplodedNode **ExplodedNode::NodeGroup::begin() const { if (getFlag()) return NULL; - + if (getKind() == Size1) - return (ExplodedNodeImpl**) (getPtr() ? &P : NULL); + return (ExplodedNode**) (getPtr() ? &P : NULL); else - return const_cast(&*(getVector(getPtr()).begin())); + return const_cast(&*(getVector(getPtr()).begin())); } -ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::end() const { +ExplodedNode** ExplodedNode::NodeGroup::end() const { if (getFlag()) return NULL; - + if (getKind() == Size1) - return (ExplodedNodeImpl**) (getPtr() ? &P+1 : NULL); + return (ExplodedNode**) (getPtr() ? &P+1 : NULL); else { // Dereferencing end() is undefined behaviour. The vector is not empty, so // we can dereference the last elem and then add 1 to the result. - return const_cast(&getVector(getPtr()).back()) + 1; + return const_cast(getVector(getPtr()).end()); } } -ExplodedNodeImpl::NodeGroup::~NodeGroup() { - if (getKind() == SizeOther) delete &getVector(getPtr()); +ExplodedNode *ExplodedGraph::getNode(const ProgramPoint& L, + const GRState* State, bool* IsNew) { + // Profile 'State' to determine if we already have an existing node. + llvm::FoldingSetNodeID profile; + void* InsertPos = 0; + + NodeTy::Profile(profile, L, State); + NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos); + + if (!V) { + // Allocate a new node. + V = (NodeTy*) getAllocator().Allocate(); + new (V) NodeTy(L, State); + + // Insert the node into the node set and return it. + Nodes.InsertNode(V, InsertPos); + + ++NumNodes; + + if (IsNew) *IsNew = true; + } + else + if (IsNew) *IsNew = false; + + return V; +} + +std::pair +ExplodedGraph::Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd, + llvm::DenseMap *InverseMap) const { + + if (NBeg == NEnd) + return std::make_pair((ExplodedGraph*) 0, + (InterExplodedGraphMap*) 0); + + assert (NBeg < NEnd); + + llvm::OwningPtr M(new InterExplodedGraphMap()); + + ExplodedGraph* G = TrimInternal(NBeg, NEnd, M.get(), InverseMap); + + return std::make_pair(static_cast(G), M.take()); } -ExplodedGraphImpl* -ExplodedGraphImpl::Trim(const ExplodedNodeImpl* const* BeginSources, - const ExplodedNodeImpl* const* EndSources, - InterExplodedGraphMapImpl* M, - llvm::DenseMap *InverseMap) -const { - - typedef llvm::DenseSet Pass1Ty; +ExplodedGraph* +ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources, + const ExplodedNode* const* EndSources, + InterExplodedGraphMap* M, + llvm::DenseMap *InverseMap) const { + + typedef llvm::DenseSet Pass1Ty; Pass1Ty Pass1; - - typedef llvm::DenseMap Pass2Ty; + + typedef llvm::DenseMap Pass2Ty; Pass2Ty& Pass2 = M->M; - - llvm::SmallVector WL1, WL2; + + llvm::SmallVector WL1, WL2; // ===- Pass 1 (reverse DFS) -=== - for (const ExplodedNodeImpl* const* I = BeginSources; I != EndSources; ++I) { + for (const ExplodedNode* const* I = BeginSources; I != EndSources; ++I) { assert(*I); WL1.push_back(*I); } - + // Process the first worklist until it is empty. Because it is a std::list // it acts like a FIFO queue. while (!WL1.empty()) { - const ExplodedNodeImpl *N = WL1.back(); + const ExplodedNode *N = WL1.back(); WL1.pop_back(); - + // Have we already visited this node? If so, continue to the next one. if (Pass1.count(N)) continue; // Otherwise, mark this node as visited. Pass1.insert(N); - + // If this is a root enqueue it to the second worklist. if (N->Preds.empty()) { WL2.push_back(N); continue; } - + // Visit our predecessors and enqueue them. - for (ExplodedNodeImpl** I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) + for (ExplodedNode** I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) WL1.push_back(*I); } - + // We didn't hit a root? Return with a null pointer for the new graph. if (WL2.empty()) return 0; // Create an empty graph. - ExplodedGraphImpl* G = MakeEmptyGraph(); - - // ===- Pass 2 (forward DFS to construct the new graph) -=== + ExplodedGraph* G = MakeEmptyGraph(); + + // ===- Pass 2 (forward DFS to construct the new graph) -=== while (!WL2.empty()) { - const ExplodedNodeImpl* N = WL2.back(); + const ExplodedNode* N = WL2.back(); WL2.pop_back(); - + // Skip this node if we have already processed it. if (Pass2.find(N) != Pass2.end()) continue; - + // Create the corresponding node in the new graph and record the mapping // from the old node to the new node. - ExplodedNodeImpl* NewN = G->getNodeImpl(N->getLocation(), N->State, NULL); + ExplodedNode* NewN = G->getNode(N->getLocation(), N->State, NULL); Pass2[N] = NewN; - + // Also record the reverse mapping from the new node to the old node. if (InverseMap) (*InverseMap)[NewN] = N; - + // If this node is a root, designate it as such in the graph. if (N->Preds.empty()) G->addRoot(NewN); - + // In the case that some of the intended predecessors of NewN have already // been created, we should hook them up as predecessors. // Walk through the predecessors of 'N' and hook up their corresponding // nodes in the new graph (if any) to the freshly created node. - for (ExplodedNodeImpl **I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) { + for (ExplodedNode **I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) { Pass2Ty::iterator PI = Pass2.find(*I); if (PI == Pass2.end()) continue; - - NewN->addPredecessor(PI->second); + + NewN->addPredecessor(PI->second, *G); } // In the case that some of the intended successors of NewN have already // been created, we should hook them up as successors. Otherwise, enqueue // the new nodes from the original graph that should have nodes created // in the new graph. - for (ExplodedNodeImpl **I=N->Succs.begin(), **E=N->Succs.end(); I!=E; ++I) { - Pass2Ty::iterator PI = Pass2.find(*I); + for (ExplodedNode **I=N->Succs.begin(), **E=N->Succs.end(); I!=E; ++I) { + Pass2Ty::iterator PI = Pass2.find(*I); if (PI != Pass2.end()) { - PI->second->addPredecessor(NewN); + PI->second->addPredecessor(NewN, *G); continue; } @@ -220,22 +262,20 @@ const { if (Pass1.count(*I)) WL2.push_back(*I); } - + // Finally, explictly mark all nodes without any successors as sinks. if (N->isSink()) NewN->markAsSink(); } - + return G; } -ExplodedNodeImpl* -InterExplodedGraphMapImpl::getMappedImplNode(const ExplodedNodeImpl* N) const { - llvm::DenseMap::iterator I = +ExplodedNode* +InterExplodedGraphMap::getMappedNode(const ExplodedNode* N) const { + llvm::DenseMap::iterator I = M.find(N); return I == M.end() ? 0 : I->second; } -InterExplodedGraphMapImpl::InterExplodedGraphMapImpl() {} - diff --git a/lib/Analysis/GRBlockCounter.cpp b/lib/Analysis/GRBlockCounter.cpp index f69a16da401c..4f4103ac45b4 100644 --- a/lib/Analysis/GRBlockCounter.cpp +++ b/lib/Analysis/GRBlockCounter.cpp @@ -1,5 +1,5 @@ //==- GRBlockCounter.h - ADT for counting block visits -------------*- C++ -*-// -// +// // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Analysis/GRCoreEngine.cpp index ff7b548bc054..87472472fdee 100644 --- a/lib/Analysis/GRCoreEngine.cpp +++ b/lib/Analysis/GRCoreEngine.cpp @@ -1,5 +1,5 @@ //==- GRCoreEngine.cpp - Path-Sensitive Dataflow Engine ------------*- C++ -*-// -// +// // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/PathSensitive/GRCoreEngine.h" +#include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/AST/Expr.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Casting.h" @@ -29,7 +30,7 @@ using namespace clang; //===----------------------------------------------------------------------===// namespace { - class VISIBILITY_HIDDEN DFS : public GRWorkList { +class VISIBILITY_HIDDEN DFS : public GRWorkList { llvm::SmallVector Stack; public: virtual bool hasWork() const { @@ -47,27 +48,27 @@ public: return U; } }; - + class VISIBILITY_HIDDEN BFS : public GRWorkList { std::queue Queue; public: virtual bool hasWork() const { return !Queue.empty(); } - + virtual void Enqueue(const GRWorkListUnit& U) { Queue.push(U); } - + virtual GRWorkListUnit Dequeue() { // Don't use const reference. The subsequent pop_back() might make it // unsafe. - GRWorkListUnit U = Queue.front(); + GRWorkListUnit U = Queue.front(); Queue.pop(); return U; } }; - + } // end anonymous namespace // Place the dstor for GRWorkList here because it contains virtual member @@ -85,14 +86,14 @@ namespace { virtual bool hasWork() const { return !Queue.empty() || !Stack.empty(); } - + virtual void Enqueue(const GRWorkListUnit& U) { if (isa(U.getNode()->getLocation())) Queue.push(U); else Stack.push_back(U); } - + virtual GRWorkListUnit Dequeue() { // Process all basic blocks to completion. if (!Stack.empty()) { @@ -100,13 +101,13 @@ namespace { Stack.pop_back(); // This technically "invalidates" U, but we are fine. return U; } - + assert(!Queue.empty()); // Don't use const reference. The subsequent pop_back() might make it // unsafe. - GRWorkListUnit U = Queue.front(); + GRWorkListUnit U = Queue.front(); Queue.pop(); - return U; + return U; } }; } // end anonymous namespace @@ -118,55 +119,80 @@ GRWorkList* GRWorkList::MakeBFSBlockDFSContents() { //===----------------------------------------------------------------------===// // Core analysis engine. //===----------------------------------------------------------------------===// +void GRCoreEngine::ProcessEndPath(GREndPathNodeBuilder& Builder) { + SubEngine.ProcessEndPath(Builder); +} + +void GRCoreEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& Builder) { + SubEngine.ProcessStmt(S, Builder); +} + +bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const GRState* State, + GRBlockCounter BC) { + return SubEngine.ProcessBlockEntrance(Blk, State, BC); +} + +void GRCoreEngine::ProcessBranch(Stmt* Condition, Stmt* Terminator, + GRBranchNodeBuilder& Builder) { + SubEngine.ProcessBranch(Condition, Terminator, Builder); +} + +void GRCoreEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& Builder) { + SubEngine.ProcessIndirectGoto(Builder); +} + +void GRCoreEngine::ProcessSwitch(GRSwitchNodeBuilder& Builder) { + SubEngine.ProcessSwitch(Builder); +} /// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. -bool GRCoreEngineImpl::ExecuteWorkList(unsigned Steps) { - +bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) { + if (G->num_roots() == 0) { // Initialize the analysis by constructing // the root if none exists. - - CFGBlock* Entry = &getCFG().getEntry(); - - assert (Entry->empty() && + + CFGBlock* Entry = &(L->getCFG()->getEntry()); + + assert (Entry->empty() && "Entry block must be empty."); - + assert (Entry->succ_size() == 1 && "Entry block must have 1 successor."); - + // Get the solitary successor. - CFGBlock* Succ = *(Entry->succ_begin()); - + CFGBlock* Succ = *(Entry->succ_begin()); + // Construct an edge representing the // starting location in the function. - BlockEdge StartLoc(Entry, Succ); - + BlockEdge StartLoc(Entry, Succ, L); + // Set the current block counter to being empty. WList->setBlockCounter(BCounterFactory.GetEmptyCounter()); - + // Generate the root. - GenerateNode(StartLoc, getInitialState(), 0); + GenerateNode(StartLoc, getInitialState(L), 0); } - + while (Steps && WList->hasWork()) { --Steps; const GRWorkListUnit& WU = WList->Dequeue(); - + // Set the current block counter. WList->setBlockCounter(WU.getBlockCounter()); // Retrieve the node. - ExplodedNodeImpl* Node = WU.getNode(); - + ExplodedNode* Node = WU.getNode(); + // Dispatch on the location type. switch (Node->getLocation().getKind()) { case ProgramPoint::BlockEdgeKind: HandleBlockEdge(cast(Node->getLocation()), Node); break; - + case ProgramPoint::BlockEntranceKind: HandleBlockEntrance(cast(Node->getLocation()), Node); break; - + case ProgramPoint::BlockExitKind: assert (false && "BlockExit location never occur in forward analysis."); break; @@ -175,26 +201,26 @@ bool GRCoreEngineImpl::ExecuteWorkList(unsigned Steps) { assert(isa(Node->getLocation())); HandlePostStmt(cast(Node->getLocation()), WU.getBlock(), WU.getIndex(), Node); - break; + break; } } - + return WList->hasWork(); } -void GRCoreEngineImpl::HandleBlockEdge(const BlockEdge& L, - ExplodedNodeImpl* Pred) { - + +void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { + CFGBlock* Blk = L.getDst(); - - // Check if we are entering the EXIT block. - if (Blk == &getCFG().getExit()) { - - assert (getCFG().getExit().size() == 0 + + // Check if we are entering the EXIT block. + if (Blk == &(Pred->getLocationContext()->getCFG()->getExit())) { + + assert (Pred->getLocationContext()->getCFG()->getExit().size() == 0 && "EXIT block cannot contain Stmts."); // Process the final state transition. - GREndPathNodeBuilderImpl Builder(Blk, Pred, this); + GREndPathNodeBuilder Builder(Blk, Pred, this); ProcessEndPath(Builder); // This path is done. Don't enqueue any more nodes. @@ -202,84 +228,81 @@ void GRCoreEngineImpl::HandleBlockEdge(const BlockEdge& L, } // FIXME: Should we allow ProcessBlockEntrance to also manipulate state? - + if (ProcessBlockEntrance(Blk, Pred->State, WList->getBlockCounter())) - GenerateNode(BlockEntrance(Blk), Pred->State, Pred); + GenerateNode(BlockEntrance(Blk, Pred->getLocationContext()), Pred->State, Pred); } -void GRCoreEngineImpl::HandleBlockEntrance(const BlockEntrance& L, - ExplodedNodeImpl* Pred) { - +void GRCoreEngine::HandleBlockEntrance(const BlockEntrance& L, + ExplodedNode* Pred) { + // Increment the block counter. GRBlockCounter Counter = WList->getBlockCounter(); Counter = BCounterFactory.IncrementCount(Counter, L.getBlock()->getBlockID()); WList->setBlockCounter(Counter); - - // Process the entrance of the block. + + // Process the entrance of the block. if (Stmt* S = L.getFirstStmt()) { - GRStmtNodeBuilderImpl Builder(L.getBlock(), 0, Pred, this); + GRStmtNodeBuilder Builder(L.getBlock(), 0, Pred, this, + SubEngine.getStateManager()); ProcessStmt(S, Builder); } - else + else HandleBlockExit(L.getBlock(), Pred); } -GRCoreEngineImpl::~GRCoreEngineImpl() { - delete WList; -} +void GRCoreEngine::HandleBlockExit(CFGBlock * B, ExplodedNode* Pred) { -void GRCoreEngineImpl::HandleBlockExit(CFGBlock * B, ExplodedNodeImpl* Pred) { - if (Stmt* Term = B->getTerminator()) { switch (Term->getStmtClass()) { default: assert(false && "Analysis for this terminator not implemented."); break; - + case Stmt::BinaryOperatorClass: // '&&' and '||' HandleBranch(cast(Term)->getLHS(), Term, B, Pred); return; - + case Stmt::ConditionalOperatorClass: HandleBranch(cast(Term)->getCond(), Term, B, Pred); return; - + // FIXME: Use constant-folding in CFG construction to simplify this // case. - + case Stmt::ChooseExprClass: HandleBranch(cast(Term)->getCond(), Term, B, Pred); return; - + case Stmt::DoStmtClass: HandleBranch(cast(Term)->getCond(), Term, B, Pred); return; - + case Stmt::ForStmtClass: HandleBranch(cast(Term)->getCond(), Term, B, Pred); return; - + case Stmt::ContinueStmtClass: case Stmt::BreakStmtClass: - case Stmt::GotoStmtClass: + case Stmt::GotoStmtClass: break; - + case Stmt::IfStmtClass: HandleBranch(cast(Term)->getCond(), Term, B, Pred); return; - + case Stmt::IndirectGotoStmtClass: { // Only 1 successor: the indirect goto dispatch block. assert (B->succ_size() == 1); - - GRIndirectGotoNodeBuilderImpl + + GRIndirectGotoNodeBuilder builder(Pred, B, cast(Term)->getTarget(), *(B->succ_begin()), this); - + ProcessIndirectGoto(builder); return; } - + case Stmt::ObjCForCollectionStmtClass: { // In the case of ObjCForCollectionStmt, it appears twice in a CFG: // @@ -294,16 +317,15 @@ void GRCoreEngineImpl::HandleBlockExit(CFGBlock * B, ExplodedNodeImpl* Pred) { HandleBranch(Term, Term, B, Pred); return; } - + case Stmt::SwitchStmtClass: { - GRSwitchNodeBuilderImpl builder(Pred, B, - cast(Term)->getCond(), - this); - + GRSwitchNodeBuilder builder(Pred, B, cast(Term)->getCond(), + this); + ProcessSwitch(builder); return; } - + case Stmt::WhileStmtClass: HandleBranch(cast(Term)->getCond(), Term, B, Pred); return; @@ -312,265 +334,280 @@ void GRCoreEngineImpl::HandleBlockExit(CFGBlock * B, ExplodedNodeImpl* Pred) { assert (B->succ_size() == 1 && "Blocks with no terminator should have at most 1 successor."); - - GenerateNode(BlockEdge(B, *(B->succ_begin())), Pred->State, Pred); + + GenerateNode(BlockEdge(B, *(B->succ_begin()), Pred->getLocationContext()), + Pred->State, Pred); } -void GRCoreEngineImpl::HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock * B, - ExplodedNodeImpl* Pred) { +void GRCoreEngine::HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock * B, + ExplodedNode* Pred) { assert (B->succ_size() == 2); - GRBranchNodeBuilderImpl Builder(B, *(B->succ_begin()), *(B->succ_begin()+1), - Pred, this); - + GRBranchNodeBuilder Builder(B, *(B->succ_begin()), *(B->succ_begin()+1), + Pred, this); + ProcessBranch(Cond, Term, Builder); } -void GRCoreEngineImpl::HandlePostStmt(const PostStmt& L, CFGBlock* B, - unsigned StmtIdx, ExplodedNodeImpl* Pred) { - +void GRCoreEngine::HandlePostStmt(const PostStmt& L, CFGBlock* B, + unsigned StmtIdx, ExplodedNode* Pred) { + assert (!B->empty()); if (StmtIdx == B->size()) HandleBlockExit(B, Pred); else { - GRStmtNodeBuilderImpl Builder(B, StmtIdx, Pred, this); + GRStmtNodeBuilder Builder(B, StmtIdx, Pred, this, + SubEngine.getStateManager()); ProcessStmt((*B)[StmtIdx], Builder); } } /// GenerateNode - Utility method to generate nodes, hook up successors, /// and add nodes to the worklist. -void GRCoreEngineImpl::GenerateNode(const ProgramPoint& Loc, const void* State, - ExplodedNodeImpl* Pred) { - +void GRCoreEngine::GenerateNode(const ProgramPoint& Loc, + const GRState* State, ExplodedNode* Pred) { + bool IsNew; - ExplodedNodeImpl* Node = G->getNodeImpl(Loc, State, &IsNew); - - if (Pred) - Node->addPredecessor(Pred); // Link 'Node' with its predecessor. + ExplodedNode* Node = G->getNode(Loc, State, &IsNew); + + if (Pred) + Node->addPredecessor(Pred, *G); // Link 'Node' with its predecessor. else { assert (IsNew); G->addRoot(Node); // 'Node' has no predecessor. Make it a root. } - + // Only add 'Node' to the worklist if it was freshly generated. if (IsNew) WList->Enqueue(Node); } -GRStmtNodeBuilderImpl::GRStmtNodeBuilderImpl(CFGBlock* b, unsigned idx, - ExplodedNodeImpl* N, GRCoreEngineImpl* e) - : Eng(*e), B(*b), Idx(idx), Pred(N), LastNode(N) { +GRStmtNodeBuilder::GRStmtNodeBuilder(CFGBlock* b, unsigned idx, + ExplodedNode* N, GRCoreEngine* e, + GRStateManager &mgr) + : Eng(*e), B(*b), Idx(idx), Pred(N), LastNode(N), Mgr(mgr), Auditor(0), + PurgingDeadSymbols(false), BuildSinks(false), HasGeneratedNode(false), + PointKind(ProgramPoint::PostStmtKind), Tag(0) { Deferred.insert(N); + CleanedState = getLastNode()->getState(); } -GRStmtNodeBuilderImpl::~GRStmtNodeBuilderImpl() { +GRStmtNodeBuilder::~GRStmtNodeBuilder() { for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I) if (!(*I)->isSink()) GenerateAutoTransition(*I); } -void GRStmtNodeBuilderImpl::GenerateAutoTransition(ExplodedNodeImpl* N) { +void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { assert (!N->isSink()); - - PostStmt Loc(getStmt()); - + + PostStmt Loc(getStmt(), N->getLocationContext()); + if (Loc == N->getLocation()) { // Note: 'N' should be a fresh node because otherwise it shouldn't be // a member of Deferred. Eng.WList->Enqueue(N, B, Idx+1); return; } - + bool IsNew; - ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(Loc, N->State, &IsNew); - Succ->addPredecessor(N); + ExplodedNode* Succ = Eng.G->getNode(Loc, N->State, &IsNew); + Succ->addPredecessor(N, *Eng.G); if (IsNew) Eng.WList->Enqueue(Succ, B, Idx+1); } -static inline PostStmt GetPostLoc(Stmt* S, ProgramPoint::Kind K, - const void *tag) { +static inline PostStmt GetPostLoc(const Stmt* S, ProgramPoint::Kind K, + const LocationContext *L, const void *tag) { switch (K) { default: assert(false && "Invalid PostXXXKind."); - + case ProgramPoint::PostStmtKind: - return PostStmt(S, tag); - + return PostStmt(S, L, tag); + case ProgramPoint::PostLoadKind: - return PostLoad(S, tag); + return PostLoad(S, L, tag); case ProgramPoint::PostUndefLocationCheckFailedKind: - return PostUndefLocationCheckFailed(S, tag); + return PostUndefLocationCheckFailed(S, L, tag); case ProgramPoint::PostLocationChecksSucceedKind: - return PostLocationChecksSucceed(S, tag); - + return PostLocationChecksSucceed(S, L, tag); + case ProgramPoint::PostOutOfBoundsCheckFailedKind: - return PostOutOfBoundsCheckFailed(S, tag); - + return PostOutOfBoundsCheckFailed(S, L, tag); + case ProgramPoint::PostNullCheckFailedKind: - return PostNullCheckFailed(S, tag); - + return PostNullCheckFailed(S, L, tag); + case ProgramPoint::PostStoreKind: - return PostStore(S, tag); - + return PostStore(S, L, tag); + case ProgramPoint::PostLValueKind: - return PostLValue(S, tag); - + return PostLValue(S, L, tag); + case ProgramPoint::PostPurgeDeadSymbolsKind: - return PostPurgeDeadSymbols(S, tag); + return PostPurgeDeadSymbols(S, L, tag); } } -ExplodedNodeImpl* -GRStmtNodeBuilderImpl::generateNodeImpl(Stmt* S, const void* State, - ExplodedNodeImpl* Pred, +ExplodedNode* +GRStmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* State, + ExplodedNode* Pred, ProgramPoint::Kind K, const void *tag) { - return generateNodeImpl(GetPostLoc(S, K, tag), State, Pred); + return K == ProgramPoint::PreStmtKind + ? generateNodeInternal(PreStmt(S, Pred->getLocationContext(),tag), + State, Pred) + : generateNodeInternal(GetPostLoc(S, K, Pred->getLocationContext(), tag), + State, Pred); } -ExplodedNodeImpl* -GRStmtNodeBuilderImpl::generateNodeImpl(PostStmt Loc, const void* State, - ExplodedNodeImpl* Pred) { +ExplodedNode* +GRStmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc, + const GRState* State, + ExplodedNode* Pred) { bool IsNew; - ExplodedNodeImpl* N = Eng.G->getNodeImpl(Loc, State, &IsNew); - N->addPredecessor(Pred); + ExplodedNode* N = Eng.G->getNode(Loc, State, &IsNew); + N->addPredecessor(Pred, *Eng.G); Deferred.erase(Pred); - + if (IsNew) { Deferred.insert(N); LastNode = N; return N; } - + LastNode = NULL; - return NULL; + return NULL; } -ExplodedNodeImpl* GRBranchNodeBuilderImpl::generateNodeImpl(const void* State, - bool branch) { +ExplodedNode* GRBranchNodeBuilder::generateNode(const GRState* State, + bool branch) { + + // If the branch has been marked infeasible we should not generate a node. + if (!isFeasible(branch)) + return NULL; + bool IsNew; - - ExplodedNodeImpl* Succ = - Eng.G->getNodeImpl(BlockEdge(Src, branch ? DstT : DstF), State, &IsNew); - - Succ->addPredecessor(Pred); - - if (branch) GeneratedTrue = true; - else GeneratedFalse = true; - + + ExplodedNode* Succ = + Eng.G->getNode(BlockEdge(Src,branch ? DstT:DstF,Pred->getLocationContext()), + State, &IsNew); + + Succ->addPredecessor(Pred, *Eng.G); + + if (branch) + GeneratedTrue = true; + else + GeneratedFalse = true; + if (IsNew) { Deferred.push_back(Succ); return Succ; } - + return NULL; } -GRBranchNodeBuilderImpl::~GRBranchNodeBuilderImpl() { - if (!GeneratedTrue) generateNodeImpl(Pred->State, true); - if (!GeneratedFalse) generateNodeImpl(Pred->State, false); - +GRBranchNodeBuilder::~GRBranchNodeBuilder() { + if (!GeneratedTrue) generateNode(Pred->State, true); + if (!GeneratedFalse) generateNode(Pred->State, false); + for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I) if (!(*I)->isSink()) Eng.WList->Enqueue(*I); } -ExplodedNodeImpl* -GRIndirectGotoNodeBuilderImpl::generateNodeImpl(const Iterator& I, - const void* St, - bool isSink) { +ExplodedNode* +GRIndirectGotoNodeBuilder::generateNode(const iterator& I, const GRState* St, + bool isSink) { bool IsNew; - - ExplodedNodeImpl* Succ = - Eng.G->getNodeImpl(BlockEdge(Src, I.getBlock()), St, &IsNew); - - Succ->addPredecessor(Pred); - + + ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(), + Pred->getLocationContext()), St, &IsNew); + + Succ->addPredecessor(Pred, *Eng.G); + if (IsNew) { - + if (isSink) Succ->markAsSink(); else Eng.WList->Enqueue(Succ); - + return Succ; } - + return NULL; } -ExplodedNodeImpl* -GRSwitchNodeBuilderImpl::generateCaseStmtNodeImpl(const Iterator& I, - const void* St) { +ExplodedNode* +GRSwitchNodeBuilder::generateCaseStmtNode(const iterator& I, const GRState* St){ bool IsNew; - - ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(BlockEdge(Src, I.getBlock()), - St, &IsNew); - Succ->addPredecessor(Pred); - + + ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(), + Pred->getLocationContext()), St, &IsNew); + Succ->addPredecessor(Pred, *Eng.G); + if (IsNew) { Eng.WList->Enqueue(Succ); return Succ; } - + return NULL; } -ExplodedNodeImpl* -GRSwitchNodeBuilderImpl::generateDefaultCaseNodeImpl(const void* St, - bool isSink) { - +ExplodedNode* +GRSwitchNodeBuilder::generateDefaultCaseNode(const GRState* St, bool isSink) { + // Get the block for the default case. assert (Src->succ_rbegin() != Src->succ_rend()); CFGBlock* DefaultBlock = *Src->succ_rbegin(); - + bool IsNew; - - ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(BlockEdge(Src, DefaultBlock), - St, &IsNew); - Succ->addPredecessor(Pred); - + + ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock, + Pred->getLocationContext()), St, &IsNew); + Succ->addPredecessor(Pred, *Eng.G); + if (IsNew) { if (isSink) Succ->markAsSink(); else Eng.WList->Enqueue(Succ); - + return Succ; } - + return NULL; } -GREndPathNodeBuilderImpl::~GREndPathNodeBuilderImpl() { +GREndPathNodeBuilder::~GREndPathNodeBuilder() { // Auto-generate an EOP node if one has not been generated. - if (!HasGeneratedNode) generateNodeImpl(Pred->State); + if (!HasGeneratedNode) generateNode(Pred->State); } -ExplodedNodeImpl* -GREndPathNodeBuilderImpl::generateNodeImpl(const void* State, - const void *tag, - ExplodedNodeImpl* P) { - HasGeneratedNode = true; +ExplodedNode* +GREndPathNodeBuilder::generateNode(const GRState* State, const void *tag, + ExplodedNode* P) { + HasGeneratedNode = true; bool IsNew; - - ExplodedNodeImpl* Node = - Eng.G->getNodeImpl(BlockEntrance(&B, tag), State, &IsNew); - - Node->addPredecessor(P ? P : Pred); - + + ExplodedNode* Node = Eng.G->getNode(BlockEntrance(&B, + Pred->getLocationContext(), tag), State, &IsNew); + + Node->addPredecessor(P ? P : Pred, *Eng.G); + if (IsNew) { Eng.G->addEndOfPath(Node); return Node; } - + return NULL; } diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index d9117f5930e6..5079acef54b4 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -15,16 +15,16 @@ #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h" +#include "clang/Analysis/PathSensitive/Checker.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtObjC.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/PrettyStackTrace.h" -#include "llvm/Support/Streams.h" -#include "llvm/ADT/ImmutableList.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/ImmutableList.h" #ifndef NDEBUG #include "llvm/Support/GraphWriter.h" @@ -36,7 +36,7 @@ using llvm::cast; using llvm::APSInt; //===----------------------------------------------------------------------===// -// Engine construction and deletion. +// Batch auditor. DEPRECATED. //===----------------------------------------------------------------------===// namespace { @@ -44,7 +44,7 @@ namespace { class VISIBILITY_HIDDEN MappedBatchAuditor : public GRSimpleAPICheck { typedef llvm::ImmutableList Checks; typedef llvm::DenseMap MapTy; - + MapTy M; Checks::Factory F; Checks AllStmts; @@ -52,18 +52,18 @@ class VISIBILITY_HIDDEN MappedBatchAuditor : public GRSimpleAPICheck { public: MappedBatchAuditor(llvm::BumpPtrAllocator& Alloc) : F(Alloc), AllStmts(F.GetEmptyList()) {} - + virtual ~MappedBatchAuditor() { llvm::DenseSet AlreadyVisited; - + for (MapTy::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) for (Checks::iterator I=MI->second.begin(), E=MI->second.end(); I!=E;++I){ GRSimpleAPICheck* check = *I; - + if (AlreadyVisited.count(check)) continue; - + AlreadyVisited.insert(check); delete check; } @@ -75,33 +75,68 @@ public: MapTy::iterator I = M.find(key); M[key] = F.Concat(A, I == M.end() ? F.GetEmptyList() : I->second); } - + void AddCheck(GRSimpleAPICheck *A) { assert (A && "Check cannot be null."); - AllStmts = F.Concat(A, AllStmts); + AllStmts = F.Concat(A, AllStmts); } - virtual bool Audit(NodeTy* N, GRStateManager& VMgr) { + virtual bool Audit(ExplodedNode* N, GRStateManager& VMgr) { // First handle the auditors that accept all statements. bool isSink = false; for (Checks::iterator I = AllStmts.begin(), E = AllStmts.end(); I!=E; ++I) isSink |= (*I)->Audit(N, VMgr); - + // Next handle the auditors that accept only specific statements. - Stmt* S = cast(N->getLocation()).getStmt(); + const Stmt* S = cast(N->getLocation()).getStmt(); void* key = reinterpret_cast((uintptr_t) S->getStmtClass()); MapTy::iterator MI = M.find(key); - if (MI != M.end()) { + if (MI != M.end()) { for (Checks::iterator I=MI->second.begin(), E=MI->second.end(); I!=E; ++I) isSink |= (*I)->Audit(N, VMgr); } - - return isSink; + + return isSink; } }; } // end anonymous namespace +//===----------------------------------------------------------------------===// +// Checker worklist routines. +//===----------------------------------------------------------------------===// + +void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, + ExplodedNodeSet &Src, bool isPrevisit) { + + if (Checkers.empty()) { + Dst = Src; + return; + } + + ExplodedNodeSet Tmp; + ExplodedNodeSet *PrevSet = &Src; + + for (std::vector::iterator I = Checkers.begin(), E = Checkers.end(); + I != E; ++I) { + + ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst + : (PrevSet == &Tmp) ? &Src : &Tmp; + CurrSet->clear(); + Checker *checker = *I; + + for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); + NI != NE; ++NI) + checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, isPrevisit); + + // Update which NodeSet is the current one. + PrevSet = CurrSet; + } + + // Don't autotransition. The CheckerContext objects should do this + // automatically. +} + //===----------------------------------------------------------------------===// // Engine construction and deletion. //===----------------------------------------------------------------------===// @@ -112,29 +147,27 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { } -GRExprEngine::GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx, - LiveVariables& L, BugReporterData& BRD, - bool purgeDead, bool eagerlyAssume, - StoreManagerCreator SMC, - ConstraintManagerCreator CMC) - : CoreEngine(cfg, CD, Ctx, *this), +GRExprEngine::GRExprEngine(AnalysisManager &mgr) + : AMgr(mgr), + CoreEngine(mgr.getASTContext(), *this), G(CoreEngine.getGraph()), - Liveness(L), Builder(NULL), - StateMgr(G.getContext(), SMC, CMC, G.getAllocator(), cfg, CD, L), + StateMgr(G.getContext(), mgr.getStoreManagerCreator(), + mgr.getConstraintManagerCreator(), G.getAllocator()), SymMgr(StateMgr.getSymbolManager()), ValMgr(StateMgr.getValueManager()), - SVator(clang::CreateSimpleSValuator(ValMgr)), // FIXME: Generalize later. + SVator(ValMgr.getSValuator()), CurrentStmt(NULL), NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL), - RaiseSel(GetNullarySelector("raise", G.getContext())), - PurgeDead(purgeDead), - BR(BRD, *this), - EagerlyAssume(eagerlyAssume) {} + RaiseSel(GetNullarySelector("raise", G.getContext())), + BR(mgr, *this) {} -GRExprEngine::~GRExprEngine() { +GRExprEngine::~GRExprEngine() { BR.FlushReports(); delete [] NSExceptionInstanceRaiseSelectors; + for (std::vector::iterator I=Checkers.begin(), E=Checkers.end(); + I!=E; ++I) + delete *I; } //===----------------------------------------------------------------------===// @@ -151,7 +184,7 @@ void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) { void GRExprEngine::AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C) { if (!BatchAuditor) BatchAuditor.reset(new MappedBatchAuditor(getGraph().getAllocator())); - + ((MappedBatchAuditor*) BatchAuditor.get())->AddCheck(A, C); } @@ -162,29 +195,50 @@ void GRExprEngine::AddCheck(GRSimpleAPICheck *A) { ((MappedBatchAuditor*) BatchAuditor.get())->AddCheck(A); } -const GRState* GRExprEngine::getInitialState() { - const GRState *state = StateMgr.getInitialState(); - - // Precondition: the first argument of 'main' is an integer guaranteed - // to be > 0. +const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) { + const GRState *state = StateMgr.getInitialState(InitLoc); + + // Preconditions. + // FIXME: It would be nice if we had a more general mechanism to add // such preconditions. Some day. - if (const FunctionDecl *FD = dyn_cast(&StateMgr.getCodeDecl())) + const Decl *D = InitLoc->getDecl(); + + if (const FunctionDecl *FD = dyn_cast(D)) { + // Precondition: the first argument of 'main' is an integer guaranteed + // to be > 0. if (strcmp(FD->getIdentifier()->getName(), "main") == 0 && FD->getNumParams() > 0) { const ParmVarDecl *PD = FD->getParamDecl(0); QualType T = PD->getType(); if (T->isIntegerType()) - if (const MemRegion *R = state->getRegion(PD)) { + if (const MemRegion *R = state->getRegion(PD, InitLoc)) { SVal V = state->getSVal(loc::MemRegionVal(R)); - SVal Constraint = EvalBinOp(state, BinaryOperator::GT, V, - ValMgr.makeZeroVal(T), - getContext().IntTy); - - if (const GRState *newState = state->assume(Constraint, true)) - state = newState; + SVal Constraint_untested = EvalBinOp(state, BinaryOperator::GT, V, + ValMgr.makeZeroVal(T), + getContext().IntTy); + + if (DefinedOrUnknownSVal *Constraint = + dyn_cast(&Constraint_untested)) { + if (const GRState *newState = state->Assume(*Constraint, true)) + state = newState; + } } } + } + else if (const ObjCMethodDecl *MD = dyn_cast(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(&V)) { + // Assume that the pointer value in 'self' is non-null. + state = state->Assume(*LV, true); + assert(state && "'self' cannot be null"); + } + } return state; } @@ -193,32 +247,33 @@ const GRState* GRExprEngine::getInitialState() { // Top-level transfer function logic (Dispatcher). //===----------------------------------------------------------------------===// -void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) { - +void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { + PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), S->getLocStart(), "Error evaluating statement"); - + Builder = &builder; EntryNode = builder.getLastNode(); - + // FIXME: Consolidate. CurrentStmt = S; StateMgr.CurrentStmt = S; - + // Set up our simple checks. if (BatchAuditor) Builder->setAuditor(BatchAuditor.get()); - - // Create the cleaned state. - SymbolReaper SymReaper(Liveness, SymMgr); - CleanedState = PurgeDead ? StateMgr.RemoveDeadBindings(EntryNode->getState(), - CurrentStmt, SymReaper) - : EntryNode->getState(); + + // Create the cleaned state. + SymbolReaper SymReaper(Builder->getBasePredecessor()->getLiveVariables(), + SymMgr); + CleanedState = AMgr.shouldPurgeDead() + ? StateMgr.RemoveDeadBindings(EntryNode->getState(), CurrentStmt, SymReaper) + : EntryNode->getState(); // Process any special transfer function for dead symbols. - NodeSet Tmp; - + ExplodedNodeSet Tmp; + if (!SymReaper.hasDeadSymbols()) Tmp.Add(EntryNode); else { @@ -227,36 +282,36 @@ void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) { SaveAndRestore OldPurgeDeadSymbols(Builder->PurgingDeadSymbols); Builder->PurgingDeadSymbols = true; - - getTF().EvalDeadSymbols(Tmp, *this, *Builder, EntryNode, S, + + getTF().EvalDeadSymbols(Tmp, *this, *Builder, EntryNode, S, CleanedState, SymReaper); if (!Builder->BuildSinks && !Builder->HasGeneratedNode) Tmp.Add(EntryNode); } - + bool HasAutoGenerated = false; - for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - NodeSet Dst; - - // Set the cleaned state. + ExplodedNodeSet Dst; + + // Set the cleaned state. Builder->SetCleanedState(*I == EntryNode ? CleanedState : GetState(*I)); - - // Visit the statement. + + // Visit the statement. Visit(S, *I, Dst); // Do we need to auto-generate a node? We only need to do this to generate // a node with a "cleaned" state; GRCoreEngine will actually handle - // auto-transitions for other cases. + // auto-transitions for other cases. if (Dst.size() == 1 && *Dst.begin() == EntryNode && !Builder->HasGeneratedNode && !HasAutoGenerated) { HasAutoGenerated = true; builder.generateNode(S, GetState(EntryNode), *I); } } - + // NULL out these variables to cleanup. CleanedState = NULL; EntryNode = NULL; @@ -264,11 +319,11 @@ void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) { // FIXME: Consolidate. StateMgr.CurrentStmt = 0; CurrentStmt = 0; - + Builder = NULL; } -void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { +void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), S->getLocStart(), "Error evaluating statement"); @@ -276,46 +331,46 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { // FIXME: add metadata to the CFG so that we can disable // this check when we KNOW that there is no block-level subexpression. // The motivation is that this check requires a hashtable lookup. - - if (S != CurrentStmt && getCFG().isBlkExpr(S)) { + + if (S != CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S)) { Dst.Add(Pred); return; } - + switch (S->getStmtClass()) { - + default: // Cases we intentionally have "default" handle: // AddrLabelExpr, IntegerLiteral, CharacterLiteral - + Dst.Add(Pred); // No-op. Simply propagate the current state unchanged. break; - + case Stmt::ArraySubscriptExprClass: VisitArraySubscriptExpr(cast(S), Pred, Dst, false); break; - + case Stmt::AsmStmtClass: VisitAsmStmt(cast(S), Pred, Dst); break; - + case Stmt::BinaryOperatorClass: { BinaryOperator* B = cast(S); - + if (B->isLogicalOp()) { VisitLogicalExpr(B, Pred, Dst); break; } else if (B->getOpcode() == BinaryOperator::Comma) { const GRState* state = GetState(Pred); - MakeNode(Dst, B, Pred, state->bindExpr(B, state->getSVal(B->getRHS()))); + MakeNode(Dst, B, Pred, state->BindExpr(B, state->getSVal(B->getRHS()))); break; } - if (EagerlyAssume && (B->isRelationalOp() || B->isEqualityOp())) { - NodeSet Tmp; + if (AMgr.shouldEagerlyAssume() && (B->isRelationalOp() || B->isEqualityOp())) { + ExplodedNodeSet Tmp; VisitBinaryOperator(cast(S), Pred, Tmp); - EvalEagerlyAssume(Dst, Tmp, cast(S)); + EvalEagerlyAssume(Dst, Tmp, cast(S)); } else VisitBinaryOperator(cast(S), Pred, Dst); @@ -332,13 +387,13 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { // FIXME: ChooseExpr is really a constant. We need to fix // the CFG do not model them as explicit control-flow. - + case Stmt::ChooseExprClass: { // __builtin_choose_expr ChooseExpr* C = cast(S); VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); break; } - + case Stmt::CompoundAssignOperatorClass: VisitBinaryOperator(cast(S), Pred, Dst); break; @@ -346,22 +401,22 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { case Stmt::CompoundLiteralExprClass: VisitCompoundLiteralExpr(cast(S), Pred, Dst, false); break; - + case Stmt::ConditionalOperatorClass: { // '?' operator ConditionalOperator* C = cast(S); VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); break; } - + case Stmt::DeclRefExprClass: case Stmt::QualifiedDeclRefExprClass: VisitDeclRefExpr(cast(S), Pred, Dst, false); break; - + case Stmt::DeclStmtClass: VisitDeclStmt(cast(S), Pred, Dst); break; - + case Stmt::ImplicitCastExprClass: case Stmt::CStyleCastExprClass: { CastExpr* C = cast(S); @@ -372,11 +427,11 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { case Stmt::InitListExprClass: VisitInitListExpr(cast(S), Pred, Dst); break; - + case Stmt::MemberExprClass: VisitMemberExpr(cast(S), Pred, Dst, false); break; - + case Stmt::ObjCIvarRefExprClass: VisitObjCIvarRefExpr(cast(S), Pred, Dst, false); break; @@ -384,12 +439,12 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { case Stmt::ObjCForCollectionStmtClass: VisitObjCForCollectionStmt(cast(S), Pred, Dst); break; - + case Stmt::ObjCMessageExprClass: { VisitObjCMessageExpr(cast(S), Pred, Dst); break; } - + case Stmt::ObjCAtThrowStmtClass: { // FIXME: This is not complete. We basically treat @throw as // an abort. @@ -398,19 +453,19 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { MakeNode(Dst, S, Pred, GetState(Pred)); break; } - + case Stmt::ParenExprClass: Visit(cast(S)->getSubExpr()->IgnoreParens(), Pred, Dst); break; - + case Stmt::ReturnStmtClass: VisitReturnStmt(cast(S), Pred, Dst); break; - + case Stmt::SizeOfAlignOfExprClass: VisitSizeOfAlignOfExpr(cast(S), Pred, Dst); break; - + case Stmt::StmtExprClass: { StmtExpr* SE = cast(S); @@ -421,25 +476,25 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { Dst.Add(Pred); break; } - + if (Expr* LastExpr = dyn_cast(*SE->getSubStmt()->body_rbegin())) { const GRState* state = GetState(Pred); - MakeNode(Dst, SE, Pred, state->bindExpr(SE, state->getSVal(LastExpr))); + MakeNode(Dst, SE, Pred, state->BindExpr(SE, state->getSVal(LastExpr))); } else Dst.Add(Pred); - + break; } case Stmt::StringLiteralClass: VisitLValue(cast(S), Pred, Dst); break; - + case Stmt::UnaryOperatorClass: { UnaryOperator *U = cast(S); - if (EagerlyAssume && (U->getOpcode() == UnaryOperator::LNot)) { - NodeSet Tmp; + if (AMgr.shouldEagerlyAssume() && (U->getOpcode() == UnaryOperator::LNot)) { + ExplodedNodeSet Tmp; VisitUnaryOperator(U, Pred, Tmp, false); EvalEagerlyAssume(Dst, Tmp, U); } @@ -450,44 +505,45 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { } } -void GRExprEngine::VisitLValue(Expr* Ex, NodeTy* Pred, NodeSet& Dst) { - +void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, + ExplodedNodeSet& Dst) { + Ex = Ex->IgnoreParens(); - - if (Ex != CurrentStmt && getCFG().isBlkExpr(Ex)) { + + if (Ex != CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)) { Dst.Add(Pred); return; } - + switch (Ex->getStmtClass()) { - + case Stmt::ArraySubscriptExprClass: VisitArraySubscriptExpr(cast(Ex), Pred, Dst, true); return; - + case Stmt::DeclRefExprClass: case Stmt::QualifiedDeclRefExprClass: VisitDeclRefExpr(cast(Ex), Pred, Dst, true); return; - + case Stmt::ObjCIvarRefExprClass: VisitObjCIvarRefExpr(cast(Ex), Pred, Dst, true); return; - + case Stmt::UnaryOperatorClass: VisitUnaryOperator(cast(Ex), Pred, Dst, true); return; - + case Stmt::MemberExprClass: VisitMemberExpr(cast(Ex), Pred, Dst, true); return; - + case Stmt::CompoundLiteralExprClass: VisitCompoundLiteralExpr(cast(Ex), Pred, Dst, true); return; - + case Stmt::ObjCPropertyRefExprClass: - case Stmt::ObjCKVCRefExprClass: + case Stmt::ObjCImplicitSetterGetterRefExprClass: // FIXME: Property assignments are lvalues, but not really "locations". // e.g.: self.x = something; // Here the "self.x" really can translate to a method call (setter) when @@ -505,10 +561,10 @@ void GRExprEngine::VisitLValue(Expr* Ex, NodeTy* Pred, NodeSet& Dst) { case Stmt::StringLiteralClass: { const GRState* state = GetState(Pred); SVal V = state->getLValue(cast(Ex)); - MakeNode(Dst, Ex, Pred, state->bindExpr(Ex, V)); + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V)); return; } - + default: // Arbitrary subexpressions can return aggregate temporaries that // can be used in a lvalue context. We need to enhance our support @@ -517,7 +573,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, NodeTy* Pred, NodeSet& Dst) { assert ((Ex->getType()->isAggregateType()) && "Other kinds of expressions with non-aggregate/union types do" " not have lvalues."); - + Visit(Ex, Pred, Dst); } } @@ -528,7 +584,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, NodeTy* Pred, NodeSet& Dst) { bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const GRState*, GRBlockCounter BC) { - + return BC.getNumVisited(B->getBlockID()) < 3; } @@ -536,12 +592,9 @@ bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const GRState*, // Generic node creation. //===----------------------------------------------------------------------===// -GRExprEngine::NodeTy* GRExprEngine::MakeNode(NodeSet& Dst, Stmt* S, - NodeTy* Pred, - const GRState* St, - ProgramPoint::Kind K, - const void *tag) { - +ExplodedNode* GRExprEngine::MakeNode(ExplodedNodeSet& Dst, Stmt* S, + ExplodedNode* Pred, const GRState* St, + ProgramPoint::Kind K, const void *tag) { assert (Builder && "GRStmtNodeBuilder not present."); SaveAndRestore OldTag(Builder->Tag); Builder->Tag = tag; @@ -555,54 +608,54 @@ GRExprEngine::NodeTy* GRExprEngine::MakeNode(NodeSet& Dst, Stmt* S, const GRState* GRExprEngine::MarkBranch(const GRState* state, Stmt* Terminator, bool branchTaken) { - + switch (Terminator->getStmtClass()) { default: return state; - + case Stmt::BinaryOperatorClass: { // '&&' and '||' - + BinaryOperator* B = cast(Terminator); BinaryOperator::Opcode Op = B->getOpcode(); - + assert (Op == BinaryOperator::LAnd || Op == BinaryOperator::LOr); - + // For &&, if we take the true branch, then the value of the whole // expression is that of the RHS expression. // // For ||, if we take the false branch, then the value of the whole // expression is that of the RHS expression. - + Expr* Ex = (Op == BinaryOperator::LAnd && branchTaken) || - (Op == BinaryOperator::LOr && !branchTaken) + (Op == BinaryOperator::LOr && !branchTaken) ? B->getRHS() : B->getLHS(); - - return state->bindBlkExpr(B, UndefinedVal(Ex)); + + return state->BindExpr(B, UndefinedVal(Ex)); } - + case Stmt::ConditionalOperatorClass: { // ?: - + ConditionalOperator* C = cast(Terminator); - + // For ?, if branchTaken == true then the value is either the LHS or // the condition itself. (GNU extension). - - Expr* Ex; - + + Expr* Ex; + if (branchTaken) - Ex = C->getLHS() ? C->getLHS() : C->getCond(); + Ex = C->getLHS() ? C->getLHS() : C->getCond(); else Ex = C->getRHS(); - - return state->bindBlkExpr(C, UndefinedVal(Ex)); + + return state->BindExpr(C, UndefinedVal(Ex)); } - + case Stmt::ChooseExprClass: { // ?: - + ChooseExpr* C = cast(Terminator); - - Expr* Ex = branchTaken ? C->getLHS() : C->getRHS(); - return state->bindBlkExpr(C, UndefinedVal(Ex)); + + Expr* Ex = branchTaken ? C->getLHS() : C->getRHS(); + return state->BindExpr(C, UndefinedVal(Ex)); } } } @@ -621,19 +674,19 @@ static SVal RecoverCastedSymbol(GRStateManager& StateMgr, const GRState* state, uint64_t bits = 0; bool bitsInit = false; - + while (CastExpr *CE = dyn_cast(Ex)) { QualType T = CE->getType(); if (!T->isIntegerType()) return UnknownVal(); - + uint64_t newBits = Ctx.getTypeSize(T); if (!bitsInit || newBits < bits) { bitsInit = true; bits = newBits; } - + Ex = CE->getSubExpr(); } @@ -642,211 +695,215 @@ static SVal RecoverCastedSymbol(GRStateManager& StateMgr, const GRState* state, if (!bitsInit || !T->isIntegerType() || Ctx.getTypeSize(T) > bits) return UnknownVal(); - + return state->getSVal(Ex); } void GRExprEngine::ProcessBranch(Stmt* Condition, Stmt* Term, - BranchNodeBuilder& builder) { - - // Remove old bindings for subexpressions. - const GRState* PrevState = - StateMgr.RemoveSubExprBindings(builder.getState()); - + GRBranchNodeBuilder& builder) { + // Check for NULL conditions; e.g. "for(;;)" - if (!Condition) { + if (!Condition) { builder.markInfeasible(false); return; } - + PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), Condition->getLocStart(), "Error evaluating branch"); + + const GRState* PrevState = builder.getState(); + SVal X = PrevState->getSVal(Condition); + DefinedSVal *V = NULL; - SVal V = PrevState->getSVal(Condition); - - switch (V.getBaseKind()) { - default: - break; + while (true) { + V = dyn_cast(&X); - case SVal::UnknownKind: { - if (Expr *Ex = dyn_cast(Condition)) { + if (!V) { + if (X.isUnknown()) { + if (const Expr *Ex = dyn_cast(Condition)) { if (Ex->getType()->isIntegerType()) { - // Try to recover some path-sensitivity. Right now casts of symbolic - // integers that promote their values are currently not tracked well. - // If 'Condition' is such an expression, try and recover the - // underlying value and use that instead. - SVal recovered = RecoverCastedSymbol(getStateManager(), - builder.getState(), Condition, - getContext()); - - if (!recovered.isUnknown()) { - V = recovered; - break; + // Try to recover some path-sensitivity. Right now casts of symbolic + // integers that promote their values are currently not tracked well. + // If 'Condition' is such an expression, try and recover the + // underlying value and use that instead. + SVal recovered = RecoverCastedSymbol(getStateManager(), + builder.getState(), Condition, + getContext()); + + if (!recovered.isUnknown()) { + X = recovered; + continue; + } } - } + } + + builder.generateNode(MarkBranch(PrevState, Term, true), true); + builder.generateNode(MarkBranch(PrevState, Term, false), false); + return; } - - builder.generateNode(MarkBranch(PrevState, Term, true), true); - builder.generateNode(MarkBranch(PrevState, Term, false), false); - return; - } - - case SVal::UndefinedKind: { - NodeTy* N = builder.generateNode(PrevState, true); + + assert(X.isUndef()); + ExplodedNode *N = builder.generateNode(PrevState, true); if (N) { N->markAsSink(); UndefBranches.insert(N); } - + builder.markInfeasible(false); return; - } - } + } + break; + } + // Process the true branch. - if (const GRState *state = PrevState->assume(V, true)) - builder.generateNode(MarkBranch(state, Term, true), true); - else - builder.markInfeasible(true); - - // Process the false branch. - if (const GRState *state = PrevState->assume(V, false)) - builder.generateNode(MarkBranch(state, Term, false), false); - else - builder.markInfeasible(false); + if (builder.isFeasible(true)) { + if (const GRState *state = PrevState->Assume(*V, true)) + builder.generateNode(MarkBranch(state, Term, true), true); + else + builder.markInfeasible(true); + } + + // Process the false branch. + if (builder.isFeasible(false)) { + if (const GRState *state = PrevState->Assume(*V, false)) + builder.generateNode(MarkBranch(state, Term, false), false); + else + builder.markInfeasible(false); + } } /// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor /// nodes by processing the 'effects' of a computed goto jump. -void GRExprEngine::ProcessIndirectGoto(IndirectGotoNodeBuilder& builder) { +void GRExprEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) { - const GRState *state = builder.getState(); + const GRState *state = builder.getState(); SVal V = state->getSVal(builder.getTarget()); - + // Three possibilities: // // (1) We know the computed label. // (2) The label is NULL (or some other constant), or Undefined. // (3) We have no clue about the label. Dispatch to all targets. // - - typedef IndirectGotoNodeBuilder::iterator iterator; + + typedef GRIndirectGotoNodeBuilder::iterator iterator; if (isa(V)) { LabelStmt* L = cast(V).getLabel(); - + for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) { if (I.getLabel() == L) { builder.generateNode(I, state); return; } } - + assert (false && "No block with label."); return; } if (isa(V) || isa(V)) { // Dispatch to the first target and mark it as a sink. - NodeTy* N = builder.generateNode(builder.begin(), state, true); + ExplodedNode* N = builder.generateNode(builder.begin(), state, true); UndefBranches.insert(N); return; } - + // This is really a catch-all. We don't support symbolics yet. // FIXME: Implement dispatch for symbolic pointers. - + for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) builder.generateNode(I, state); } void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, - NodeTy* Pred, NodeSet& Dst) { - - assert (Ex == CurrentStmt && getCFG().isBlkExpr(Ex)); - + ExplodedNode* Pred, ExplodedNodeSet& Dst) { + + assert (Ex == CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)); + const GRState* state = GetState(Pred); - SVal X = state->getBlkExprSVal(Ex); - + SVal X = state->getSVal(Ex); + assert (X.isUndef()); - + Expr *SE = (Expr*) cast(X).getData(); - assert(SE); - X = state->getBlkExprSVal(SE); - + assert(SE); + X = state->getSVal(SE); + // Make sure that we invalidate the previous binding. - MakeNode(Dst, Ex, Pred, state->bindExpr(Ex, X, true, true)); + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, X, true)); } /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor /// nodes by processing the 'effects' of a switch statement. -void GRExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) { - typedef SwitchNodeBuilder::iterator iterator; - const GRState* state = builder.getState(); +void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { + typedef GRSwitchNodeBuilder::iterator iterator; + const GRState* state = builder.getState(); Expr* CondE = builder.getCondition(); - SVal CondV = state->getSVal(CondE); + SVal CondV_untested = state->getSVal(CondE); - if (CondV.isUndef()) { - NodeTy* N = builder.generateDefaultCaseNode(state, true); + if (CondV_untested.isUndef()) { + ExplodedNode* N = builder.generateDefaultCaseNode(state, true); UndefBranches.insert(N); return; } + DefinedOrUnknownSVal CondV = cast(CondV_untested); - const GRState* DefaultSt = state; + const GRState *DefaultSt = state; bool defaultIsFeasible = false; - + for (iterator I = builder.begin(), EI = builder.end(); I != EI; ++I) { CaseStmt* Case = cast(I.getCase()); // Evaluate the LHS of the case value. Expr::EvalResult V1; - bool b = Case->getLHS()->Evaluate(V1, getContext()); - + bool b = Case->getLHS()->Evaluate(V1, getContext()); + // Sanity checks. These go away in Release builds. - assert(b && V1.Val.isInt() && !V1.HasSideEffects + assert(b && V1.Val.isInt() && !V1.HasSideEffects && "Case condition must evaluate to an integer constant."); - b = b; // silence unused variable warning - assert(V1.Val.getInt().getBitWidth() == + b = b; // silence unused variable warning + assert(V1.Val.getInt().getBitWidth() == getContext().getTypeSize(CondE->getType())); - + // Get the RHS of the case, if it exists. Expr::EvalResult V2; - + if (Expr* E = Case->getRHS()) { b = E->Evaluate(V2, getContext()); - assert(b && V2.Val.isInt() && !V2.HasSideEffects + assert(b && V2.Val.isInt() && !V2.HasSideEffects && "Case condition must evaluate to an integer constant."); b = b; // silence unused variable warning } else V2 = V1; - + // FIXME: Eventually we should replace the logic below with a range // comparison, rather than concretize the values within the range. // This should be easy once we have "ranges" for NonLVals. - + do { - nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt())); - SVal Res = EvalBinOp(DefaultSt, BinaryOperator::EQ, CondV, CaseVal, - getContext().IntTy); - - // Now "assume" that the case matches. - if (const GRState* stateNew = state->assume(Res, true)) { + nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt())); + DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt, CondV, CaseVal); + + // Now "assume" that the case matches. + if (const GRState* stateNew = state->Assume(Res, true)) { builder.generateCaseStmtNode(I, stateNew); - + // If CondV evaluates to a constant, then we know that this // is the *only* case that we can take, so stop evaluating the // others. if (isa(CondV)) return; } - + // Now "assume" that the case doesn't match. Add this state // to the default state (if it is feasible). - if (const GRState *stateNew = DefaultSt->assume(Res, false)) { + if (const GRState *stateNew = DefaultSt->Assume(Res, false)) { defaultIsFeasible = true; DefaultSt = stateNew; } @@ -854,15 +911,15 @@ void GRExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) { // Concretize the next value in the range. if (V1.Val.getInt() == V2.Val.getInt()) break; - + ++V1.Val.getInt(); assert (V1.Val.getInt() <= V2.Val.getInt()); - + } while (true); } - + // If we reach here, than we know that the default branch is - // possible. + // possible. if (defaultIsFeasible) builder.generateDefaultCaseNode(DefaultSt); } @@ -870,74 +927,72 @@ void GRExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) { // Transfer functions: logical operations ('&&', '||'). //===----------------------------------------------------------------------===// -void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, - NodeSet& Dst) { - +void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, + ExplodedNodeSet& Dst) { + assert(B->getOpcode() == BinaryOperator::LAnd || B->getOpcode() == BinaryOperator::LOr); - - assert(B == CurrentStmt && getCFG().isBlkExpr(B)); - + + assert(B == CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(B)); + const GRState* state = GetState(Pred); - SVal X = state->getBlkExprSVal(B); + SVal X = state->getSVal(B); assert(X.isUndef()); - - Expr* Ex = (Expr*) cast(X).getData(); - + + const Expr *Ex = (const Expr*) cast(X).getData(); assert(Ex); - + if (Ex == B->getRHS()) { - - X = state->getBlkExprSVal(Ex); - + X = state->getSVal(Ex); + // Handle undefined values. - if (X.isUndef()) { - MakeNode(Dst, B, Pred, state->bindBlkExpr(B, X)); + MakeNode(Dst, B, Pred, state->BindExpr(B, X)); return; } + DefinedOrUnknownSVal XD = cast(X); + // We took the RHS. Because the value of the '&&' or '||' expression must // evaluate to 0 or 1, we must assume the value of the RHS evaluates to 0 // or 1. Alternatively, we could take a lazy approach, and calculate this // value later when necessary. We don't have the machinery in place for // this right now, and since most logical expressions are used for branches, - // the payoff is not likely to be large. Instead, we do eager evaluation. - if (const GRState *newState = state->assume(X, true)) - MakeNode(Dst, B, Pred, - newState->bindBlkExpr(B, ValMgr.makeIntVal(1U, B->getType()))); - - if (const GRState *newState = state->assume(X, false)) - MakeNode(Dst, B, Pred, - newState->bindBlkExpr(B, ValMgr.makeIntVal(0U, B->getType()))); + // the payoff is not likely to be large. Instead, we do eager evaluation. + if (const GRState *newState = state->Assume(XD, true)) + MakeNode(Dst, B, Pred, + newState->BindExpr(B, ValMgr.makeIntVal(1U, B->getType()))); + + if (const GRState *newState = state->Assume(XD, false)) + MakeNode(Dst, B, Pred, + newState->BindExpr(B, ValMgr.makeIntVal(0U, B->getType()))); } else { // We took the LHS expression. Depending on whether we are '&&' or // '||' we know what the value of the expression is via properties of // the short-circuiting. - X = ValMgr.makeIntVal(B->getOpcode() == BinaryOperator::LAnd ? 0U : 1U, + X = ValMgr.makeIntVal(B->getOpcode() == BinaryOperator::LAnd ? 0U : 1U, B->getType()); - MakeNode(Dst, B, Pred, state->bindBlkExpr(B, X)); + MakeNode(Dst, B, Pred, state->BindExpr(B, X)); } } - + //===----------------------------------------------------------------------===// // Transfer functions: Loads and stores. //===----------------------------------------------------------------------===// -void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* Ex, NodeTy* Pred, NodeSet& Dst, - bool asLValue) { - - const GRState* state = GetState(Pred); +void GRExprEngine::VisitDeclRefExpr(DeclRefExpr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst, bool asLValue) { - const NamedDecl* D = Ex->getDecl(); + const GRState *state = GetState(Pred); + const NamedDecl *D = Ex->getDecl(); if (const VarDecl* VD = dyn_cast(D)) { - SVal V = state->getLValue(VD); + SVal V = state->getLValue(VD, Pred->getLocationContext()); if (asLValue) - MakeNode(Dst, Ex, Pred, state->bindExpr(Ex, V), + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), ProgramPoint::PostLValueKind); else EvalLoad(Dst, Ex, Pred, state, V); @@ -947,29 +1002,30 @@ void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* Ex, NodeTy* Pred, NodeSet& Dst, assert(!asLValue && "EnumConstantDecl does not have lvalue."); SVal V = ValMgr.makeIntVal(ED->getInitVal()); - MakeNode(Dst, Ex, Pred, state->bindExpr(Ex, V)); + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V)); return; } else if (const FunctionDecl* FD = dyn_cast(D)) { - assert(asLValue); + // This code is valid regardless of the value of 'isLValue'. SVal V = ValMgr.getFunctionPointer(FD); - MakeNode(Dst, Ex, Pred, state->bindExpr(Ex, V), + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), ProgramPoint::PostLValueKind); return; } - + assert (false && "ValueDecl support for this ValueDecl not implemented."); } /// VisitArraySubscriptExpr - Transfer function for array accesses -void GRExprEngine::VisitArraySubscriptExpr(ArraySubscriptExpr* A, NodeTy* Pred, - NodeSet& Dst, bool asLValue) { - +void GRExprEngine::VisitArraySubscriptExpr(ArraySubscriptExpr* A, + ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue){ + Expr* Base = A->getBase()->IgnoreParens(); Expr* Idx = A->getIdx()->IgnoreParens(); - NodeSet Tmp; - + ExplodedNodeSet Tmp; + if (Base->getType()->isVectorType()) { // For vector types get its lvalue. // FIXME: This may not be correct. Is the rvalue of a vector its location? @@ -977,20 +1033,20 @@ void GRExprEngine::VisitArraySubscriptExpr(ArraySubscriptExpr* A, NodeTy* Pred, // semantics. VisitLValue(Base, Pred, Tmp); } - else + else Visit(Base, Pred, Tmp); // Get Base's rvalue, which should be an LocVal. - - for (NodeSet::iterator I1=Tmp.begin(), E1=Tmp.end(); I1!=E1; ++I1) { - NodeSet Tmp2; + + for (ExplodedNodeSet::iterator I1=Tmp.begin(), E1=Tmp.end(); I1!=E1; ++I1) { + ExplodedNodeSet Tmp2; Visit(Idx, *I1, Tmp2); // Evaluate the index. - - for (NodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end(); I2!=E2; ++I2) { + + for (ExplodedNodeSet::iterator I2=Tmp2.begin(),E2=Tmp2.end();I2!=E2; ++I2) { const GRState* state = GetState(*I2); - SVal V = state->getLValue(A->getType(), state->getSVal(Base), - state->getSVal(Idx)); + SVal V = state->getLValue(A->getType(), state->getSVal(Idx), + state->getSVal(Base)); if (asLValue) - MakeNode(Dst, A, *I2, state->bindExpr(A, V), + MakeNode(Dst, A, *I2, state->BindExpr(A, V), ProgramPoint::PostLValueKind); else EvalLoad(Dst, A, *I2, state, V); @@ -999,30 +1055,30 @@ void GRExprEngine::VisitArraySubscriptExpr(ArraySubscriptExpr* A, NodeTy* Pred, } /// VisitMemberExpr - Transfer function for member expressions. -void GRExprEngine::VisitMemberExpr(MemberExpr* M, NodeTy* Pred, - NodeSet& Dst, bool asLValue) { - +void GRExprEngine::VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue) { + Expr* Base = M->getBase()->IgnoreParens(); - NodeSet Tmp; - - if (M->isArrow()) + ExplodedNodeSet Tmp; + + if (M->isArrow()) Visit(Base, Pred, Tmp); // p->f = ... or ... = p->f else VisitLValue(Base, Pred, Tmp); // x.f = ... or ... = x.f - + FieldDecl *Field = dyn_cast(M->getMemberDecl()); if (!Field) // FIXME: skipping member expressions for non-fields return; - for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { const GRState* state = GetState(*I); // FIXME: Should we insert some assumption logic in here to determine // if "Base" is a valid piece of memory? Before we put this assumption // later when using FieldOffset lvals (which we no longer have). - SVal L = state->getLValue(state->getSVal(Base), Field); + SVal L = state->getLValue(Field, state->getSVal(Base)); if (asLValue) - MakeNode(Dst, M, *I, state->bindExpr(M, L), + MakeNode(Dst, M, *I, state->BindExpr(M, L), ProgramPoint::PostLValueKind); else EvalLoad(Dst, M, *I, state, L); @@ -1031,11 +1087,11 @@ void GRExprEngine::VisitMemberExpr(MemberExpr* M, NodeTy* Pred, /// EvalBind - Handle the semantics of binding a value to a specific location. /// This method is used by EvalStore and (soon) VisitDeclStmt, and others. -void GRExprEngine::EvalBind(NodeSet& Dst, Expr* Ex, NodeTy* Pred, - const GRState* state, SVal location, SVal Val) { +void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, + const GRState* state, SVal location, SVal Val) { const GRState* newState = 0; - + if (location.isUnknown()) { // We know that the new state will be the same as the old state since // the location of the binding is "unknown". Consequently, there @@ -1053,7 +1109,7 @@ void GRExprEngine::EvalBind(NodeSet& Dst, Expr* Ex, NodeTy* Pred, // doesn't do anything, just auto-propagate the current state. GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, Pred, newState, Ex, newState != state); - + getTF().EvalBind(BuilderRef, location, Val); } @@ -1063,22 +1119,22 @@ void GRExprEngine::EvalBind(NodeSet& Dst, Expr* Ex, NodeTy* Pred, /// @param state The current simulation state /// @param location The location to store the value /// @param Val The value to be stored -void GRExprEngine::EvalStore(NodeSet& Dst, Expr* Ex, NodeTy* Pred, +void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, const GRState* state, SVal location, SVal Val, const void *tag) { - + assert (Builder && "GRStmtNodeBuilder must be defined."); - + // Evaluate the location (checks for bad dereferences). Pred = EvalLocation(Ex, Pred, state, location, tag); - + if (!Pred) return; assert (!location.isUndef()); state = GetState(Pred); - // Proceed with the store. + // Proceed with the store. SaveAndRestore OldSPointKind(Builder->PointKind); SaveAndRestore OldTag(Builder->Tag); Builder->PointKind = ProgramPoint::PostStoreKind; @@ -1086,18 +1142,18 @@ void GRExprEngine::EvalStore(NodeSet& Dst, Expr* Ex, NodeTy* Pred, EvalBind(Dst, Ex, Pred, state, location, Val); } -void GRExprEngine::EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred, +void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, const GRState* state, SVal location, const void *tag) { - // Evaluate the location (checks for bad dereferences). + // Evaluate the location (checks for bad dereferences). Pred = EvalLocation(Ex, Pred, state, location, tag); - + if (!Pred) return; - + state = GetState(Pred); - + // Proceed with the load. ProgramPoint::Kind K = ProgramPoint::PostLoadKind; @@ -1106,86 +1162,89 @@ void GRExprEngine::EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred, if (location.isUnknown()) { // This is important. We must nuke the old binding. - MakeNode(Dst, Ex, Pred, state->bindExpr(Ex, UnknownVal()), K, tag); + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, UnknownVal()), + K, tag); } else { SVal V = state->getSVal(cast(location), Ex->getType()); - MakeNode(Dst, Ex, Pred, state->bindExpr(Ex, V), K, tag); + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), K, tag); } } -void GRExprEngine::EvalStore(NodeSet& Dst, Expr* Ex, Expr* StoreE, NodeTy* Pred, - const GRState* state, SVal location, SVal Val, - const void *tag) { - - NodeSet TmpDst; +void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr* Ex, Expr* StoreE, + ExplodedNode* Pred, const GRState* state, + SVal location, SVal Val, const void *tag) { + + ExplodedNodeSet TmpDst; EvalStore(TmpDst, StoreE, Pred, state, location, Val, tag); - for (NodeSet::iterator I=TmpDst.begin(), E=TmpDst.end(); I!=E; ++I) + for (ExplodedNodeSet::iterator I=TmpDst.begin(), E=TmpDst.end(); I!=E; ++I) MakeNode(Dst, Ex, *I, (*I)->getState(), ProgramPoint::PostStmtKind, tag); } -GRExprEngine::NodeTy* GRExprEngine::EvalLocation(Stmt* Ex, NodeTy* Pred, - const GRState* state, - SVal location, - const void *tag) { - +ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred, + const GRState* state, SVal location, + const void *tag) { + SaveAndRestore OldTag(Builder->Tag); Builder->Tag = tag; - - // Check for loads/stores from/to undefined values. + + // Check for loads/stores from/to undefined values. if (location.isUndef()) { - NodeTy* N = + ExplodedNode* N = Builder->generateNode(Ex, state, Pred, ProgramPoint::PostUndefLocationCheckFailedKind); - + if (N) { N->markAsSink(); UndefDeref.insert(N); } - + return 0; } - + // Check for loads/stores from/to unknown locations. Treat as No-Ops. if (location.isUnknown()) return Pred; - + // During a load, one of two possible situations arise: // (1) A crash, because the location (pointer) was NULL. // (2) The location (pointer) is not NULL, and the dereference works. - // + // // We add these assumptions. - - Loc LV = cast(location); - + + Loc LV = cast(location); + // "Assume" that the pointer is not NULL. - const GRState *StNotNull = state->assume(LV, true); - + const GRState *StNotNull = state->Assume(LV, true); + // "Assume" that the pointer is NULL. - const GRState *StNull = state->assume(LV, false); + const GRState *StNull = state->Assume(LV, false); - if (StNull) { + if (StNull) { // Use the Generic Data Map to mark in the state what lval was null. const SVal* PersistentLV = getBasicVals().getPersistentSVal(LV); StNull = StNull->set(PersistentLV); - + // We don't use "MakeNode" here because the node will be a sink // and we have no intention of processing it later. - NodeTy* NullNode = - Builder->generateNode(Ex, StNull, Pred, + ExplodedNode* NullNode = + Builder->generateNode(Ex, StNull, Pred, ProgramPoint::PostNullCheckFailedKind); - if (NullNode) { - NullNode->markAsSink(); + if (NullNode) { + NullNode->markAsSink(); if (StNotNull) ImplicitNullDeref.insert(NullNode); else ExplicitNullDeref.insert(NullNode); } } - + if (!StNotNull) return NULL; + // FIXME: Temporarily disable out-of-bounds checking until we make + // the logic reflect recent changes to CastRegion and friends. +#if 0 // Check for out-of-bound array access. if (isa(LV)) { const MemRegion* R = cast(LV).getRegion(); @@ -1196,14 +1255,14 @@ GRExprEngine::NodeTy* GRExprEngine::EvalLocation(Stmt* Ex, NodeTy* Pred, SVal NumElements = getStoreManager().getSizeInElements(StNotNull, ER->getSuperRegion()); - const GRState * StInBound = StNotNull->assumeInBound(Idx, NumElements, + const GRState * StInBound = StNotNull->AssumeInBound(Idx, NumElements, true); - const GRState* StOutBound = StNotNull->assumeInBound(Idx, NumElements, + const GRState* StOutBound = StNotNull->AssumeInBound(Idx, NumElements, false); if (StOutBound) { // Report warning. Make sink node manually. - NodeTy* OOBNode = + ExplodedNode* OOBNode = Builder->generateNode(Ex, StOutBound, Pred, ProgramPoint::PostOutOfBoundsCheckFailedKind); @@ -1223,7 +1282,8 @@ GRExprEngine::NodeTy* GRExprEngine::EvalLocation(Stmt* Ex, NodeTy* Pred, StNotNull = StInBound; } } - +#endif + // Generate a new node indicating the checks succeed. return Builder->generateNode(Ex, StNotNull, Pred, ProgramPoint::PostLocationChecksSucceedKind); @@ -1239,105 +1299,127 @@ GRExprEngine::NodeTy* GRExprEngine::EvalLocation(Stmt* Ex, NodeTy* Pred, // http://developer.apple.com/documentation/Darwin/Reference/Manpages/man3 // atomic.3.html // -static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet& Dst, +static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - CallExpr* CE, SVal L, - ExplodedNode* Pred) { + GRStmtNodeBuilder& Builder, + CallExpr* CE, SVal L, + ExplodedNode* Pred) { // Not enough arguments to match OSAtomicCompareAndSwap? if (CE->getNumArgs() != 3) return false; - + ASTContext &C = Engine.getContext(); Expr *oldValueExpr = CE->getArg(0); QualType oldValueType = C.getCanonicalType(oldValueExpr->getType()); Expr *newValueExpr = CE->getArg(1); QualType newValueType = C.getCanonicalType(newValueExpr->getType()); - + // Do the types of 'oldValue' and 'newValue' match? if (oldValueType != newValueType) return false; - + Expr *theValueExpr = CE->getArg(2); - const PointerType *theValueType = theValueExpr->getType()->getAsPointerType(); - + const PointerType *theValueType = + theValueExpr->getType()->getAs(); + // theValueType not a pointer? if (!theValueType) return false; - + QualType theValueTypePointee = C.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType(); - + // The pointee must match newValueType and oldValueType. if (theValueTypePointee != newValueType) return false; - + static unsigned magic_load = 0; static unsigned magic_store = 0; const void *OSAtomicLoadTag = &magic_load; const void *OSAtomicStoreTag = &magic_store; - + // Load 'theValue'. const GRState *state = Pred->getState(); - ExplodedNodeSet Tmp; + ExplodedNodeSet Tmp; SVal location = state->getSVal(theValueExpr); Engine.EvalLoad(Tmp, theValueExpr, Pred, state, location, OSAtomicLoadTag); - for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { - - ExplodedNode *N = *I; + + ExplodedNode *N = *I; const GRState *stateLoad = N->getState(); - SVal theValueVal = stateLoad->getSVal(theValueExpr); - SVal oldValueVal = stateLoad->getSVal(oldValueExpr); - - // Perform the comparison. - SVal Cmp = Engine.EvalBinOp(stateLoad, BinaryOperator::EQ, theValueVal, - oldValueVal, Engine.getContext().IntTy); + SVal theValueVal_untested = stateLoad->getSVal(theValueExpr); + SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr); - const GRState *stateEqual = stateLoad->assume(Cmp, true); + // FIXME: Issue an error. + if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) { + return false; + } + DefinedOrUnknownSVal theValueVal = + cast(theValueVal_untested); + DefinedOrUnknownSVal oldValueVal = + cast(oldValueVal_untested); + + SValuator &SVator = Engine.getSValuator(); + + // Perform the comparison. + DefinedOrUnknownSVal Cmp = SVator.EvalEQ(stateLoad, theValueVal, + oldValueVal); + + const GRState *stateEqual = stateLoad->Assume(Cmp, true); + // Were they equal? if (stateEqual) { // Perform the store. - ExplodedNodeSet TmpStore; - Engine.EvalStore(TmpStore, theValueExpr, N, stateEqual, location, - stateEqual->getSVal(newValueExpr), OSAtomicStoreTag); - + ExplodedNodeSet TmpStore; + SVal val = stateEqual->getSVal(newValueExpr); + + // Handle implicit value casts. + if (const TypedRegion *R = + dyn_cast_or_null(location.getAsRegion())) { + llvm::tie(state, val) = SVator.EvalCast(val, state, R->getValueType(C), + newValueExpr->getType()); + } + + Engine.EvalStore(TmpStore, theValueExpr, N, stateEqual, location, + val, OSAtomicStoreTag); + // Now bind the result of the comparison. - for (ExplodedNodeSet::iterator I2 = TmpStore.begin(), + for (ExplodedNodeSet::iterator I2 = TmpStore.begin(), E2 = TmpStore.end(); I2 != E2; ++I2) { - ExplodedNode *predNew = *I2; + ExplodedNode *predNew = *I2; const GRState *stateNew = predNew->getState(); SVal Res = Engine.getValueManager().makeTruthVal(true, CE->getType()); - Engine.MakeNode(Dst, CE, predNew, stateNew->bindExpr(CE, Res)); + Engine.MakeNode(Dst, CE, predNew, stateNew->BindExpr(CE, Res)); } } - + // Were they not equal? - if (const GRState *stateNotEqual = stateLoad->assume(Cmp, false)) { + if (const GRState *stateNotEqual = stateLoad->Assume(Cmp, false)) { SVal Res = Engine.getValueManager().makeTruthVal(false, CE->getType()); - Engine.MakeNode(Dst, CE, N, stateNotEqual->bindExpr(CE, Res)); + Engine.MakeNode(Dst, CE, N, stateNotEqual->BindExpr(CE, Res)); } } - + return true; } -static bool EvalOSAtomic(ExplodedNodeSet& Dst, +static bool EvalOSAtomic(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, + GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, - ExplodedNode* Pred) { + ExplodedNode* Pred) { const FunctionDecl* FD = L.getAsFunctionDecl(); if (!FD) return false; const char *FName = FD->getNameAsCString(); - + // Check for compare and swap. if (strncmp(FName, "OSAtomicCompareAndSwap", 22) == 0 || strncmp(FName, "objc_atomicCompareAndSwap", 25) == 0) @@ -1350,37 +1432,163 @@ static bool EvalOSAtomic(ExplodedNodeSet& Dst, //===----------------------------------------------------------------------===// // Transfer function: Function calls. //===----------------------------------------------------------------------===// +static void MarkNoReturnFunction(const FunctionDecl *FD, CallExpr *CE, + const GRState *state, + GRStmtNodeBuilder *Builder) { + if (!FD) + return; + + if (FD->getAttr() || + FD->getAttr()) + Builder->BuildSinks = true; + else { + // HACK: Some functions are not marked noreturn, and don't return. + // Here are a few hardwired ones. If this takes too long, we can + // potentially cache these results. + const char* s = FD->getIdentifier()->getName(); + unsigned n = strlen(s); + + switch (n) { + default: + break; -void GRExprEngine::EvalCall(NodeSet& Dst, CallExpr* CE, SVal L, NodeTy* Pred) { + case 4: + if (!memcmp(s, "exit", 4)) Builder->BuildSinks = true; + break; + + case 5: + if (!memcmp(s, "panic", 5)) Builder->BuildSinks = true; + else if (!memcmp(s, "error", 5)) { + if (CE->getNumArgs() > 0) { + SVal X = state->getSVal(*CE->arg_begin()); + // FIXME: use Assume to inspect the possible symbolic value of + // X. Also check the specific signature of error(). + nonloc::ConcreteInt* CI = dyn_cast(&X); + if (CI && CI->getValue() != 0) + Builder->BuildSinks = true; + } + } + break; + + case 6: + if (!memcmp(s, "Assert", 6)) { + Builder->BuildSinks = true; + break; + } + + // FIXME: This is just a wrapper around throwing an exception. + // Eventually inter-procedural analysis should handle this easily. + if (!memcmp(s, "ziperr", 6)) Builder->BuildSinks = true; + + break; + + case 7: + if (!memcmp(s, "assfail", 7)) Builder->BuildSinks = true; + break; + + case 8: + if (!memcmp(s ,"db_error", 8) || + !memcmp(s, "__assert", 8)) + Builder->BuildSinks = true; + break; + + case 12: + if (!memcmp(s, "__assert_rtn", 12)) Builder->BuildSinks = true; + break; + + case 13: + if (!memcmp(s, "__assert_fail", 13)) Builder->BuildSinks = true; + break; + + case 14: + if (!memcmp(s, "dtrace_assfail", 14) || + !memcmp(s, "yy_fatal_error", 14)) + Builder->BuildSinks = true; + break; + + case 26: + if (!memcmp(s, "_XCAssertionFailureHandler", 26) || + !memcmp(s, "_DTAssertionFailureHandler", 26) || + !memcmp(s, "_TSAssertionFailureHandler", 26)) + Builder->BuildSinks = true; + + break; + } + + } +} + +bool GRExprEngine::EvalBuiltinFunction(const FunctionDecl *FD, CallExpr *CE, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + if (!FD) + return false; + + unsigned id = FD->getBuiltinID(); + if (!id) + return false; + + const GRState *state = Pred->getState(); + + switch (id) { + case Builtin::BI__builtin_expect: { + // For __builtin_expect, just return the value of the subexpression. + assert (CE->arg_begin() != CE->arg_end()); + SVal X = state->getSVal(*(CE->arg_begin())); + MakeNode(Dst, CE, Pred, state->BindExpr(CE, X)); + return true; + } + + case Builtin::BI__builtin_alloca: { + // FIXME: Refactor into StoreManager itself? + MemRegionManager& RM = getStateManager().getRegionManager(); + const MemRegion* R = + RM.getAllocaRegion(CE, Builder->getCurrentBlockCount()); + + // Set the extent of the region in bytes. This enables us to use the + // SVal of the argument directly. If we save the extent in bits, we + // cannot represent values like symbol*8. + SVal Extent = state->getSVal(*(CE->arg_begin())); + state = getStoreManager().setExtent(state, R, Extent); + MakeNode(Dst, CE, Pred, state->BindExpr(CE, loc::MemRegionVal(R))); + return true; + } + } + + return false; +} + +void GRExprEngine::EvalCall(ExplodedNodeSet& Dst, CallExpr* CE, SVal L, + ExplodedNode* Pred) { assert (Builder && "GRStmtNodeBuilder must be defined."); - + // FIXME: Allow us to chain together transfer functions. if (EvalOSAtomic(Dst, *this, *Builder, CE, L, Pred)) return; - + getTF().EvalCall(Dst, *this, *Builder, CE, L, Pred); } -void GRExprEngine::VisitCall(CallExpr* CE, NodeTy* Pred, +void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, - NodeSet& Dst) -{ + ExplodedNodeSet& Dst) { // Determine the type of function we're calling (if available). const FunctionProtoType *Proto = NULL; QualType FnType = CE->getCallee()->IgnoreParens()->getType(); - if (const PointerType *FnTypePtr = FnType->getAsPointerType()) - Proto = FnTypePtr->getPointeeType()->getAsFunctionProtoType(); + if (const PointerType *FnTypePtr = FnType->getAs()) + Proto = FnTypePtr->getPointeeType()->getAs(); VisitCallRec(CE, Pred, AI, AE, Dst, Proto, /*ParamIdx=*/0); } -void GRExprEngine::VisitCallRec(CallExpr* CE, NodeTy* Pred, +void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, - NodeSet& Dst, const FunctionProtoType *Proto, + ExplodedNodeSet& Dst, + const FunctionProtoType *Proto, unsigned ParamIdx) { - + // Process the arguments. if (AI != AE) { // If the call argument is being bound to a reference parameter, @@ -1389,201 +1597,63 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, NodeTy* Pred, if (Proto && ParamIdx < Proto->getNumArgs()) VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType(); - NodeSet DstTmp; + ExplodedNodeSet DstTmp; if (VisitAsLvalue) - VisitLValue(*AI, Pred, DstTmp); + VisitLValue(*AI, Pred, DstTmp); else - Visit(*AI, Pred, DstTmp); + Visit(*AI, Pred, DstTmp); ++AI; - - for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI != DE; ++DI) + + for (ExplodedNodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI != DE; + ++DI) VisitCallRec(CE, *DI, AI, AE, Dst, Proto, ParamIdx + 1); - + return; } // If we reach here we have processed all of the arguments. Evaluate // the callee expression. - - NodeSet DstTmp; + ExplodedNodeSet DstTmp; Expr* Callee = CE->getCallee()->IgnoreParens(); - Visit(Callee, Pred, DstTmp); - + { // Enter new scope to make the lifetime of 'DstTmp2' bounded. + ExplodedNodeSet DstTmp2; + Visit(Callee, Pred, DstTmp2); + + // Perform the previsit of the CallExpr, storing the results in DstTmp. + CheckerVisit(CE, DstTmp, DstTmp2, true); + } + // Finally, evaluate the function call. - for (NodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI!=DE; ++DI) { + 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). - - // Check for undefined control-flow or calls to NULL. - - if (L.isUndef() || isa(L)) { - NodeTy* N = Builder->generateNode(CE, state, *DI); - - if (N) { - N->markAsSink(); - BadCalls.insert(N); - } - - continue; - } - + // Check for the "noreturn" attribute. - + SaveAndRestore OldSink(Builder->BuildSinks); const FunctionDecl* FD = L.getAsFunctionDecl(); - if (FD) { - if (FD->getAttr() || - FD->getAttr()) - Builder->BuildSinks = true; - else { - // HACK: Some functions are not marked noreturn, and don't return. - // Here are a few hardwired ones. If this takes too long, we can - // potentially cache these results. - const char* s = FD->getIdentifier()->getName(); - unsigned n = strlen(s); - - switch (n) { - default: - break; - - case 4: - if (!memcmp(s, "exit", 4)) Builder->BuildSinks = true; - break; - case 5: - if (!memcmp(s, "panic", 5)) Builder->BuildSinks = true; - else if (!memcmp(s, "error", 5)) { - if (CE->getNumArgs() > 0) { - SVal X = state->getSVal(*CE->arg_begin()); - // FIXME: use Assume to inspect the possible symbolic value of - // X. Also check the specific signature of error(). - nonloc::ConcreteInt* CI = dyn_cast(&X); - if (CI && CI->getValue() != 0) - Builder->BuildSinks = true; - } - } - break; + MarkNoReturnFunction(FD, CE, state, Builder); - case 6: - if (!memcmp(s, "Assert", 6)) { - Builder->BuildSinks = true; - break; - } - - // FIXME: This is just a wrapper around throwing an exception. - // Eventually inter-procedural analysis should handle this easily. - if (!memcmp(s, "ziperr", 6)) Builder->BuildSinks = true; - - break; - - case 7: - if (!memcmp(s, "assfail", 7)) Builder->BuildSinks = true; - break; - - case 8: - if (!memcmp(s ,"db_error", 8) || - !memcmp(s, "__assert", 8)) - Builder->BuildSinks = true; - break; - - case 12: - if (!memcmp(s, "__assert_rtn", 12)) Builder->BuildSinks = true; - break; - - case 13: - if (!memcmp(s, "__assert_fail", 13)) Builder->BuildSinks = true; - break; - - case 14: - if (!memcmp(s, "dtrace_assfail", 14) || - !memcmp(s, "yy_fatal_error", 14)) - Builder->BuildSinks = true; - break; - - case 26: - if (!memcmp(s, "_XCAssertionFailureHandler", 26) || - !memcmp(s, "_DTAssertionFailureHandler", 26) || - !memcmp(s, "_TSAssertionFailureHandler", 26)) - Builder->BuildSinks = true; - - break; - } - - } - } - // Evaluate the call. + if (EvalBuiltinFunction(FD, CE, *DI, Dst)) + continue; - if (FD) { - - if (unsigned id = FD->getBuiltinID(getContext())) - switch (id) { - case Builtin::BI__builtin_expect: { - // For __builtin_expect, just return the value of the subexpression. - assert (CE->arg_begin() != CE->arg_end()); - SVal X = state->getSVal(*(CE->arg_begin())); - MakeNode(Dst, CE, *DI, state->bindExpr(CE, X)); - continue; - } - - case Builtin::BI__builtin_alloca: { - // FIXME: Refactor into StoreManager itself? - MemRegionManager& RM = getStateManager().getRegionManager(); - const MemRegion* R = - RM.getAllocaRegion(CE, Builder->getCurrentBlockCount()); - - // Set the extent of the region in bytes. This enables us to use the - // SVal of the argument directly. If we save the extent in bits, we - // cannot represent values like symbol*8. - SVal Extent = state->getSVal(*(CE->arg_begin())); - state = getStoreManager().setExtent(state, R, Extent); - - MakeNode(Dst, CE, *DI, state->bindExpr(CE, loc::MemRegionVal(R))); - continue; - } - - default: - break; - } - } - - // Check any arguments passed-by-value against being undefined. - - bool badArg = false; - - for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); - I != E; ++I) { + // Dispatch to the plug-in transfer function. - if (GetState(*DI)->getSVal(*I).isUndef()) { - NodeTy* N = Builder->generateNode(CE, GetState(*DI), *DI); - - if (N) { - N->markAsSink(); - UndefArgs[N] = *I; - } - - badArg = true; - break; - } - } - - if (badArg) - continue; - - // Dispatch to the plug-in transfer function. - unsigned size = Dst.size(); SaveOr OldHasGen(Builder->HasGeneratedNode); EvalCall(Dst, CE, L, *DI); - + // Handle the case where no nodes where generated. Auto-generate that // contains the updated state if we aren't generating sinks. - + if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode) MakeNode(Dst, CE, *DI, state); @@ -1597,35 +1667,38 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, NodeTy* Pred, static std::pair EagerlyAssumeTag = std::pair(&EagerlyAssumeTag,0); -void GRExprEngine::EvalEagerlyAssume(NodeSet &Dst, NodeSet &Src, Expr *Ex) { - for (NodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) { - NodeTy *Pred = *I; - +void GRExprEngine::EvalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, + Expr *Ex) { + for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) { + ExplodedNode *Pred = *I; + // Test if the previous node was as the same expression. This can happen // when the expression fails to evaluate to anything meaningful and // (as an optimization) we don't generate a node. - ProgramPoint P = Pred->getLocation(); + ProgramPoint P = Pred->getLocation(); if (!isa(P) || cast(P).getStmt() != Ex) { - Dst.Add(Pred); + Dst.Add(Pred); continue; - } + } - const GRState* state = Pred->getState(); - SVal V = state->getSVal(Ex); - if (isa(V)) { + const GRState* state = Pred->getState(); + SVal V = state->getSVal(Ex); + if (nonloc::SymExprVal *SEV = dyn_cast(&V)) { // First assume that the condition is true. - if (const GRState *stateTrue = state->assume(V, true)) { - stateTrue = stateTrue->bindExpr(Ex, + if (const GRState *stateTrue = state->Assume(*SEV, true)) { + stateTrue = stateTrue->BindExpr(Ex, ValMgr.makeIntVal(1U, Ex->getType())); - Dst.Add(Builder->generateNode(PostStmtCustom(Ex, &EagerlyAssumeTag), + Dst.Add(Builder->generateNode(PostStmtCustom(Ex, + &EagerlyAssumeTag, Pred->getLocationContext()), stateTrue, Pred)); } - + // Next, assume that the condition is false. - if (const GRState *stateFalse = state->assume(V, false)) { - stateFalse = stateFalse->bindExpr(Ex, + if (const GRState *stateFalse = state->Assume(*SEV, false)) { + stateFalse = stateFalse->BindExpr(Ex, ValMgr.makeIntVal(0U, Ex->getType())); - Dst.Add(Builder->generateNode(PostStmtCustom(Ex, &EagerlyAssumeTag), + Dst.Add(Builder->generateNode(PostStmtCustom(Ex, &EagerlyAssumeTag, + Pred->getLocationContext()), stateFalse, Pred)); } } @@ -1638,21 +1711,20 @@ void GRExprEngine::EvalEagerlyAssume(NodeSet &Dst, NodeSet &Src, Expr *Ex) { // Transfer function: Objective-C ivar references. //===----------------------------------------------------------------------===// -void GRExprEngine::VisitObjCIvarRefExpr(ObjCIvarRefExpr* Ex, - NodeTy* Pred, NodeSet& Dst, - bool asLValue) { - +void GRExprEngine::VisitObjCIvarRefExpr(ObjCIvarRefExpr* Ex, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue) { + Expr* Base = cast(Ex->getBase()); - NodeSet Tmp; + ExplodedNodeSet Tmp; Visit(Base, Pred, Tmp); - - for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { const GRState* state = GetState(*I); SVal BaseVal = state->getSVal(Base); SVal location = state->getLValue(Ex->getDecl(), BaseVal); - + if (asLValue) - MakeNode(Dst, Ex, *I, state->bindExpr(Ex, location)); + MakeNode(Dst, Ex, *I, state->BindExpr(Ex, location)); else EvalLoad(Dst, Ex, *I, state, location); } @@ -1663,8 +1735,8 @@ void GRExprEngine::VisitObjCIvarRefExpr(ObjCIvarRefExpr* Ex, //===----------------------------------------------------------------------===// void GRExprEngine::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, - NodeTy* Pred, NodeSet& Dst) { - + ExplodedNode* Pred, ExplodedNodeSet& Dst) { + // ObjCForCollectionStmts are processed in two places. This method // handles the case where an ObjCForCollectionStmt* occurs as one of the // statements within a basic block. This transfer function does two things: @@ -1676,7 +1748,7 @@ void GRExprEngine::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, // whether or not the container has any more elements. This value // will be tested in ProcessBranch. We need to explicitly bind // this value because a container can contain nil elements. - // + // // FIXME: Eventually this logic should actually do dispatches to // 'countByEnumeratingWithState:objects:count:' (NSFastEnumeration). // This will require simulating a temporary NSFastEnumerationState, either @@ -1689,51 +1761,51 @@ void GRExprEngine::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, // For now: simulate (1) by assigning either a symbol or nil if the // container is empty. Thus this transfer function will by default // result in state splitting. - + Stmt* elem = S->getElement(); SVal ElementV; - + if (DeclStmt* DS = dyn_cast(elem)) { VarDecl* ElemD = cast(DS->getSingleDecl()); assert (ElemD->getInit() == 0); - ElementV = GetState(Pred)->getLValue(ElemD); + ElementV = GetState(Pred)->getLValue(ElemD, Pred->getLocationContext()); VisitObjCForCollectionStmtAux(S, Pred, Dst, ElementV); return; } - NodeSet Tmp; + ExplodedNodeSet Tmp; VisitLValue(cast(elem), Pred, Tmp); - - for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) { + + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) { const GRState* state = GetState(*I); VisitObjCForCollectionStmtAux(S, *I, Dst, state->getSVal(elem)); } } void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, - NodeTy* Pred, NodeSet& Dst, + ExplodedNode* Pred, ExplodedNodeSet& Dst, SVal ElementV) { - - + + // Get the current state. Use 'EvalLocation' to determine if it is a null // pointer, etc. Stmt* elem = S->getElement(); - + Pred = EvalLocation(elem, Pred, GetState(Pred), ElementV); if (!Pred) return; - + const GRState *state = GetState(Pred); // Handle the case where the container still has elements. SVal TrueV = ValMgr.makeTruthVal(1); - const GRState *hasElems = state->bindExpr(S, TrueV); - + const GRState *hasElems = state->BindExpr(S, TrueV); + // Handle the case where the container has no elements. SVal FalseV = ValMgr.makeTruthVal(0); - const GRState *noElems = state->bindExpr(S, FalseV); - + const GRState *noElems = state->BindExpr(S, FalseV); + if (loc::MemRegionVal* MV = dyn_cast(&ElementV)) if (const TypedRegion* R = dyn_cast(MV->getRegion())) { // FIXME: The proper thing to do is to really iterate over the @@ -1747,10 +1819,10 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, hasElems = hasElems->bindLoc(ElementV, V); // Bind the location to 'nil' on the false branch. - SVal nilV = ValMgr.makeIntVal(0, T); - noElems = noElems->bindLoc(ElementV, nilV); + SVal nilV = ValMgr.makeIntVal(0, T); + noElems = noElems->bindLoc(ElementV, nilV); } - + // Create the new nodes. MakeNode(Dst, S, Pred, hasElems); MakeNode(Dst, S, Pred, noElems); @@ -1760,113 +1832,115 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, // Transfer function: Objective-C message expressions. //===----------------------------------------------------------------------===// -void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred, - NodeSet& Dst){ - +void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, + ExplodedNodeSet& Dst){ + VisitObjCMessageExprArgHelper(ME, ME->arg_begin(), ME->arg_end(), Pred, Dst); -} +} void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME, ObjCMessageExpr::arg_iterator AI, ObjCMessageExpr::arg_iterator AE, - NodeTy* Pred, NodeSet& Dst) { + ExplodedNode* Pred, ExplodedNodeSet& Dst) { if (AI == AE) { - + // Process the receiver. - + if (Expr* Receiver = ME->getReceiver()) { - NodeSet Tmp; + ExplodedNodeSet Tmp; Visit(Receiver, Pred, Tmp); - - for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI) + + for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; + ++NI) VisitObjCMessageExprDispatchHelper(ME, *NI, Dst); - + return; } - + VisitObjCMessageExprDispatchHelper(ME, Pred, Dst); return; } - - NodeSet Tmp; + + ExplodedNodeSet Tmp; Visit(*AI, Pred, Tmp); - + ++AI; - - for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI) + + for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI) VisitObjCMessageExprArgHelper(ME, AI, AE, *NI, Dst); } void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, - NodeTy* Pred, - NodeSet& Dst) { - - // FIXME: More logic for the processing the method call. - + ExplodedNode* Pred, + ExplodedNodeSet& Dst) { + + // FIXME: More logic for the processing the method call. + const GRState* state = GetState(Pred); bool RaisesException = false; - - + + if (Expr* Receiver = ME->getReceiver()) { - - SVal L = state->getSVal(Receiver); - - // Check for undefined control-flow. - if (L.isUndef()) { - NodeTy* N = Builder->generateNode(ME, state, Pred); - + + SVal L_untested = state->getSVal(Receiver); + + // Check for undefined control-flow. + if (L_untested.isUndef()) { + ExplodedNode* N = Builder->generateNode(ME, state, Pred); + if (N) { N->markAsSink(); UndefReceivers.insert(N); } - + return; } - - // "Assume" that the receiver is not NULL. - const GRState *StNotNull = state->assume(L, true); - - // "Assume" that the receiver is NULL. - const GRState *StNull = state->assume(L, false); - + + // "Assume" that the receiver is not NULL. + DefinedOrUnknownSVal L = cast(L_untested); + const GRState *StNotNull = state->Assume(L, true); + + // "Assume" that the receiver is NULL. + const GRState *StNull = state->Assume(L, false); + if (StNull) { QualType RetTy = ME->getType(); - + // Check if the receiver was nil and the return value a struct. - if(RetTy->isRecordType()) { - if (BR.getParentMap().isConsumedExpr(ME)) { + if (RetTy->isRecordType()) { + if (Pred->getParentMap().isConsumedExpr(ME)) { // The [0 ...] expressions will return garbage. Flag either an // explicit or implicit error. Because of the structure of this // function we currently do not bifurfacte the state graph at // this point. // FIXME: We should bifurcate and fill the returned struct with - // garbage. - if (NodeTy* N = Builder->generateNode(ME, StNull, Pred)) { + // garbage. + if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) { N->markAsSink(); if (StNotNull) NilReceiverStructRetImplicit.insert(N); else - NilReceiverStructRetExplicit.insert(N); + NilReceiverStructRetExplicit.insert(N); } } } else { ASTContext& Ctx = getContext(); if (RetTy != Ctx.VoidTy) { - if (BR.getParentMap().isConsumedExpr(ME)) { + if (Pred->getParentMap().isConsumedExpr(ME)) { // sizeof(void *) const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); // sizeof(return type) const uint64_t returnTypeSize = Ctx.getTypeSize(ME->getType()); - if(voidPtrSize < returnTypeSize) { - if (NodeTy* N = Builder->generateNode(ME, StNull, Pred)) { + if (voidPtrSize < returnTypeSize) { + if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) { N->markAsSink(); - if(StNotNull) + if (StNotNull) NilReceiverLargerThanVoidPtrRetImplicit.insert(N); else - NilReceiverLargerThanVoidPtrRetExplicit.insert(N); + NilReceiverLargerThanVoidPtrRetExplicit.insert(N); } } else if (!StNotNull) { @@ -1884,7 +1958,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, // of this case unless we have *a lot* more knowledge. // SVal V = ValMgr.makeZeroVal(ME->getType()); - MakeNode(Dst, ME, Pred, StNull->bindExpr(ME, V)); + MakeNode(Dst, ME, Pred, StNull->BindExpr(ME, V)); return; } } @@ -1894,99 +1968,99 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, // of this method should assume that the receiver is not nil. if (!StNotNull) return; - + state = StNotNull; } - + // Check if the "raise" message was sent. if (ME->getSelector() == RaiseSel) RaisesException = true; } else { - + IdentifierInfo* ClsName = ME->getClassName(); Selector S = ME->getSelector(); - + // Check for special instance methods. - - if (!NSExceptionII) { + + if (!NSExceptionII) { ASTContext& Ctx = getContext(); - + NSExceptionII = &Ctx.Idents.get("NSException"); } - + if (ClsName == NSExceptionII) { - + enum { NUM_RAISE_SELECTORS = 2 }; - + // Lazily create a cache of the selectors. if (!NSExceptionInstanceRaiseSelectors) { - + ASTContext& Ctx = getContext(); - + NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS]; - + llvm::SmallVector II; unsigned idx = 0; - - // raise:format: + + // raise:format: II.push_back(&Ctx.Idents.get("raise")); - II.push_back(&Ctx.Idents.get("format")); + II.push_back(&Ctx.Idents.get("format")); NSExceptionInstanceRaiseSelectors[idx++] = - Ctx.Selectors.getSelector(II.size(), &II[0]); - - // raise:format::arguments: + Ctx.Selectors.getSelector(II.size(), &II[0]); + + // raise:format::arguments: II.push_back(&Ctx.Idents.get("arguments")); NSExceptionInstanceRaiseSelectors[idx++] = Ctx.Selectors.getSelector(II.size(), &II[0]); } - + for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) if (S == NSExceptionInstanceRaiseSelectors[i]) { RaisesException = true; break; } } } - + // Check for any arguments that are uninitialized/undefined. - + for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end(); I != E; ++I) { - + if (state->getSVal(*I).isUndef()) { - + // Generate an error node for passing an uninitialized/undefined value // as an argument to a message expression. This node is a sink. - NodeTy* N = Builder->generateNode(ME, state, Pred); - + ExplodedNode* N = Builder->generateNode(ME, state, Pred); + if (N) { N->markAsSink(); MsgExprUndefArgs[N] = *I; } - + return; - } + } } - + // Check if we raise an exception. For now treat these as sinks. Eventually // we will want to handle exceptions properly. - + SaveAndRestore OldSink(Builder->BuildSinks); if (RaisesException) Builder->BuildSinks = true; - + // Dispatch to plug-in transfer function. - + unsigned size = Dst.size(); SaveOr OldHasGen(Builder->HasGeneratedNode); - + EvalObjCMessageExpr(Dst, ME, Pred); - + // Handle the case where no nodes where generated. Auto-generate that // contains the updated state if we aren't generating sinks. - + if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode) MakeNode(Dst, ME, Pred, state); } @@ -1995,24 +2069,8 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, // Transfer functions: Miscellaneous statements. //===----------------------------------------------------------------------===// -void GRExprEngine::VisitCastPointerToInteger(SVal V, const GRState* state, - QualType PtrTy, - Expr* CastE, NodeTy* Pred, - NodeSet& Dst) { - if (!V.isUnknownOrUndef()) { - // FIXME: Determine if the number of bits of the target type is - // equal or exceeds the number of bits to store the pointer value. - // If not, flag an error. - MakeNode(Dst, CastE, Pred, state->bindExpr(CastE, EvalCast(cast(V), - CastE->getType()))); - } - else - MakeNode(Dst, CastE, Pred, state->bindExpr(CastE, V)); -} - - -void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst){ - NodeSet S1; +void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst){ + ExplodedNodeSet S1; QualType T = CastE->getType(); QualType ExTy = Ex->getType(); @@ -2023,180 +2081,67 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst){ VisitLValue(Ex, Pred, S1); else Visit(Ex, Pred, S1); - + // Check for casting to "void". - if (T->isVoidType()) { - for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) + if (T->isVoidType()) { + for (ExplodedNodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) Dst.Add(*I1); return; } - - // FIXME: The rest of this should probably just go into EvalCall, and - // let the transfer function object be responsible for constructing - // nodes. - - for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) { - NodeTy* N = *I1; + + for (ExplodedNodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) { + ExplodedNode* N = *I1; const GRState* state = GetState(N); SVal V = state->getSVal(Ex); - ASTContext& C = getContext(); - - // Unknown? - if (V.isUnknown()) { - Dst.Add(N); - continue; - } - - // Undefined? - if (V.isUndef()) - goto PassThrough; - - // For const casts, just propagate the value. - if (C.getCanonicalType(T).getUnqualifiedType() == - C.getCanonicalType(ExTy).getUnqualifiedType()) - goto PassThrough; - - // Check for casts from pointers to integers. - if (T->isIntegerType() && Loc::IsLocType(ExTy)) { - VisitCastPointerToInteger(V, state, ExTy, CastE, N, Dst); - continue; - } - - // Check for casts from integers to pointers. - if (Loc::IsLocType(T) && ExTy->isIntegerType()) { - if (nonloc::LocAsInteger *LV = dyn_cast(&V)) { - // Just unpackage the lval and return it. - V = LV->getLoc(); - MakeNode(Dst, CastE, N, state->bindExpr(CastE, V)); - continue; - } - - goto DispatchCast; - } - - // Just pass through function and block pointers. - if (ExTy->isBlockPointerType() || ExTy->isFunctionPointerType()) { - assert(Loc::IsLocType(T)); - goto PassThrough; - } - - // Check for casts from array type to another type. - if (ExTy->isArrayType()) { - // We will always decay to a pointer. - V = StateMgr.ArrayToPointer(cast(V)); - - // Are we casting from an array to a pointer? If so just pass on - // the decayed value. - if (T->isPointerType()) - goto PassThrough; - - // Are we casting from an array to an integer? If so, cast the decayed - // pointer value to an integer. - assert(T->isIntegerType()); - QualType ElemTy = cast(ExTy)->getElementType(); - QualType PointerTy = getContext().getPointerType(ElemTy); - VisitCastPointerToInteger(V, state, PointerTy, CastE, N, Dst); - continue; - } - - // Check for casts from a region to a specific type. - if (loc::MemRegionVal *RV = dyn_cast(&V)) { - // FIXME: For TypedViewRegions, we should handle the case where the - // underlying symbolic pointer is a function pointer or - // block pointer. - - // FIXME: We should handle the case where we strip off view layers to get - // to a desugared type. - - assert(Loc::IsLocType(T)); - // We get a symbolic function pointer for a dereference of a function - // pointer, but it is of function type. Example: - - // struct FPRec { - // void (*my_func)(int * x); - // }; - // - // int bar(int x); - // - // int f1_a(struct FPRec* foo) { - // int x; - // (*foo->my_func)(&x); - // return bar(x)+1; // no-warning - // } - - assert(Loc::IsLocType(ExTy) || ExTy->isFunctionType()); - - const MemRegion* R = RV->getRegion(); - StoreManager& StoreMgr = getStoreManager(); - - // Delegate to store manager to get the result of casting a region - // to a different type. - const StoreManager::CastResult& Res = StoreMgr.CastRegion(state, R, T); - - // Inspect the result. If the MemRegion* returned is NULL, this - // expression evaluates to UnknownVal. - R = Res.getRegion(); - if (R) { V = loc::MemRegionVal(R); } else { V = UnknownVal(); } - - // Generate the new node in the ExplodedGraph. - MakeNode(Dst, CastE, N, Res.getState()->bindExpr(CastE, V)); - continue; - } - // All other cases. - DispatchCast: { - MakeNode(Dst, CastE, N, state->bindExpr(CastE, - EvalCast(V, CastE->getType()))); - continue; - } - - PassThrough: { - MakeNode(Dst, CastE, N, state->bindExpr(CastE, V)); - } + const SValuator::CastResult &Res = SVator.EvalCast(V, state, T, ExTy); + state = Res.getState()->BindExpr(CastE, Res.getSVal()); + MakeNode(Dst, CastE, N, state); } } void GRExprEngine::VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, - NodeTy* Pred, NodeSet& Dst, + ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue) { InitListExpr* ILE = cast(CL->getInitializer()->IgnoreParens()); - NodeSet Tmp; + ExplodedNodeSet Tmp; Visit(ILE, Pred, Tmp); - - for (NodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) { + + for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) { const GRState* state = GetState(*I); SVal ILV = state->getSVal(ILE); state = state->bindCompoundLiteral(CL, ILV); if (asLValue) - MakeNode(Dst, CL, *I, state->bindExpr(CL, state->getLValue(CL))); + MakeNode(Dst, CL, *I, state->BindExpr(CL, state->getLValue(CL))); else - MakeNode(Dst, CL, *I, state->bindExpr(CL, ILV)); + MakeNode(Dst, CL, *I, state->BindExpr(CL, ILV)); } } -void GRExprEngine::VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst) { +void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, + ExplodedNodeSet& Dst) { - // The CFG has one DeclStmt per Decl. + // The CFG has one DeclStmt per Decl. Decl* D = *DS->decl_begin(); - + if (!D || !isa(D)) return; - - const VarDecl* VD = dyn_cast(D); + + const VarDecl* VD = dyn_cast(D); Expr* InitEx = const_cast(VD->getInit()); // FIXME: static variables may have an initializer, but the second // time a function is called those values may not be current. - NodeSet Tmp; + ExplodedNodeSet Tmp; if (InitEx) Visit(InitEx, Pred, Tmp); - - if (Tmp.empty()) + else Tmp.Add(Pred); - - for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { const GRState* state = GetState(*I); unsigned Count = Builder->getCurrentBlockCount(); @@ -2204,58 +2149,61 @@ void GRExprEngine::VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst) { QualType T = getContext().getCanonicalType(VD->getType()); if (VariableArrayType* VLA = dyn_cast(T)) { // FIXME: Handle multi-dimensional VLAs. - + Expr* SE = VLA->getSizeExpr(); - SVal Size = state->getSVal(SE); - - if (Size.isUndef()) { - if (NodeTy* N = Builder->generateNode(DS, state, Pred)) { - N->markAsSink(); + SVal Size_untested = state->getSVal(SE); + + if (Size_untested.isUndef()) { + if (ExplodedNode* N = Builder->generateNode(DS, state, Pred)) { + N->markAsSink(); ExplicitBadSizedVLA.insert(N); } continue; } - - const GRState* zeroState = state->assume(Size, false); - state = state->assume(Size, true); - + + DefinedOrUnknownSVal Size = cast(Size_untested); + const GRState *zeroState = state->Assume(Size, false); + state = state->Assume(Size, true); + if (zeroState) { - if (NodeTy* N = Builder->generateNode(DS, zeroState, Pred)) { - N->markAsSink(); + if (ExplodedNode* N = Builder->generateNode(DS, zeroState, Pred)) { + N->markAsSink(); if (state) ImplicitBadSizedVLA.insert(N); else ExplicitBadSizedVLA.insert(N); } } - + if (!state) - continue; + continue; } - + // Decls without InitExpr are not initialized explicitly. + const LocationContext *LC = (*I)->getLocationContext(); + if (InitEx) { SVal InitVal = state->getSVal(InitEx); QualType T = VD->getType(); - + // Recover some path-sensitivity if a scalar value evaluated to // UnknownVal. - if (InitVal.isUnknown() || + if (InitVal.isUnknown() || !getConstraintManager().canReasonAbout(InitVal)) { - InitVal = ValMgr.getConjuredSymbolVal(InitEx, Count); - } - - state = state->bindDecl(VD, InitVal); - + InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, Count); + } + + state = state->bindDecl(VD, LC, InitVal); + // The next thing to do is check if the GRTransferFuncs object wants to // update the state based on the new binding. If the GRTransferFunc // object doesn't do anything, just auto-propagate the current state. GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, state, DS,true); - getTF().EvalBind(BuilderRef, loc::MemRegionVal(state->getRegion(VD)), - InitVal); - } + getTF().EvalBind(BuilderRef, loc::MemRegionVal(state->getRegion(VD, LC)), + InitVal); + } else { - state = state->bindDeclWithNoInit(VD); + state = state->bindDeclWithNoInit(VD, LC); MakeNode(Dst, DS, *I, state); } } @@ -2267,67 +2215,69 @@ namespace { class VISIBILITY_HIDDEN InitListWLItem { public: llvm::ImmutableList Vals; - GRExprEngine::NodeTy* N; + ExplodedNode* N; InitListExpr::reverse_iterator Itr; - - InitListWLItem(GRExprEngine::NodeTy* n, llvm::ImmutableList vals, - InitListExpr::reverse_iterator itr) + + InitListWLItem(ExplodedNode* n, llvm::ImmutableList vals, + InitListExpr::reverse_iterator itr) : Vals(vals), N(n), Itr(itr) {} }; } -void GRExprEngine::VisitInitListExpr(InitListExpr* E, NodeTy* Pred, - NodeSet& Dst) { +void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, + ExplodedNodeSet& Dst) { const GRState* state = GetState(Pred); QualType T = getContext().getCanonicalType(E->getType()); - unsigned NumInitElements = E->getNumInits(); + unsigned NumInitElements = E->getNumInits(); - if (T->isArrayType() || T->isStructureType()) { + if (T->isArrayType() || T->isStructureType() || + T->isUnionType() || T->isVectorType()) { llvm::ImmutableList StartVals = getBasicVals().getEmptySValList(); - + // Handle base case where the initializer has no elements. // e.g: static int* myArray[] = {}; if (NumInitElements == 0) { SVal V = ValMgr.makeCompoundVal(T, StartVals); - MakeNode(Dst, E, Pred, state->bindExpr(E, V)); + MakeNode(Dst, E, Pred, state->BindExpr(E, V)); return; - } - + } + // Create a worklist to process the initializers. llvm::SmallVector WorkList; - WorkList.reserve(NumInitElements); - WorkList.push_back(InitListWLItem(Pred, StartVals, E->rbegin())); + WorkList.reserve(NumInitElements); + WorkList.push_back(InitListWLItem(Pred, StartVals, E->rbegin())); InitListExpr::reverse_iterator ItrEnd = E->rend(); - + assert(!(E->rbegin() == E->rend())); + // Process the worklist until it is empty. while (!WorkList.empty()) { InitListWLItem X = WorkList.back(); WorkList.pop_back(); - - NodeSet Tmp; + + ExplodedNodeSet Tmp; Visit(*X.Itr, X.N, Tmp); - + InitListExpr::reverse_iterator NewItr = X.Itr + 1; - for (NodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) { + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) { // Get the last initializer value. state = GetState(*NI); SVal InitV = state->getSVal(cast(*X.Itr)); - + // Construct the new list of values by prepending the new value to // the already constructed list. llvm::ImmutableList NewVals = getBasicVals().consVals(InitV, X.Vals); - + if (NewItr == ItrEnd) { // Now we have a list holding all init values. Make CompoundValData. SVal V = ValMgr.makeCompoundVal(T, NewVals); // Make final state and node. - MakeNode(Dst, E, *NI, state->bindExpr(E, V)); + MakeNode(Dst, E, *NI, state->BindExpr(E, V)); } else { // Still some initializer values to go. Push them onto the worklist. @@ -2335,25 +2285,18 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, NodeTy* Pred, } } } - - return; - } - if (T->isUnionType() || T->isVectorType()) { - // FIXME: to be implemented. - // Note: That vectors can return true for T->isIntegerType() - MakeNode(Dst, E, Pred, state); return; } - + if (Loc::IsLocType(T) || T->isIntegerType()) { assert (E->getNumInits() == 1); - NodeSet Tmp; + ExplodedNodeSet Tmp; Expr* Init = E->getInit(0); Visit(Init, Pred, Tmp); - for (NodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I != EI; ++I) { + for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I != EI; ++I) { state = GetState(*I); - MakeNode(Dst, E, *I, state->bindExpr(E, state->getSVal(Init))); + MakeNode(Dst, E, *I, state->BindExpr(E, state->getSVal(Init))); } return; } @@ -2365,13 +2308,13 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, NodeTy* Pred, /// VisitSizeOfAlignOfExpr - Transfer function for sizeof(type). void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, - NodeTy* Pred, - NodeSet& Dst) { + ExplodedNode* Pred, + ExplodedNodeSet& Dst) { QualType T = Ex->getTypeOfArgument(); - uint64_t amt; - + uint64_t amt; + if (Ex->isSizeOf()) { - if (T == getContext().VoidTy) { + if (T == getContext().VoidTy) { // sizeof(void) == 1 byte. amt = 1; } @@ -2382,195 +2325,206 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, 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. + // for these. return; } else { // All other cases. amt = getContext().getTypeSize(T) / 8; - } + } } else // Get alignment of the type. amt = getContext().getTypeAlign(T) / 8; - + MakeNode(Dst, Ex, Pred, - GetState(Pred)->bindExpr(Ex, ValMgr.makeIntVal(amt, Ex->getType()))); + GetState(Pred)->BindExpr(Ex, ValMgr.makeIntVal(amt, Ex->getType()))); } -void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred, - NodeSet& Dst, bool asLValue) { +void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue) { switch (U->getOpcode()) { - + default: break; - + case UnaryOperator::Deref: { - + Expr* Ex = U->getSubExpr()->IgnoreParens(); - NodeSet Tmp; + ExplodedNodeSet Tmp; Visit(Ex, Pred, Tmp); - - for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + const GRState* state = GetState(*I); SVal location = state->getSVal(Ex); - + if (asLValue) - MakeNode(Dst, U, *I, state->bindExpr(U, location), + MakeNode(Dst, U, *I, state->BindExpr(U, location), ProgramPoint::PostLValueKind); else EvalLoad(Dst, U, *I, state, location); - } + } return; } - + case UnaryOperator::Real: { - + Expr* Ex = U->getSubExpr()->IgnoreParens(); - NodeSet Tmp; + ExplodedNodeSet Tmp; Visit(Ex, Pred, Tmp); - - for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + // FIXME: We don't have complex SValues yet. if (Ex->getType()->isAnyComplexType()) { // Just report "Unknown." Dst.Add(*I); continue; } - + // For all other types, UnaryOperator::Real is an identity operation. assert (U->getType() == Ex->getType()); const GRState* state = GetState(*I); - MakeNode(Dst, U, *I, state->bindExpr(U, state->getSVal(Ex))); - } - + MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex))); + } + return; } - + case UnaryOperator::Imag: { - + Expr* Ex = U->getSubExpr()->IgnoreParens(); - NodeSet Tmp; + ExplodedNodeSet Tmp; Visit(Ex, Pred, Tmp); - - for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { // FIXME: We don't have complex SValues yet. if (Ex->getType()->isAnyComplexType()) { // Just report "Unknown." Dst.Add(*I); continue; } - + // For all other types, UnaryOperator::Float returns 0. assert (Ex->getType()->isIntegerType()); const GRState* state = GetState(*I); SVal X = ValMgr.makeZeroVal(Ex->getType()); - MakeNode(Dst, U, *I, state->bindExpr(U, X)); + MakeNode(Dst, U, *I, state->BindExpr(U, X)); } - + return; } - - // FIXME: Just report "Unknown" for OffsetOf. - case UnaryOperator::OffsetOf: + + case UnaryOperator::OffsetOf: { + Expr::EvalResult Res; + if (U->Evaluate(Res, getContext()) && Res.Val.isInt()) { + const APSInt &IV = Res.Val.getInt(); + assert(IV.getBitWidth() == getContext().getTypeSize(U->getType())); + assert(U->getType()->isIntegerType()); + assert(IV.isSigned() == U->getType()->isSignedIntegerType()); + SVal X = ValMgr.makeIntVal(IV); + MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X)); + return; + } + // FIXME: Handle the case where __builtin_offsetof is not a constant. Dst.Add(Pred); return; - + } + case UnaryOperator::Plus: assert (!asLValue); // FALL-THROUGH. case UnaryOperator::Extension: { - + // Unary "+" is a no-op, similar to a parentheses. We still have places // where it may be a block-level expression, so we need to // generate an extra node that just propagates the value of the // subexpression. Expr* Ex = U->getSubExpr()->IgnoreParens(); - NodeSet Tmp; + ExplodedNodeSet Tmp; Visit(Ex, Pred, Tmp); - - for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { const GRState* state = GetState(*I); - MakeNode(Dst, U, *I, state->bindExpr(U, state->getSVal(Ex))); + MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex))); } - + return; } - + case UnaryOperator::AddrOf: { - + assert(!asLValue); Expr* Ex = U->getSubExpr()->IgnoreParens(); - NodeSet Tmp; + ExplodedNodeSet Tmp; VisitLValue(Ex, Pred, Tmp); - - for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { const GRState* state = GetState(*I); SVal V = state->getSVal(Ex); - state = state->bindExpr(U, V); + state = state->BindExpr(U, V); MakeNode(Dst, U, *I, state); } - return; + return; } - + case UnaryOperator::LNot: case UnaryOperator::Minus: case UnaryOperator::Not: { - + assert (!asLValue); Expr* Ex = U->getSubExpr()->IgnoreParens(); - NodeSet Tmp; + ExplodedNodeSet Tmp; Visit(Ex, Pred, Tmp); - - for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { const GRState* state = GetState(*I); - + // Get the value of the subexpression. SVal V = state->getSVal(Ex); if (V.isUnknownOrUndef()) { - MakeNode(Dst, U, *I, state->bindExpr(U, V)); + MakeNode(Dst, U, *I, state->BindExpr(U, V)); continue; } - + // QualType DstT = getContext().getCanonicalType(U->getType()); // QualType SrcT = getContext().getCanonicalType(Ex->getType()); -// +// // if (DstT != SrcT) // Perform promotions. -// V = EvalCast(V, DstT); -// +// V = EvalCast(V, DstT); +// // if (V.isUnknownOrUndef()) { // MakeNode(Dst, U, *I, BindExpr(St, U, V)); // continue; // } - + switch (U->getOpcode()) { default: assert(false && "Invalid Opcode."); break; - + case UnaryOperator::Not: // FIXME: Do we need to handle promotions? - state = state->bindExpr(U, EvalComplement(cast(V))); - break; - + state = state->BindExpr(U, EvalComplement(cast(V))); + break; + case UnaryOperator::Minus: // FIXME: Do we need to handle promotions? - state = state->bindExpr(U, EvalMinus(cast(V))); - break; - - case UnaryOperator::LNot: - + state = state->BindExpr(U, EvalMinus(cast(V))); + break; + + case UnaryOperator::LNot: + // C99 6.5.3.3: "The expression !E is equivalent to (0==E)." // // Note: technically we do "E == 0", but this is the same in the // transfer functions as "0 == E". SVal Result; - + if (isa(V)) { Loc X = ValMgr.makeNull(); Result = EvalBinOp(state, BinaryOperator::EQ, cast(V), X, @@ -2578,18 +2532,18 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred, } else { nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType())); - Result = EvalBinOp(BinaryOperator::EQ, cast(V), X, + Result = EvalBinOp(state, BinaryOperator::EQ, cast(V), X, U->getType()); } - - state = state->bindExpr(U, Result); - + + state = state->BindExpr(U, Result); + break; } - + MakeNode(Dst, U, *I, state); } - + return; } } @@ -2597,170 +2551,183 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred, // Handle ++ and -- (both pre- and post-increment). assert (U->isIncrementDecrementOp()); - NodeSet Tmp; + ExplodedNodeSet Tmp; Expr* Ex = U->getSubExpr()->IgnoreParens(); VisitLValue(Ex, Pred, Tmp); - - for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) { - + + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) { + const GRState* state = GetState(*I); SVal V1 = state->getSVal(Ex); - - // Perform a load. - NodeSet Tmp2; + + // Perform a load. + ExplodedNodeSet Tmp2; EvalLoad(Tmp2, Ex, *I, state, V1); - for (NodeSet::iterator I2 = Tmp2.begin(), E2 = Tmp2.end(); I2!=E2; ++I2) { - + for (ExplodedNodeSet::iterator I2 = Tmp2.begin(), E2 = Tmp2.end(); I2!=E2; ++I2) { + state = GetState(*I2); - SVal V2 = state->getSVal(Ex); - - // Propagate unknown and undefined values. - if (V2.isUnknownOrUndef()) { - MakeNode(Dst, U, *I2, state->bindExpr(U, V2)); + SVal V2_untested = state->getSVal(Ex); + + // Propagate unknown and undefined values. + if (V2_untested.isUnknownOrUndef()) { + MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested)); continue; - } - - // Handle all other values. + } + DefinedSVal V2 = cast(V2_untested); + + // Handle all other values. BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add : BinaryOperator::Sub; - SVal Result = EvalBinOp(state, Op, V2, ValMgr.makeIntVal(1U,U->getType()), - U->getType()); - + // If the UnaryOperator has non-location type, use its type to create the + // constant value. If the UnaryOperator has location type, create the + // constant with int type and pointer width. + SVal RHS; + + if (U->getType()->isAnyPointerType()) + RHS = ValMgr.makeIntValWithPtrWidth(1, false); + else + RHS = ValMgr.makeIntVal(1, U->getType()); + + SVal Result = EvalBinOp(state, Op, V2, RHS, U->getType()); + // Conjure a new symbol if necessary to recover precision. if (Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)){ - Result = ValMgr.getConjuredSymbolVal(Ex, - Builder->getCurrentBlockCount()); - + DefinedOrUnknownSVal SymVal = + ValMgr.getConjuredSymbolVal(NULL, Ex, + Builder->getCurrentBlockCount()); + Result = SymVal; + // If the value is a location, ++/-- should always preserve // non-nullness. Check if the original value was non-null, and if so - // propagate that constraint. + // propagate that constraint. if (Loc::IsLocType(U->getType())) { - SVal Constraint = EvalBinOp(state, BinaryOperator::EQ, V2, - ValMgr.makeZeroVal(U->getType()), - getContext().IntTy); - - if (!state->assume(Constraint, true)) { + DefinedOrUnknownSVal Constraint = + SVator.EvalEQ(state, V2, ValMgr.makeZeroVal(U->getType())); + + if (!state->Assume(Constraint, true)) { // It isn't feasible for the original value to be null. // Propagate this constraint. - Constraint = EvalBinOp(state, BinaryOperator::EQ, Result, - ValMgr.makeZeroVal(U->getType()), - getContext().IntTy); - - state = state->assume(Constraint, false); + Constraint = SVator.EvalEQ(state, SymVal, + ValMgr.makeZeroVal(U->getType())); + + + state = state->Assume(Constraint, false); assert(state); - } - } + } + } } - - state = state->bindExpr(U, U->isPostfix() ? V2 : Result); - // Perform the store. + state = state->BindExpr(U, U->isPostfix() ? V2 : Result); + + // Perform the store. EvalStore(Dst, U, *I2, state, V1, Result); } } } -void GRExprEngine::VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst) { +void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst); -} +} void GRExprEngine::VisitAsmStmtHelperOutputs(AsmStmt* A, AsmStmt::outputs_iterator I, AsmStmt::outputs_iterator E, - NodeTy* Pred, NodeSet& Dst) { + ExplodedNode* Pred, ExplodedNodeSet& Dst) { if (I == E) { VisitAsmStmtHelperInputs(A, A->begin_inputs(), A->end_inputs(), Pred, Dst); return; } - - NodeSet Tmp; + + ExplodedNodeSet Tmp; VisitLValue(*I, Pred, Tmp); - + ++I; - - for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI) + + for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI) VisitAsmStmtHelperOutputs(A, I, E, *NI, Dst); } void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A, AsmStmt::inputs_iterator I, AsmStmt::inputs_iterator E, - NodeTy* Pred, NodeSet& Dst) { + ExplodedNode* Pred, ExplodedNodeSet& Dst) { if (I == E) { - + // We have processed both the inputs and the outputs. All of the outputs // should evaluate to Locs. Nuke all of their values. - + // FIXME: Some day in the future it would be nice to allow a "plug-in" // which interprets the inline asm and stores proper results in the // outputs. - + const GRState* state = GetState(Pred); - + for (AsmStmt::outputs_iterator OI = A->begin_outputs(), OE = A->end_outputs(); OI != OE; ++OI) { - - SVal X = state->getSVal(*OI); + + SVal X = state->getSVal(*OI); assert (!isa(X)); // Should be an Lval, or unknown, undef. - + if (isa(X)) state = state->bindLoc(cast(X), UnknownVal()); } - + MakeNode(Dst, A, Pred, state); return; } - - NodeSet Tmp; + + ExplodedNodeSet Tmp; Visit(*I, Pred, Tmp); - + ++I; - - for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI) + + for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI!=NE; ++NI) VisitAsmStmtHelperInputs(A, I, E, *NI, Dst); } -void GRExprEngine::EvalReturn(NodeSet& Dst, ReturnStmt* S, NodeTy* Pred) { +void GRExprEngine::EvalReturn(ExplodedNodeSet& Dst, ReturnStmt* S, + ExplodedNode* Pred) { assert (Builder && "GRStmtNodeBuilder must be defined."); - - unsigned size = Dst.size(); + + unsigned size = Dst.size(); SaveAndRestore OldSink(Builder->BuildSinks); SaveOr OldHasGen(Builder->HasGeneratedNode); getTF().EvalReturn(Dst, *this, *Builder, S, Pred); - + // Handle the case where no nodes where generated. - + if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode) MakeNode(Dst, S, Pred, GetState(Pred)); } -void GRExprEngine::VisitReturnStmt(ReturnStmt* S, NodeTy* Pred, NodeSet& Dst) { +void GRExprEngine::VisitReturnStmt(ReturnStmt* S, ExplodedNode* Pred, + ExplodedNodeSet& Dst) { Expr* R = S->getRetValue(); - + if (!R) { EvalReturn(Dst, S, Pred); return; } - NodeSet Tmp; + ExplodedNodeSet Tmp; Visit(R, Pred, Tmp); - for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { SVal X = (*I)->getState()->getSVal(R); - + // Check if we return the address of a stack variable. if (isa(X)) { // Determine if the value is on the stack. const MemRegion* R = cast(&X)->getRegion(); - + if (R && R->hasStackStorage()) { // Create a special node representing the error. - if (NodeTy* N = Builder->generateNode(S, GetState(*I), *I)) { + if (ExplodedNode* N = Builder->generateNode(S, GetState(*I), *I)) { N->markAsSink(); RetsStackAddr.insert(N); } @@ -2769,13 +2736,13 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt* S, NodeTy* Pred, NodeSet& Dst) { } // Check if we return an undefined value. else if (X.isUndef()) { - if (NodeTy* N = Builder->generateNode(S, GetState(*I), *I)) { + if (ExplodedNode* N = Builder->generateNode(S, GetState(*I), *I)) { N->markAsSink(); RetsUndef.insert(N); } continue; } - + EvalReturn(Dst, S, *I); } } @@ -2784,127 +2751,76 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt* S, NodeTy* Pred, NodeSet& Dst) { // Transfer functions: Binary operators. //===----------------------------------------------------------------------===// -const GRState* GRExprEngine::CheckDivideZero(Expr* Ex, const GRState* state, - NodeTy* Pred, SVal Denom) { - - // Divide by undefined? (potentially zero) - - if (Denom.isUndef()) { - NodeTy* DivUndef = Builder->generateNode(Ex, state, Pred); - - if (DivUndef) { - DivUndef->markAsSink(); - ExplicitBadDivides.insert(DivUndef); - } - - return 0; - } - - // Check for divide/remainder-by-zero. - // First, "assume" that the denominator is 0 or undefined. - const GRState* zeroState = state->assume(Denom, false); - - // Second, "assume" that the denominator cannot be 0. - state = state->assume(Denom, true); - - // Create the node for the divide-by-zero (if it occurred). - if (zeroState) - if (NodeTy* DivZeroNode = Builder->generateNode(Ex, zeroState, Pred)) { - DivZeroNode->markAsSink(); - - if (state) - ImplicitBadDivides.insert(DivZeroNode); - else - ExplicitBadDivides.insert(DivZeroNode); - - } - - return state; -} - void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, - GRExprEngine::NodeTy* Pred, - GRExprEngine::NodeSet& Dst) { + ExplodedNode* Pred, + ExplodedNodeSet& Dst) { - NodeSet Tmp1; + ExplodedNodeSet Tmp1; Expr* LHS = B->getLHS()->IgnoreParens(); Expr* RHS = B->getRHS()->IgnoreParens(); - - // FIXME: Add proper support for ObjCKVCRefExpr. - if (isa(LHS)) { - Visit(RHS, Pred, Dst); + + // FIXME: Add proper support for ObjCImplicitSetterGetterRefExpr. + if (isa(LHS)) { + Visit(RHS, Pred, Dst); return; } - + if (B->isAssignmentOp()) VisitLValue(LHS, Pred, Tmp1); else Visit(LHS, Pred, Tmp1); - for (NodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1 != E1; ++I1) { - + for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) { SVal LeftV = (*I1)->getState()->getSVal(LHS); - - // Process the RHS. - - NodeSet Tmp2; + ExplodedNodeSet Tmp2; Visit(RHS, *I1, Tmp2); - + + ExplodedNodeSet CheckedSet; + CheckerVisit(B, CheckedSet, Tmp2, true); + // With both the LHS and RHS evaluated, process the operation itself. - - for (NodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end(); I2 != E2; ++I2) { - const GRState* state = GetState(*I2); - const GRState* OldSt = state; + for (ExplodedNodeSet::iterator I2=CheckedSet.begin(), E2=CheckedSet.end(); + I2 != E2; ++I2) { + const GRState *state = GetState(*I2); + const GRState *OldSt = state; SVal RightV = state->getSVal(RHS); + BinaryOperator::Opcode Op = B->getOpcode(); - switch (Op) { - case BinaryOperator::Assign: { - + // EXPERIMENTAL: "Conjured" symbols. // FIXME: Handle structs. QualType T = RHS->getType(); - - if ((RightV.isUnknown() || - !getConstraintManager().canReasonAbout(RightV)) - && (Loc::IsLocType(T) || + + if ((RightV.isUnknown() || + !getConstraintManager().canReasonAbout(RightV)) + && (Loc::IsLocType(T) || (T->isScalarType() && T->isIntegerType()))) { - unsigned Count = Builder->getCurrentBlockCount(); - RightV = ValMgr.getConjuredSymbolVal(B->getRHS(), Count); + unsigned Count = Builder->getCurrentBlockCount(); + RightV = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), Count); } - + // Simulate the effects of a "store": bind the value of the RHS - // to the L-Value represented by the LHS. - EvalStore(Dst, B, LHS, *I2, state->bindExpr(B, RightV), LeftV, - RightV); + // to the L-Value represented by the LHS. + EvalStore(Dst, B, LHS, *I2, state->BindExpr(B, RightV), + LeftV, RightV); continue; } - - case BinaryOperator::Div: - case BinaryOperator::Rem: - - // Special checking for integer denominators. - if (RHS->getType()->isIntegerType() && - RHS->getType()->isScalarType()) { - - state = CheckDivideZero(B, state, *I2, RightV); - if (!state) continue; - } - + // FALL-THROUGH. default: { - + if (B->isAssignmentOp()) break; - + // Process non-assignments except commas or short-circuited - // logical expressions (LAnd and LOr). + // 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. @@ -2912,30 +2828,28 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, } else Dst.Add(*I2); - + continue; } - - if (Result.isUndef() && !LeftV.isUndef() && !RightV.isUndef()) { - + + state = state->BindExpr(B, Result); + + if (Result.isUndef()) { // The operands were *not* undefined, but the result is undefined. // This is a special node that should be flagged as an error. - - if (NodeTy* UndefNode = Builder->generateNode(B, state, *I2)) { - UndefNode->markAsSink(); + if (ExplodedNode *UndefNode = Builder->generateNode(B, state, *I2)){ + UndefNode->markAsSink(); UndefResults.insert(UndefNode); } - continue; } - + // Otherwise, create a new node. - - MakeNode(Dst, B, *I2, state->bindExpr(B, Result)); + MakeNode(Dst, B, *I2, state); continue; } } - + assert (B->isCompoundAssignmentOp()); switch (Op) { @@ -2952,78 +2866,44 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, case BinaryOperator::XorAssign: Op = BinaryOperator::Xor; break; case BinaryOperator::OrAssign: Op = BinaryOperator::Or; break; } - + // Perform a load (the LHS). This performs the checks for // null dereferences, and so on. - NodeSet Tmp3; + ExplodedNodeSet Tmp3; SVal location = state->getSVal(LHS); EvalLoad(Tmp3, LHS, *I2, state, location); - - for (NodeSet::iterator I3=Tmp3.begin(), E3=Tmp3.end(); I3!=E3; ++I3) { - + + for (ExplodedNodeSet::iterator I3=Tmp3.begin(), E3=Tmp3.end(); I3!=E3; + ++I3) { + state = GetState(*I3); SVal V = state->getSVal(LHS); - // Check for divide-by-zero. - if ((Op == BinaryOperator::Div || Op == BinaryOperator::Rem) - && RHS->getType()->isIntegerType() - && RHS->getType()->isScalarType()) { - - // CheckDivideZero returns a new state where the denominator - // is assumed to be non-zero. - state = CheckDivideZero(B, state, *I3, RightV); - - if (!state) - continue; - } - - // Propagate undefined values (left-side). - if (V.isUndef()) { - EvalStore(Dst, B, LHS, *I3, state->bindExpr(B, V), location, V); - continue; - } - - // Propagate unknown values (left and right-side). - if (RightV.isUnknown() || V.isUnknown()) { - EvalStore(Dst, B, LHS, *I3, state->bindExpr(B, UnknownVal()), - location, UnknownVal()); - continue; - } - - // At this point: - // - // The LHS is not Undef/Unknown. - // The RHS is not Unknown. - // Get the computation type. - QualType CTy = cast(B)->getComputationResultType(); + QualType CTy = + cast(B)->getComputationResultType(); CTy = getContext().getCanonicalType(CTy); - QualType CLHSTy = cast(B)->getComputationLHSType(); - CLHSTy = getContext().getCanonicalType(CTy); + QualType CLHSTy = + cast(B)->getComputationLHSType(); + CLHSTy = getContext().getCanonicalType(CLHSTy); QualType LTy = getContext().getCanonicalType(LHS->getType()); QualType RTy = getContext().getCanonicalType(RHS->getType()); // Promote LHS. - V = EvalCast(V, CLHSTy); + llvm::tie(state, V) = SVator.EvalCast(V, state, 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); - // Evaluate operands and promote to result type. - if (RightV.isUndef()) { - // Propagate undefined values (right-side). - EvalStore(Dst, B, LHS, *I3, state->bindExpr(B, RightV), location, - RightV); - continue; - } - - // Compute the result of the operation. - SVal Result = EvalCast(EvalBinOp(state, Op, V, RightV, CTy), - B->getType()); - if (Result.isUndef()) { // The operands were not undefined, but the result is undefined. - if (NodeTy* UndefNode = Builder->generateNode(B, state, *I3)) { - UndefNode->markAsSink(); + if (ExplodedNode* UndefNode = Builder->generateNode(B, state, *I3)) { + UndefNode->markAsSink(); UndefResults.insert(UndefNode); } continue; @@ -3031,70 +2911,37 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, // EXPERIMENTAL: "Conjured" symbols. // FIXME: Handle structs. - + SVal LHSVal; - - if ((Result.isUnknown() || + + if ((Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)) - && (Loc::IsLocType(CTy) + && (Loc::IsLocType(CTy) || (CTy->isScalarType() && CTy->isIntegerType()))) { - + unsigned Count = Builder->getCurrentBlockCount(); - + // The symbolic value is actually for the type of the left-hand side // expression, not the computation type, as this is the value the // LValue on the LHS will bind to. - LHSVal = ValMgr.getConjuredSymbolVal(B->getRHS(), LTy, Count); - + LHSVal = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), LTy, Count); + // However, we need to convert the symbol to the computation type. - Result = (LTy == CTy) ? LHSVal : EvalCast(LHSVal,CTy); + llvm::tie(state, Result) = SVator.EvalCast(LHSVal, state, CTy, LTy); } else { // The left-hand side may bind to a different value then the // computation type. - LHSVal = (LTy == CTy) ? Result : EvalCast(Result,LTy); + llvm::tie(state, LHSVal) = SVator.EvalCast(Result, state, LTy, CTy); } - - EvalStore(Dst, B, LHS, *I3, state->bindExpr(B, Result), location, - LHSVal); + + EvalStore(Dst, B, LHS, *I3, state->BindExpr(B, Result), + location, LHSVal); } } } } -//===----------------------------------------------------------------------===// -// Transfer-function Helpers. -//===----------------------------------------------------------------------===// - -SVal GRExprEngine::EvalBinOp(const GRState* state, BinaryOperator::Opcode Op, - SVal L, SVal R, QualType T) { - - if (L.isUndef() || R.isUndef()) - return UndefinedVal(); - - if (L.isUnknown() || R.isUnknown()) - return UnknownVal(); - - if (isa(L)) { - if (isa(R)) - return SVator->EvalBinOpLL(Op, cast(L), cast(R), T); - else - return SVator->EvalBinOpLN(state, Op, cast(L), cast(R), T); - } - - if (isa(R)) { - // Support pointer arithmetic where the increment/decrement operand - // is on the left and the pointer on the right. - - assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub); - - // Commute the operands. - return SVator->EvalBinOpLN(state, Op, cast(R), cast(L), T); - } - else - return SVator->EvalBinOpNN(Op, cast(L), cast(R), T); -} - //===----------------------------------------------------------------------===// // Visualization. //===----------------------------------------------------------------------===// @@ -3105,67 +2952,65 @@ static SourceManager* GraphPrintSourceManager; namespace llvm { template<> -struct VISIBILITY_HIDDEN DOTGraphTraits : +struct VISIBILITY_HIDDEN DOTGraphTraits : public DefaultDOTGraphTraits { - - static std::string getNodeAttributes(const GRExprEngine::NodeTy* N, void*) { - + + static std::string getNodeAttributes(const ExplodedNode* N, void*) { + if (GraphPrintCheckerState->isImplicitNullDeref(N) || GraphPrintCheckerState->isExplicitNullDeref(N) || GraphPrintCheckerState->isUndefDeref(N) || GraphPrintCheckerState->isUndefStore(N) || GraphPrintCheckerState->isUndefControlFlow(N) || - GraphPrintCheckerState->isExplicitBadDivide(N) || - GraphPrintCheckerState->isImplicitBadDivide(N) || GraphPrintCheckerState->isUndefResult(N) || GraphPrintCheckerState->isBadCall(N) || GraphPrintCheckerState->isUndefArg(N)) return "color=\"red\",style=\"filled\""; - + if (GraphPrintCheckerState->isNoReturnCall(N)) return "color=\"blue\",style=\"filled\""; - + return ""; } - - static std::string getNodeLabel(const GRExprEngine::NodeTy* N, void*, - bool ShortNames) { - + + static std::string getNodeLabel(const ExplodedNode* N, void*,bool ShortNames){ + std::string sbuf; llvm::raw_string_ostream Out(sbuf); // Program Location. ProgramPoint Loc = N->getLocation(); - + switch (Loc.getKind()) { case ProgramPoint::BlockEntranceKind: - Out << "Block Entrance: B" + Out << "Block Entrance: B" << cast(Loc).getBlock()->getBlockID(); break; - + case ProgramPoint::BlockExitKind: assert (false); break; - + default: { - if (isa(Loc)) { - const PostStmt& L = cast(Loc); - Stmt* S = L.getStmt(); + if (StmtPoint *L = dyn_cast(&Loc)) { + const Stmt* S = L->getStmt(); SourceLocation SLoc = S->getLocStart(); - Out << S->getStmtClassName() << ' ' << (void*) S << ' '; + Out << S->getStmtClassName() << ' ' << (void*) S << ' '; LangOptions LO; // FIXME. S->printPretty(Out, 0, PrintingPolicy(LO)); - - if (SLoc.isFileID()) { + + if (SLoc.isFileID()) { Out << "\\lline=" << GraphPrintSourceManager->getInstantiationLineNumber(SLoc) << " col=" << GraphPrintSourceManager->getInstantiationColumnNumber(SLoc) << "\\l"; } - - if (isa(Loc)) + + if (isa(Loc)) + Out << "\\lPreStmt\\l;"; + else if (isa(Loc)) Out << "\\lPostLoad\\l;"; else if (isa(Loc)) Out << "\\lPostStore\\l"; @@ -3175,7 +3020,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits : Out << "\\lPostLocationChecksSucceed\\l"; else if (isa(Loc)) Out << "\\lPostNullCheckFailed\\l"; - + if (GraphPrintCheckerState->isImplicitNullDeref(N)) Out << "\\|Implicit-Null Dereference.\\l"; else if (GraphPrintCheckerState->isExplicitNullDeref(N)) @@ -3184,10 +3029,6 @@ struct VISIBILITY_HIDDEN DOTGraphTraits : Out << "\\|Dereference of undefialied value.\\l"; else if (GraphPrintCheckerState->isUndefStore(N)) Out << "\\|Store to Undefined Loc."; - else if (GraphPrintCheckerState->isExplicitBadDivide(N)) - Out << "\\|Explicit divide-by zero or undefined value."; - else if (GraphPrintCheckerState->isImplicitBadDivide(N)) - Out << "\\|Implicit divide-by zero or undefined value."; else if (GraphPrintCheckerState->isUndefResult(N)) Out << "\\|Result of operation is undefined."; else if (GraphPrintCheckerState->isNoReturnCall(N)) @@ -3196,43 +3037,43 @@ struct VISIBILITY_HIDDEN DOTGraphTraits : Out << "\\|Call to NULL/Undefined."; else if (GraphPrintCheckerState->isUndefArg(N)) Out << "\\|Argument in call is undefined"; - + break; } const BlockEdge& E = cast(Loc); Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B" << E.getDst()->getBlockID() << ')'; - + if (Stmt* T = E.getSrc()->getTerminator()) { - + SourceLocation SLoc = T->getLocStart(); - + Out << "\\|Terminator: "; LangOptions LO; // FIXME. E.getSrc()->printTerminator(Out, LO); - + if (SLoc.isFileID()) { Out << "\\lline=" << GraphPrintSourceManager->getInstantiationLineNumber(SLoc) << " col=" << GraphPrintSourceManager->getInstantiationColumnNumber(SLoc); } - + if (isa(T)) { Stmt* Label = E.getDst()->getLabel(); - - if (Label) { + + if (Label) { if (CaseStmt* C = dyn_cast(Label)) { Out << "\\lcase "; LangOptions LO; // FIXME. C->getLHS()->printPretty(Out, 0, PrintingPolicy(LO)); - + if (Stmt* RHS = C->getRHS()) { Out << " .. "; RHS->printPretty(Out, 0, PrintingPolicy(LO)); } - + Out << ":"; } else { @@ -3240,7 +3081,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits : Out << "\\ldefault:"; } } - else + else Out << "\\l(implicit) default:"; } else if (isa(T)) { @@ -3251,46 +3092,45 @@ struct VISIBILITY_HIDDEN DOTGraphTraits : if (*E.getSrc()->succ_begin() == E.getDst()) Out << "true"; else - Out << "false"; + Out << "false"; } - + Out << "\\l"; } - + if (GraphPrintCheckerState->isUndefControlFlow(N)) { Out << "\\|Control-flow based on\\lUndefined value.\\l"; } } } - + Out << "\\|StateID: " << (void*) N->getState() << "\\|"; const GRState *state = N->getState(); state->printDOT(Out); - + Out << "\\l"; return Out.str(); } }; -} // end llvm namespace +} // end llvm namespace #endif #ifndef NDEBUG template -GRExprEngine::NodeTy* GetGraphNode(ITERATOR I) { return *I; } +ExplodedNode* GetGraphNode(ITERATOR I) { return *I; } -template <> -GRExprEngine::NodeTy* -GetGraphNode::iterator> - (llvm::DenseMap::iterator I) { +template <> ExplodedNode* +GetGraphNode::iterator> + (llvm::DenseMap::iterator I) { return I->first; } #endif void GRExprEngine::ViewGraph(bool trim) { -#ifndef NDEBUG +#ifndef NDEBUG if (trim) { - std::vector Src; + std::vector Src; // Flush any outstanding reports to make sure we cover all the nodes. // This does not cause them to get displayed. @@ -3299,14 +3139,15 @@ void GRExprEngine::ViewGraph(bool trim) { // Iterate through the reports and get their nodes. for (BugReporter::iterator I=BR.begin(), E=BR.end(); I!=E; ++I) { - for (BugType::const_iterator I2=(*I)->begin(), E2=(*I)->end(); I2!=E2; ++I2) { + for (BugType::const_iterator I2=(*I)->begin(), E2=(*I)->end(); + I2!=E2; ++I2) { const BugReportEquivClass& EQ = *I2; const BugReport &R = **EQ.begin(); - NodeTy *N = const_cast(R.getEndNode()); + ExplodedNode *N = const_cast(R.getEndNode()); if (N) Src.push_back(N); } } - + ViewGraph(&Src[0], &Src[0]+Src.size()); } else { @@ -3314,25 +3155,25 @@ void GRExprEngine::ViewGraph(bool trim) { GraphPrintSourceManager = &getContext().getSourceManager(); llvm::ViewGraph(*G.roots_begin(), "GRExprEngine"); - + GraphPrintCheckerState = NULL; GraphPrintSourceManager = NULL; } #endif } -void GRExprEngine::ViewGraph(NodeTy** Beg, NodeTy** End) { +void GRExprEngine::ViewGraph(ExplodedNode** Beg, ExplodedNode** End) { #ifndef NDEBUG GraphPrintCheckerState = this; GraphPrintSourceManager = &getContext().getSourceManager(); - - std::auto_ptr TrimmedG(G.Trim(Beg, End).first); + + std::auto_ptr TrimmedG(G.Trim(Beg, End).first); if (!TrimmedG.get()) - llvm::cerr << "warning: Trimmed ExplodedGraph is empty.\n"; + llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n"; else - llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedGRExprEngine"); - + llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedGRExprEngine"); + GraphPrintCheckerState = NULL; GraphPrintSourceManager = NULL; #endif diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp index a2ce79a2f390..cc1ec4b77e48 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.cpp +++ b/lib/Analysis/GRExprEngineInternalChecks.cpp @@ -14,41 +14,29 @@ #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" #include "clang/Analysis/PathDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" using namespace clang; +using namespace clang::bugreporter; //===----------------------------------------------------------------------===// // Utility functions. //===----------------------------------------------------------------------===// template inline -ExplodedNode* GetNode(ITERATOR I) { +ExplodedNode* GetNode(ITERATOR I) { return *I; } template <> inline -ExplodedNode* GetNode(GRExprEngine::undef_arg_iterator I) { +ExplodedNode* GetNode(GRExprEngine::undef_arg_iterator I) { return I->first; } -//===----------------------------------------------------------------------===// -// Forward declarations for bug reporter visitors. -//===----------------------------------------------------------------------===// - -static const Stmt *GetDerefExpr(const ExplodedNode *N); -static const Stmt *GetReceiverExpr(const ExplodedNode *N); -static const Stmt *GetDenomExpr(const ExplodedNode *N); -static const Stmt *GetCalleeExpr(const ExplodedNode *N); -static const Stmt *GetRetValExpr(const ExplodedNode *N); - -static void registerTrackNullOrUndefValue(BugReporterContext& BRC, - const Stmt *ValExpr, - const ExplodedNode* N); - //===----------------------------------------------------------------------===// // Bug Descriptions. //===----------------------------------------------------------------------===// @@ -58,17 +46,17 @@ namespace { class VISIBILITY_HIDDEN BuiltinBugReport : public RangedBugReport { public: BuiltinBugReport(BugType& bt, const char* desc, - ExplodedNode *n) + ExplodedNode *n) : RangedBugReport(bt, desc, n) {} - + BuiltinBugReport(BugType& bt, const char *shortDesc, const char *desc, - ExplodedNode *n) - : RangedBugReport(bt, shortDesc, desc, n) {} - + ExplodedNode *n) + : RangedBugReport(bt, shortDesc, desc, n) {} + void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N); -}; - + const ExplodedNode* N); +}; + class VISIBILITY_HIDDEN BuiltinBug : public BugType { GRExprEngine &Eng; protected: @@ -79,30 +67,32 @@ public: BuiltinBug(GRExprEngine *eng, const char* n) : BugType(n, "Logic errors"), Eng(*eng), desc(n) {} - - virtual void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) = 0; + + const std::string &getDescription() const { return desc; } + + virtual void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {} void FlushReports(BugReporter& BR) { FlushReportsImpl(BR, Eng); } - + virtual void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, + const ExplodedNode* N, BuiltinBugReport *R) {} - + template void Emit(BugReporter& BR, ITER I, ITER E); }; - - + + template void BuiltinBug::Emit(BugReporter& BR, ITER I, ITER E) { for (; I != E; ++I) BR.EmitReport(new BuiltinBugReport(*this, desc.c_str(), GetNode(I))); -} +} void BuiltinBugReport::registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N) { + const ExplodedNode* N) { static_cast(getBugType()).registerInitialVisitors(BRC, N, this); -} - +} + class VISIBILITY_HIDDEN NullDeref : public BuiltinBug { public: NullDeref(GRExprEngine* eng) @@ -111,14 +101,14 @@ public: void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { Emit(BR, Eng.null_derefs_begin(), Eng.null_derefs_end()); } - + void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, + const ExplodedNode* N, BuiltinBugReport *R) { registerTrackNullOrUndefValue(BRC, GetDerefExpr(N), N); } }; - + class VISIBILITY_HIDDEN NilReceiverStructRet : public BuiltinBug { public: NilReceiverStructRet(GRExprEngine* eng) : @@ -132,20 +122,20 @@ public: std::string sbuf; llvm::raw_string_ostream os(sbuf); PostStmt P = cast((*I)->getLocation()); - ObjCMessageExpr *ME = cast(P.getStmt()); + const ObjCMessageExpr *ME = cast(P.getStmt()); os << "The receiver in the message expression is 'nil' and results in the" " returned value (of type '" << ME->getType().getAsString() - << "') to be garbage or otherwise undefined."; + << "') to be garbage or otherwise undefined"; BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I); R->addRange(ME->getReceiver()->getSourceRange()); BR.EmitReport(R); } } - + void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, + const ExplodedNode* N, BuiltinBugReport *R) { registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N); } @@ -156,46 +146,46 @@ public: NilReceiverLargerThanVoidPtrRet(GRExprEngine* eng) : BuiltinBug(eng, "'nil' receiver with return type larger than sizeof(void *)") {} - + void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { for (GRExprEngine::nil_receiver_larger_than_voidptr_ret_iterator I=Eng.nil_receiver_larger_than_voidptr_ret_begin(), E=Eng.nil_receiver_larger_than_voidptr_ret_end(); I!=E; ++I) { - + std::string sbuf; llvm::raw_string_ostream os(sbuf); PostStmt P = cast((*I)->getLocation()); - ObjCMessageExpr *ME = cast(P.getStmt()); + const ObjCMessageExpr *ME = cast(P.getStmt()); os << "The receiver in the message expression is 'nil' and results in the" " returned value (of type '" << ME->getType().getAsString() << "' and of size " << Eng.getContext().getTypeSize(ME->getType()) / 8 - << " bytes) to be garbage or otherwise undefined."; - + << " bytes) to be garbage or otherwise undefined"; + BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I); R->addRange(ME->getReceiver()->getSourceRange()); BR.EmitReport(R); } - } + } void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, + const ExplodedNode* N, BuiltinBugReport *R) { registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N); } }; - + class VISIBILITY_HIDDEN UndefinedDeref : public BuiltinBug { public: UndefinedDeref(GRExprEngine* eng) : BuiltinBug(eng,"Dereference of undefined pointer value") {} - + void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { Emit(BR, Eng.undef_derefs_begin(), Eng.undef_derefs_end()); } - + void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, + const ExplodedNode* N, BuiltinBugReport *R) { registerTrackNullOrUndefValue(BRC, GetDerefExpr(N), N); } @@ -203,43 +193,100 @@ public: class VISIBILITY_HIDDEN DivZero : public BuiltinBug { public: - DivZero(GRExprEngine* eng) - : BuiltinBug(eng,"Division-by-zero", - "Division by zero or undefined value.") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - Emit(BR, Eng.explicit_bad_divides_begin(), Eng.explicit_bad_divides_end()); - } - + DivZero(GRExprEngine* eng = 0) + : BuiltinBug(eng,"Division by zero") {} + void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, + const ExplodedNode* N, BuiltinBugReport *R) { registerTrackNullOrUndefValue(BRC, GetDenomExpr(N), N); } }; - + class VISIBILITY_HIDDEN UndefResult : public BuiltinBug { public: - UndefResult(GRExprEngine* eng) : BuiltinBug(eng,"Undefined result", - "Result of operation is undefined.") {} - + UndefResult(GRExprEngine* eng) + : BuiltinBug(eng,"Undefined or garbage result", + "Result of operation is garbage or undefined") {} + void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - Emit(BR, Eng.undef_results_begin(), Eng.undef_results_end()); + for (GRExprEngine::undef_result_iterator I=Eng.undef_results_begin(), + E = Eng.undef_results_end(); I!=E; ++I) { + + ExplodedNode *N = *I; + const Stmt *S = N->getLocationAs()->getStmt(); + BuiltinBugReport *report = NULL; + + if (const BinaryOperator *B = dyn_cast(S)) { + llvm::SmallString<256> sbuf; + llvm::raw_svector_ostream OS(sbuf); + const GRState *ST = N->getState(); + const Expr *Ex = NULL; + bool isLeft = true; + + if (ST->getSVal(B->getLHS()).isUndef()) { + Ex = B->getLHS()->IgnoreParenCasts(); + isLeft = true; + } + else if (ST->getSVal(B->getRHS()).isUndef()) { + Ex = B->getRHS()->IgnoreParenCasts(); + isLeft = false; + } + + if (Ex) { + OS << "The " << (isLeft ? "left" : "right") + << " operand of '" + << BinaryOperator::getOpcodeStr(B->getOpcode()) + << "' is a garbage value"; + } + else { + // Neither operand was undefined, but the result is undefined. + OS << "The result of the '" + << BinaryOperator::getOpcodeStr(B->getOpcode()) + << "' expression is undefined"; + } + + // FIXME: Use StringRefs to pass string information. + report = new BuiltinBugReport(*this, OS.str().str().c_str(), N); + if (Ex) report->addRange(Ex->getSourceRange()); + } + else { + report = new BuiltinBugReport(*this, + "Expression evaluates to an uninitialized" + " or undefined value", N); + } + + BR.EmitReport(report); + } } -}; + void registerInitialVisitors(BugReporterContext& BRC, + const ExplodedNode* N, + BuiltinBugReport *R) { + + const Stmt *S = N->getLocationAs()->getStmt(); + const Stmt *X = S; + + if (const BinaryOperator *B = dyn_cast(S)) { + const GRState *ST = N->getState(); + if (ST->getSVal(B->getLHS()).isUndef()) + X = B->getLHS(); + else if (ST->getSVal(B->getRHS()).isUndef()) + X = B->getRHS(); + } + + registerTrackNullOrUndefValue(BRC, X, N); + } +}; + class VISIBILITY_HIDDEN BadCall : public BuiltinBug { public: - BadCall(GRExprEngine *eng) + BadCall(GRExprEngine *eng = 0) : BuiltinBug(eng, "Invalid function call", "Called function pointer is a null or undefined pointer value") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - Emit(BR, Eng.bad_calls_begin(), Eng.bad_calls_end()); - } - + void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, + const ExplodedNode* N, BuiltinBugReport *R) { registerTrackNullOrUndefValue(BRC, GetCalleeExpr(N), N); } @@ -249,76 +296,65 @@ public: class VISIBILITY_HIDDEN ArgReport : public BuiltinBugReport { const Stmt *Arg; public: - ArgReport(BugType& bt, const char* desc, ExplodedNode *n, + ArgReport(BugType& bt, const char* desc, ExplodedNode *n, const Stmt *arg) : BuiltinBugReport(bt, desc, n), Arg(arg) {} - + ArgReport(BugType& bt, const char *shortDesc, const char *desc, - ExplodedNode *n, const Stmt *arg) - : BuiltinBugReport(bt, shortDesc, desc, n), Arg(arg) {} - - const Stmt *getArg() const { return Arg; } + ExplodedNode *n, const Stmt *arg) + : BuiltinBugReport(bt, shortDesc, desc, n), Arg(arg) {} + + const Stmt *getArg() const { return Arg; } }; class VISIBILITY_HIDDEN BadArg : public BuiltinBug { -public: - BadArg(GRExprEngine* eng) : BuiltinBug(eng,"Uninitialized argument", - "Pass-by-value argument in function call is undefined.") {} +public: + BadArg(GRExprEngine* eng=0) : BuiltinBug(eng,"Uninitialized argument", + "Pass-by-value argument in function call is undefined") {} BadArg(GRExprEngine* eng, const char* d) : BuiltinBug(eng,"Uninitialized argument", d) {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - for (GRExprEngine::UndefArgsTy::iterator I = Eng.undef_arg_begin(), - E = Eng.undef_arg_end(); I!=E; ++I) { - // Generate a report for this bug. - ArgReport *report = new ArgReport(*this, desc.c_str(), I->first, - I->second); - report->addRange(I->second->getSourceRange()); - BR.EmitReport(report); - } - } void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, + const ExplodedNode* N, BuiltinBugReport *R) { registerTrackNullOrUndefValue(BRC, static_cast(R)->getArg(), N); - } + } }; - + class VISIBILITY_HIDDEN BadMsgExprArg : public BadArg { public: - BadMsgExprArg(GRExprEngine* eng) + BadMsgExprArg(GRExprEngine* eng) : BadArg(eng,"Pass-by-value argument in message expression is undefined"){} - + void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { for (GRExprEngine::UndefArgsTy::iterator I=Eng.msg_expr_undef_arg_begin(), - E = Eng.msg_expr_undef_arg_end(); I!=E; ++I) { + E = Eng.msg_expr_undef_arg_end(); I!=E; ++I) { // Generate a report for this bug. ArgReport *report = new ArgReport(*this, desc.c_str(), I->first, I->second); report->addRange(I->second->getSourceRange()); BR.EmitReport(report); - } - } + } + } }; - + class VISIBILITY_HIDDEN BadReceiver : public BuiltinBug { -public: +public: BadReceiver(GRExprEngine* eng) : BuiltinBug(eng,"Uninitialized receiver", "Receiver in message expression is an uninitialized value") {} - + void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { for (GRExprEngine::ErrorNodes::iterator I=Eng.undef_receivers_begin(), End = Eng.undef_receivers_end(); I!=End; ++I) { - + // Generate a report for this bug. BuiltinBugReport *report = new BuiltinBugReport(*this, desc.c_str(), *I); - ExplodedNode* N = *I; - Stmt *S = cast(N->getLocation()).getStmt(); - Expr* E = cast(S)->getReceiver(); + ExplodedNode* N = *I; + const Stmt *S = cast(N->getLocation()).getStmt(); + const Expr* E = cast(S)->getReceiver(); assert (E && "Receiver cannot be NULL"); report->addRange(E->getSourceRange()); BR.EmitReport(report); @@ -326,61 +362,61 @@ public: } void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, + const ExplodedNode* N, BuiltinBugReport *R) { registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N); - } + } }; class VISIBILITY_HIDDEN RetStack : public BuiltinBug { public: RetStack(GRExprEngine* eng) : BuiltinBug(eng, "Return of address to stack-allocated memory") {} - + void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { for (GRExprEngine::ret_stackaddr_iterator I=Eng.ret_stackaddr_begin(), End = Eng.ret_stackaddr_end(); I!=End; ++I) { - ExplodedNode* N = *I; - Stmt *S = cast(N->getLocation()).getStmt(); - Expr* E = cast(S)->getRetValue(); - assert (E && "Return expression cannot be NULL"); - + ExplodedNode* N = *I; + const Stmt *S = cast(N->getLocation()).getStmt(); + const Expr* E = cast(S)->getRetValue(); + assert(E && "Return expression cannot be NULL"); + // Get the value associated with E. loc::MemRegionVal V = cast(N->getState()->getSVal(E)); - + // Generate a report for this bug. std::string buf; llvm::raw_string_ostream os(buf); SourceRange R; - + // Check if the region is a compound literal. - if (const CompoundLiteralRegion* CR = + if (const CompoundLiteralRegion* CR = dyn_cast(V.getRegion())) { - + const CompoundLiteralExpr* CL = CR->getLiteralExpr(); os << "Address of stack memory associated with a compound literal " "declared on line " << BR.getSourceManager() .getInstantiationLineNumber(CL->getLocStart()) << " returned."; - + R = CL->getSourceRange(); } else if (const AllocaRegion* AR = dyn_cast(V.getRegion())) { const Expr* ARE = AR->getExpr(); SourceLocation L = ARE->getLocStart(); R = ARE->getSourceRange(); - + os << "Address of stack memory allocated by call to alloca() on line " << BR.getSourceManager().getInstantiationLineNumber(L) << " returned."; - } - else { + } + else { os << "Address of stack memory associated with local variable '" << V.getRegion()->getString() << "' returned."; } - + RangedBugReport *report = new RangedBugReport(*this, os.str().c_str(), N); report->addRange(E->getSourceRange()); if (R.isValid()) report->addRange(R); @@ -388,51 +424,52 @@ public: } } }; - + class VISIBILITY_HIDDEN RetUndef : public BuiltinBug { public: - RetUndef(GRExprEngine* eng) : BuiltinBug(eng, "Uninitialized return value", - "Uninitialized or undefined value returned to caller.") {} - + RetUndef(GRExprEngine* eng) : BuiltinBug(eng, "Garbage return value", + "Undefined or garbage value returned to caller") {} + void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { Emit(BR, Eng.ret_undef_begin(), Eng.ret_undef_end()); } - + void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, + const ExplodedNode* N, BuiltinBugReport *R) { registerTrackNullOrUndefValue(BRC, GetRetValExpr(N), N); - } + } }; class VISIBILITY_HIDDEN UndefBranch : public BuiltinBug { struct VISIBILITY_HIDDEN FindUndefExpr { GRStateManager& VM; const GRState* St; - + FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {} - - Expr* FindExpr(Expr* Ex) { + + Expr* FindExpr(Expr* Ex) { if (!MatchesCriteria(Ex)) return 0; - + for (Stmt::child_iterator I=Ex->child_begin(), E=Ex->child_end();I!=E;++I) if (Expr* ExI = dyn_cast_or_null(*I)) { Expr* E2 = FindExpr(ExI); if (E2) return E2; } - + return Ex; } - + bool MatchesCriteria(Expr* Ex) { return St->getSVal(Ex).isUndef(); } }; - + public: UndefBranch(GRExprEngine *eng) - : BuiltinBug(eng,"Use of uninitialized value", - "Branch condition evaluates to an uninitialized value.") {} - + : BuiltinBug(eng,"Use of garbage value", + "Branch condition evaluates to an undefined or garbage value") + {} + void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { for (GRExprEngine::undef_branch_iterator I=Eng.undef_branches_begin(), E=Eng.undef_branches_end(); I!=E; ++I) { @@ -455,7 +492,7 @@ public: // Note: any predecessor will do. They should have identical state, // since all the BlockEdge did was act as an error sink since the value // had to already be undefined. - ExplodedNode *N = *(*I)->pred_begin(); + ExplodedNode *N = *(*I)->pred_begin(); ProgramPoint P = N->getLocation(); const GRState* St = (*I)->getState(); @@ -471,9 +508,9 @@ public: BR.EmitReport(R); } } - + void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, + const ExplodedNode* N, BuiltinBugReport *R) { registerTrackNullOrUndefValue(BRC, static_cast(R)->getArg(), N); @@ -490,12 +527,12 @@ public: Emit(BR, Eng.explicit_oob_memacc_begin(), Eng.explicit_oob_memacc_end()); } }; - + class VISIBILITY_HIDDEN BadSizeVLA : public BuiltinBug { public: BadSizeVLA(GRExprEngine* eng) : BuiltinBug(eng, "Bad variable-length array (VLA) size") {} - + void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { for (GRExprEngine::ErrorNodes::iterator I = Eng.ExplicitBadSizedVLA.begin(), @@ -503,27 +540,27 @@ public: // Determine whether this was a 'zero-sized' VLA or a VLA with an // undefined size. - GRExprEngine::NodeTy* N = *I; - PostStmt PS = cast(N->getLocation()); - DeclStmt *DS = cast(PS.getStmt()); + ExplodedNode* N = *I; + PostStmt PS = cast(N->getLocation()); + const DeclStmt *DS = cast(PS.getStmt()); VarDecl* VD = cast(*DS->decl_begin()); QualType T = Eng.getContext().getCanonicalType(VD->getType()); VariableArrayType* VT = cast(T); Expr* SizeExpr = VT->getSizeExpr(); - + std::string buf; llvm::raw_string_ostream os(buf); os << "The expression used to specify the number of elements in the " "variable-length array (VLA) '" << VD->getNameAsString() << "' evaluates to "; - + bool isUndefined = N->getState()->getSVal(SizeExpr).isUndef(); - + if (isUndefined) os << "an undefined or garbage value."; else os << "0. VLAs with no elements have undefined behavior."; - + std::string shortBuf; llvm::raw_string_ostream os_short(shortBuf); os_short << "Variable-length array '" << VD->getNameAsString() << "' " @@ -537,9 +574,9 @@ public: BR.EmitReport(report); } } - + void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, + const ExplodedNode* N, BuiltinBugReport *R) { registerTrackNullOrUndefValue(BRC, static_cast(R)->getArg(), N); @@ -549,370 +586,217 @@ public: //===----------------------------------------------------------------------===// // __attribute__(nonnull) checking -class VISIBILITY_HIDDEN CheckAttrNonNull : public GRSimpleAPICheck { +class VISIBILITY_HIDDEN CheckAttrNonNull : + public CheckerVisitor { + BugType *BT; - BugReporter &BR; - + public: - CheckAttrNonNull(BugReporter &br) : BT(0), BR(br) {} + CheckAttrNonNull() : BT(0) {} + ~CheckAttrNonNull() {} - virtual bool Audit(ExplodedNode* N, GRStateManager& VMgr) { - CallExpr* CE = cast(cast(N->getLocation()).getStmt()); - const GRState* state = N->getState(); - + const void *getTag() { + static int x = 0; + return &x; + } + + void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { + const GRState *state = C.getState(); + const GRState *originalState = state; + + // Check if the callee has a 'nonnull' attribute. SVal X = state->getSVal(CE->getCallee()); const FunctionDecl* FD = X.getAsFunctionDecl(); if (!FD) - return false; + return; const NonNullAttr* Att = FD->getAttr(); - if (!Att) - return false; - + return; + // Iterate through the arguments of CE and check them for null. unsigned idx = 0; - bool hasError = false; - - for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E; + + for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E; ++I, ++idx) { - - if (!VMgr.isEqual(state, *I, 0) || !Att->isNonNull(idx)) + + if (!Att->isNonNull(idx)) continue; - // Lazily allocate the BugType object if it hasn't already been created. - // Ownership is transferred to the BugReporter object once the BugReport - // is passed to 'EmitWarning'. - if (!BT) BT = - new BugType("Argument with 'nonnull' attribute passed null", "API"); - - RangedBugReport *R = new RangedBugReport(*BT, - "Null pointer passed as an argument to a " - "'nonnull' parameter", N); + const SVal &V = state->getSVal(*I); + const DefinedSVal *DV = dyn_cast(&V); - R->addRange((*I)->getSourceRange()); - BR.EmitReport(R); - hasError = true; + if (!DV) + continue; + + ConstraintManager &CM = C.getConstraintManager(); + const GRState *stateNotNull, *stateNull; + llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV); + + if (stateNull && !stateNotNull) { + // Generate an error node. Check for a null node in case + // we cache out. + if (ExplodedNode *errorNode = C.GenerateNode(CE, stateNull, true)) { + + // Lazily allocate the BugType object if it hasn't already been + // created. Ownership is transferred to the BugReporter object once + // the BugReport is passed to 'EmitWarning'. + if (!BT) + BT = new BugType("Argument with 'nonnull' attribute passed null", + "API"); + + EnhancedBugReport *R = + new EnhancedBugReport(*BT, + "Null pointer passed as an argument to a " + "'nonnull' parameter", errorNode); + + // Highlight the range of the argument that was null. + const Expr *arg = *I; + R->addRange(arg->getSourceRange()); + R->addVisitorCreator(registerTrackNullOrUndefValue, arg); + + // Emit the bug report. + C.EmitReport(R); + } + + // Always return. Either we cached out or we just emitted an error. + return; + } + + // If a pointer value passed the check we should assume that it is + // indeed not null from this point forward. + assert(stateNotNull); + state = stateNotNull; } - - return hasError; + + // If we reach here all of the arguments passed the nonnull check. + // If 'state' has been updated generated a new node. + if (state != originalState) + C.addTransition(C.GenerateNode(CE, state)); } }; } // end anonymous namespace -//===----------------------------------------------------------------------===// -// Definitions for bug reporter visitors. -//===----------------------------------------------------------------------===// +// Undefined arguments checking. +namespace { +class VISIBILITY_HIDDEN CheckUndefinedArg + : public CheckerVisitor { -static const Stmt *GetDerefExpr(const ExplodedNode *N) { - // Pattern match for a few useful cases (do something smarter later): - // a[0], p->f, *p - const Stmt *S = N->getLocationAs()->getStmt(); + BadArg *BT; - if (const UnaryOperator *U = dyn_cast(S)) { - if (U->getOpcode() == UnaryOperator::Deref) - return U->getSubExpr()->IgnoreParenCasts(); - } - else if (const MemberExpr *ME = dyn_cast(S)) { - return ME->getBase()->IgnoreParenCasts(); +public: + CheckUndefinedArg() : BT(0) {} + ~CheckUndefinedArg() {} + + const void *getTag() { + static int x = 0; + return &x; } - else if (const ArraySubscriptExpr *AE = dyn_cast(S)) { - // Retrieve the base for arrays since BasicStoreManager doesn't know how - // to reason about them. - return AE->getBase(); + + void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); +}; + +void CheckUndefinedArg::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE){ + for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); + I != E; ++I) { + if (C.getState()->getSVal(*I).isUndef()) { + if (ExplodedNode *ErrorNode = C.GenerateNode(CE, true)) { + if (!BT) + BT = new BadArg(); + // Generate a report for this bug. + ArgReport *Report = new ArgReport(*BT, BT->getDescription().c_str(), + ErrorNode, *I); + Report->addRange((*I)->getSourceRange()); + C.EmitReport(Report); + } + } } - - return NULL; } -static const Stmt *GetReceiverExpr(const ExplodedNode *N) { - const Stmt *S = N->getLocationAs()->getStmt(); - if (const ObjCMessageExpr *ME = dyn_cast(S)) - return ME->getReceiver(); - return NULL; -} - -static const Stmt *GetDenomExpr(const ExplodedNode *N) { - const Stmt *S = N->getLocationAs()->getStmt(); - if (const BinaryOperator *BE = dyn_cast(S)) - return BE->getRHS(); - return NULL; -} - -static const Stmt *GetCalleeExpr(const ExplodedNode *N) { - const Stmt *S = N->getLocationAs()->getStmt(); - if (const CallExpr *CE = dyn_cast(S)) - return CE->getCallee(); - return NULL; -} - -static const Stmt *GetRetValExpr(const ExplodedNode *N) { - const Stmt *S = N->getLocationAs()->getStmt(); - if (const ReturnStmt *RS = dyn_cast(S)) - return RS->getRetValue(); - return NULL; -} +class VISIBILITY_HIDDEN CheckBadCall : public CheckerVisitor { + BadCall *BT; -namespace { -class VISIBILITY_HIDDEN FindLastStoreBRVisitor : public BugReporterVisitor { - const MemRegion *R; - SVal V; - bool satisfied; - const ExplodedNode *StoreSite; public: - FindLastStoreBRVisitor(SVal v, const MemRegion *r) - : R(r), V(v), satisfied(false), StoreSite(0) {} - - PathDiagnosticPiece* VisitNode(const ExplodedNode *N, - const ExplodedNode *PrevN, - BugReporterContext& BRC) { - - if (satisfied) - return NULL; - - if (!StoreSite) { - const ExplodedNode *Node = N, *Last = NULL; - - for ( ; Node ; Last = Node, Node = Node->getFirstPred()) { - - if (const VarRegion *VR = dyn_cast(R)) { - if (const PostStmt *P = Node->getLocationAs()) - if (const DeclStmt *DS = P->getStmtAs()) - if (DS->getSingleDecl() == VR->getDecl()) { - Last = Node; - break; - } - } - - if (Node->getState()->getSVal(R) != V) - break; - } + CheckBadCall() : BT(0) {} + ~CheckBadCall() {} - if (!Node || !Last) { - satisfied = true; - return NULL; - } - - StoreSite = Last; - } - - if (StoreSite != N) - return NULL; + const void *getTag() { + static int x = 0; + return &x; + } - satisfied = true; - std::string sbuf; - llvm::raw_string_ostream os(sbuf); - - if (const PostStmt *PS = N->getLocationAs()) { - if (const DeclStmt *DS = PS->getStmtAs()) { - - if (const VarRegion *VR = dyn_cast(R)) { - os << "Variable '" << VR->getDecl()->getNameAsString() << "' "; - } - else - return NULL; - - if (isa(V)) { - bool b = false; - ASTContext &C = BRC.getASTContext(); - if (R->isBoundable()) { - if (const TypedRegion *TR = dyn_cast(R)) { - if (C.isObjCObjectPointerType(TR->getValueType(C))) { - os << "initialized to nil"; - b = true; - } - } - } - - if (!b) - os << "initialized to a null pointer value"; - } - else if (isa(V)) { - os << "initialized to " << cast(V).getValue(); - } - else if (V.isUndef()) { - if (isa(R)) { - const VarDecl *VD = cast(DS->getSingleDecl()); - if (VD->getInit()) - os << "initialized to a garbage value"; - else - os << "declared without an initial value"; - } - } - } - } + void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); +}; - if (os.str().empty()) { - if (isa(V)) { - bool b = false; - ASTContext &C = BRC.getASTContext(); - if (R->isBoundable()) { - if (const TypedRegion *TR = dyn_cast(R)) { - if (C.isObjCObjectPointerType(TR->getValueType(C))) { - os << "nil object reference stored to "; - b = true; - } - } - } +void CheckBadCall::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { + const Expr *Callee = CE->getCallee()->IgnoreParens(); + SVal L = C.getState()->getSVal(Callee); - if (!b) - os << "Null pointer value stored to "; - } - else if (V.isUndef()) { - os << "Uninitialized value stored to "; - } - else - return NULL; - - if (const VarRegion *VR = dyn_cast(R)) { - os << '\'' << VR->getDecl()->getNameAsString() << '\''; - } - else - return NULL; + if (L.isUndef() || isa(L)) { + if (ExplodedNode *N = C.GenerateNode(CE, true)) { + if (!BT) + BT = new BadCall(); + C.EmitReport(new BuiltinBugReport(*BT, BT->getDescription().c_str(), N)); } - - // FIXME: Refactor this into BugReporterContext. - Stmt *S = 0; - ProgramPoint P = N->getLocation(); - - if (BlockEdge *BE = dyn_cast(&P)) { - CFGBlock *BSrc = BE->getSrc(); - S = BSrc->getTerminatorCondition(); - } - else if (PostStmt *PS = dyn_cast(&P)) { - S = PS->getStmt(); - } - - if (!S) - return NULL; - - // Construct a new PathDiagnosticPiece. - PathDiagnosticLocation L(S, BRC.getSourceManager()); - return new PathDiagnosticEventPiece(L, os.str()); } -}; - - -static void registerFindLastStore(BugReporterContext& BRC, const MemRegion *R, - SVal V) { - BRC.addVisitor(new FindLastStoreBRVisitor(V, R)); } -class VISIBILITY_HIDDEN TrackConstraintBRVisitor : public BugReporterVisitor { - SVal Constraint; - const bool Assumption; - bool isSatisfied; +class VISIBILITY_HIDDEN CheckBadDiv : public CheckerVisitor { + DivZero *BT; public: - TrackConstraintBRVisitor(SVal constraint, bool assumption) - : Constraint(constraint), Assumption(assumption), isSatisfied(false) {} - - PathDiagnosticPiece* VisitNode(const ExplodedNode *N, - const ExplodedNode *PrevN, - BugReporterContext& BRC) { - if (isSatisfied) - return NULL; - - // Check if in the previous state it was feasible for this constraint - // to *not* be true. - if (PrevN->getState()->assume(Constraint, !Assumption)) { + CheckBadDiv() : BT(0) {} + ~CheckBadDiv() {} - isSatisfied = true; - - // As a sanity check, make sure that the negation of the constraint - // was infeasible in the current state. If it is feasible, we somehow - // missed the transition point. - if (N->getState()->assume(Constraint, !Assumption)) - return NULL; - - // We found the transition point for the constraint. We now need to - // pretty-print the constraint. (work-in-progress) - std::string sbuf; - llvm::raw_string_ostream os(sbuf); - - if (isa(Constraint)) { - os << "Assuming pointer value is "; - os << (Assumption ? "non-null" : "null"); - } - - if (os.str().empty()) - return NULL; - - // FIXME: Refactor this into BugReporterContext. - Stmt *S = 0; - ProgramPoint P = N->getLocation(); - - if (BlockEdge *BE = dyn_cast(&P)) { - CFGBlock *BSrc = BE->getSrc(); - S = BSrc->getTerminatorCondition(); - } - else if (PostStmt *PS = dyn_cast(&P)) { - S = PS->getStmt(); - } - - if (!S) - return NULL; - - // Construct a new PathDiagnosticPiece. - PathDiagnosticLocation L(S, BRC.getSourceManager()); - return new PathDiagnosticEventPiece(L, os.str()); - } - - return NULL; - } + const void *getTag() { + static int x; + return &x; + } + + void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); }; -} // end anonymous namespace -static void registerTrackConstraint(BugReporterContext& BRC, SVal Constraint, - bool Assumption) { - BRC.addVisitor(new TrackConstraintBRVisitor(Constraint, Assumption)); -} +void CheckBadDiv::PreVisitBinaryOperator(CheckerContext &C, + const BinaryOperator *B) { + BinaryOperator::Opcode Op = B->getOpcode(); + if (Op != BinaryOperator::Div && + Op != BinaryOperator::Rem && + Op != BinaryOperator::DivAssign && + Op != BinaryOperator::RemAssign) + return; -static void registerTrackNullOrUndefValue(BugReporterContext& BRC, - const Stmt *S, - const ExplodedNode* N) { - - if (!S) + if (!B->getRHS()->getType()->isIntegerType() || + !B->getRHS()->getType()->isScalarType()) return; - GRStateManager &StateMgr = BRC.getStateManager(); - const GRState *state = N->getState(); - - if (const DeclRefExpr *DR = dyn_cast(S)) { - if (const VarDecl *VD = dyn_cast(DR->getDecl())) { - const VarRegion *R = - StateMgr.getRegionManager().getVarRegion(VD); - - // What did we load? - SVal V = state->getSVal(S); - - if (isa(V) || isa(V) - || V.isUndef()) { - registerFindLastStore(BRC, R, V); - } - } - } - - SVal V = state->getSValAsScalarOrLoc(S); - - // Uncomment this to find cases where we aren't properly getting the - // base value that was dereferenced. - // assert(!V.isUnknownOrUndef()); - - // Is it a symbolic value? - if (loc::MemRegionVal *L = dyn_cast(&V)) { - const SubRegion *R = cast(L->getRegion()); - while (R && !isa(R)) { - R = dyn_cast(R->getSuperRegion()); - } - - if (R) { - assert(isa(R)); - registerTrackConstraint(BRC, loc::MemRegionVal(R), false); + SVal Denom = C.getState()->getSVal(B->getRHS()); + const DefinedSVal *DV = dyn_cast(&Denom); + + // Divide-by-undefined handled in the generic checking for uses of + // undefined values. + if (!DV) + return; + + // Check for divide by zero. + ConstraintManager &CM = C.getConstraintManager(); + const GRState *stateNotZero, *stateZero; + llvm::tie(stateNotZero, stateZero) = CM.AssumeDual(C.getState(), *DV); + + if (stateZero && !stateNotZero) { + if (ExplodedNode *N = C.GenerateNode(B, stateZero, true)) { + if (!BT) + BT = new DivZero(); + + C.EmitReport(new BuiltinBugReport(*BT, BT->getDescription().c_str(), N)); } + return; } -} + // If we get here, then the denom should not be zero. + if (stateNotZero != C.getState()) + C.addTransition(C.GenerateNode(B, stateNotZero)); +} +} //===----------------------------------------------------------------------===// // Check registration. //===----------------------------------------------------------------------===// @@ -926,23 +810,23 @@ void GRExprEngine::RegisterInternalChecks() { BR.Register(new NullDeref(this)); BR.Register(new UndefinedDeref(this)); BR.Register(new UndefBranch(this)); - BR.Register(new DivZero(this)); BR.Register(new UndefResult(this)); - BR.Register(new BadCall(this)); BR.Register(new RetStack(this)); BR.Register(new RetUndef(this)); - BR.Register(new BadArg(this)); BR.Register(new BadMsgExprArg(this)); BR.Register(new BadReceiver(this)); BR.Register(new OutOfBoundMemoryAccess(this)); BR.Register(new BadSizeVLA(this)); BR.Register(new NilReceiverStructRet(this)); BR.Register(new NilReceiverLargerThanVoidPtrRet(this)); - + // The following checks do not need to have their associated BugTypes // 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. - AddCheck(new CheckAttrNonNull(BR), Stmt::CallExprClass); + registerCheck(new CheckAttrNonNull()); + registerCheck(new CheckUndefinedArg()); + registerCheck(new CheckBadCall()); + registerCheck(new CheckBadDiv()); } diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp index 54c0afbff33e..f269824d5477 100644 --- a/lib/Analysis/GRState.cpp +++ b/lib/Analysis/GRState.cpp @@ -27,7 +27,7 @@ GRStateManager::~GRStateManager() { for (std::vector::iterator I=Printers.begin(), E=Printers.end(); I!=E; ++I) delete *I; - + for (GDMContextsTy::iterator I=GDMContexts.begin(), E=GDMContexts.end(); I!=E; ++I) I->second.second(I->second.first); @@ -46,12 +46,11 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc, llvm::SmallVector RegionRoots; GRState NewState = *state; - NewState.Env = EnvMgr.RemoveDeadBindings(NewState.Env, Loc, SymReaper, *this, + NewState.Env = EnvMgr.RemoveDeadBindings(NewState.Env, Loc, SymReaper, state, RegionRoots); // Clean up the store. - NewState.St = StoreMgr->RemoveDeadBindings(&NewState, Loc, SymReaper, - RegionRoots); + StoreMgr->RemoveDeadBindings(NewState, Loc, SymReaper, RegionRoots); return ConstraintMgr->RemoveDeadBindings(getPersistentState(NewState), SymReaper); @@ -59,14 +58,14 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc, const GRState *GRState::unbindLoc(Loc LV) const { Store OldStore = getStore(); - Store NewStore = Mgr->StoreMgr->Remove(OldStore, LV); - + Store NewStore = getStateManager().StoreMgr->Remove(OldStore, LV); + if (NewStore == OldStore) return this; - + GRState NewSt = *this; NewSt.St = NewStore; - return Mgr->getPersistentState(NewSt); + return getStateManager().getPersistentState(NewSt); } SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const { @@ -77,7 +76,7 @@ SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const { return UnknownVal(); if (const TypedRegion *TR = dyn_cast(R)) { - QualType T = TR->getValueType(Mgr->getContext()); + QualType T = TR->getValueType(getStateManager().getContext()); if (Loc::IsLocType(T) || T->isIntegerType()) return getSVal(R); } @@ -86,55 +85,37 @@ SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const { } -const GRState *GRState::bindExpr(const Stmt* Ex, SVal V, bool isBlkExpr, - bool Invalidate) const { - - Environment NewEnv = Mgr->EnvMgr.BindExpr(Env, Ex, V, isBlkExpr, Invalidate); - +const GRState *GRState::BindExpr(const Stmt* Ex, SVal V, bool Invalidate) const{ + Environment NewEnv = getStateManager().EnvMgr.BindExpr(Env, Ex, V, + Invalidate); if (NewEnv == Env) return this; - + GRState NewSt = *this; NewSt.Env = NewEnv; - return Mgr->getPersistentState(NewSt); -} - -const GRState *GRState::bindExpr(const Stmt* Ex, SVal V, - bool Invalidate) const { - - bool isBlkExpr = false; - - if (Ex == Mgr->CurrentStmt) { - // FIXME: Should this just be an assertion? When would we want to set - // the value of a block-level expression if it wasn't CurrentStmt? - isBlkExpr = Mgr->cfg.isBlkExpr(Ex); - - if (!isBlkExpr) - return this; - } - - return bindExpr(Ex, V, isBlkExpr, Invalidate); + return getStateManager().getPersistentState(NewSt); } -const GRState* GRStateManager::getInitialState() { - GRState StateImpl(this, EnvMgr.getInitialEnvironment(), - StoreMgr->getInitialStore(), - GDMFactory.GetEmptyMap()); +const GRState* GRStateManager::getInitialState(const LocationContext *InitLoc) { + GRState State(this, + EnvMgr.getInitialEnvironment(InitLoc->getAnalysisContext()), + StoreMgr->getInitialStore(InitLoc), + GDMFactory.GetEmptyMap()); - return getPersistentState(StateImpl); + return getPersistentState(State); } const GRState* GRStateManager::getPersistentState(GRState& State) { - + llvm::FoldingSetNodeID ID; - State.Profile(ID); + State.Profile(ID); void* InsertPos; - + if (GRState* I = StateSet.FindNodeOrInsertPos(ID, InsertPos)) return I; - + GRState* I = (GRState*) Alloc.Allocate(); - new (I) GRState(State); + new (I) GRState(State); StateSet.InsertNode(I, InsertPos); return I; } @@ -142,7 +123,7 @@ const GRState* GRStateManager::getPersistentState(GRState& State) { const GRState* GRState::makeWithStore(Store store) const { GRState NewSt = *this; NewSt.St = store; - return Mgr->getPersistentState(NewSt); + return getStateManager().getPersistentState(NewSt); } //===----------------------------------------------------------------------===// @@ -150,51 +131,56 @@ const GRState* GRState::makeWithStore(Store store) const { //===----------------------------------------------------------------------===// void GRState::print(llvm::raw_ostream& Out, const char* nl, - const char* sep) const { + const char* sep) const { // Print the store. - Mgr->getStoreManager().print(getStore(), Out, nl, sep); - + GRStateManager &Mgr = getStateManager(); + Mgr.getStoreManager().print(getStore(), Out, nl, sep); + + CFG &C = *getAnalysisContext().getCFG(); + // Print Subexpression bindings. bool isFirst = true; - - for (seb_iterator I = seb_begin(), E = seb_end(); I != E; ++I) { - + + for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) { + if (C.isBlkExpr(I.getKey())) + continue; + if (isFirst) { Out << nl << nl << "Sub-Expressions:" << nl; isFirst = false; } else { Out << nl; } - + Out << " (" << (void*) I.getKey() << ") "; LangOptions LO; // FIXME. I.getKey()->printPretty(Out, 0, PrintingPolicy(LO)); - Out << " : "; - I.getData().print(Out); + Out << " : " << I.getData(); } - + // Print block-expression bindings. isFirst = true; - - for (beb_iterator I = beb_begin(), E = beb_end(); I != E; ++I) { + + for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) { + if (!C.isBlkExpr(I.getKey())) + continue; if (isFirst) { Out << nl << nl << "Block-level Expressions:" << nl; isFirst = false; } else { Out << nl; } - + Out << " (" << (void*) I.getKey() << ") "; LangOptions LO; // FIXME. I.getKey()->printPretty(Out, 0, PrintingPolicy(LO)); - Out << " : "; - I.getData().print(Out); + Out << " : " << I.getData(); } - - Mgr->getConstraintManager().print(this, Out, nl, sep); - + + Mgr.getConstraintManager().print(this, Out, nl, sep); + // Print checker-specific data. - for (std::vector::iterator I = Mgr->Printers.begin(), - E = Mgr->Printers.end(); I != E; ++I) { + for (std::vector::iterator I = Mgr.Printers.begin(), + E = Mgr.Printers.end(); I != E; ++I) { (*I)->Print(Out, this, nl, sep); } } @@ -219,23 +205,23 @@ void* GRStateManager::FindGDMContext(void* K, void* (*CreateContext)(llvm::BumpPtrAllocator&), void (*DeleteContext)(void*)) { - + std::pair& p = GDMContexts[K]; if (!p.first) { p.first = CreateContext(Alloc); p.second = DeleteContext; } - + return p.first; } const GRState* GRStateManager::addGDM(const GRState* St, void* Key, void* Data){ GRState::GenericDataMap M1 = St->getGDM(); GRState::GenericDataMap M2 = GDMFactory.Add(M1, Key, Data); - + if (M1 == M2) return St; - + GRState NewSt = *St; NewSt.GDM = M2; return getPersistentState(NewSt); @@ -254,14 +240,14 @@ class VISIBILITY_HIDDEN ScanReachableSymbols : public SubRegionMap::Visitor { SymbolVisitor &visitor; llvm::OwningPtr SRM; public: - + ScanReachableSymbols(const GRState *st, SymbolVisitor& v) : state(st), visitor(v) {} - + bool scan(nonloc::CompoundVal val); bool scan(SVal val); bool scan(const MemRegion *R); - + // From SubRegionMap::Visitor. bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) { return scan(SubRegion); @@ -276,44 +262,44 @@ bool ScanReachableSymbols::scan(nonloc::CompoundVal val) { return true; } - + bool ScanReachableSymbols::scan(SVal val) { if (loc::MemRegionVal *X = dyn_cast(&val)) return scan(X->getRegion()); if (SymbolRef Sym = val.getAsSymbol()) return visitor.VisitSymbol(Sym); - + if (nonloc::CompoundVal *X = dyn_cast(&val)) return scan(*X); - + return true; } - + bool ScanReachableSymbols::scan(const MemRegion *R) { if (isa(R) || visited.count(R)) return true; - + visited.insert(R); // If this is a symbolic region, visit the symbol for the region. if (const SymbolicRegion *SR = dyn_cast(R)) if (!visitor.VisitSymbol(SR->getSymbol())) return false; - + // If this is a subregion, also visit the parent regions. if (const SubRegion *SR = dyn_cast(R)) if (!scan(SR->getSuperRegion())) return false; - + // Now look at the binding to this region (if any). if (!scan(state->getSValAsScalarOrLoc(R))) return false; - + // Now look at the subregions. if (!SRM.get()) SRM.reset(state->getStateManager().getStoreManager().getSubRegionMap(state)); - + return SRM->iterSubRegions(R, *this); } @@ -326,24 +312,24 @@ bool GRState::scanReachableSymbols(SVal val, SymbolVisitor& visitor) const { // Queries. //===----------------------------------------------------------------------===// -bool GRStateManager::isEqual(const GRState* state, Expr* Ex, +bool GRStateManager::isEqual(const GRState* state, const Expr* Ex, const llvm::APSInt& Y) { - + SVal V = state->getSVal(Ex); - + if (loc::ConcreteInt* X = dyn_cast(&V)) return X->getValue() == Y; if (nonloc::ConcreteInt* X = dyn_cast(&V)) return X->getValue() == Y; - + if (SymbolRef Sym = V.getAsSymbol()) return ConstraintMgr->isEqual(state, Sym, Y); return false; } - -bool GRStateManager::isEqual(const GRState* state, Expr* Ex, uint64_t x) { + +bool GRStateManager::isEqual(const GRState* state, const Expr* Ex, uint64_t x) { return isEqual(state, Ex, getBasicVals().getValue(x, Ex->getType())); } diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp index aead7f43ad8f..4d96c8f8f401 100644 --- a/lib/Analysis/LiveVariables.cpp +++ b/lib/Analysis/LiveVariables.cpp @@ -15,7 +15,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" -#include "clang/AST/CFG.h" +#include "clang/Analysis/CFG.h" #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" #include "clang/Analysis/FlowSensitive/DataflowSolver.h" #include "llvm/ADT/SmallPtrSet.h" @@ -29,35 +29,35 @@ using namespace clang; //===----------------------------------------------------------------------===// // Useful constants. -//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// static const bool Alive = true; -static const bool Dead = false; +static const bool Dead = false; //===----------------------------------------------------------------------===// // Dataflow initialization logic. -//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN RegisterDecls +class VISIBILITY_HIDDEN RegisterDecls : public CFGRecStmtDeclVisitor { - + LiveVariables::AnalysisDataTy& AD; - + typedef llvm::SmallVector AlwaysLiveTy; AlwaysLiveTy AlwaysLive; - + public: RegisterDecls(LiveVariables::AnalysisDataTy& ad) : AD(ad) {} ~RegisterDecls() { AD.AlwaysLive.resetValues(AD); - + for (AlwaysLiveTy::iterator I = AlwaysLive.begin(), E = AlwaysLive.end(); - I != E; ++ I) - AD.AlwaysLive(*I, AD) = Alive; + I != E; ++ I) + AD.AlwaysLive(*I, AD) = Alive; } void VisitImplicitParamDecl(ImplicitParamDecl* IPD) { @@ -68,12 +68,12 @@ public: void VisitVarDecl(VarDecl* VD) { // Register the VarDecl for tracking. AD.Register(VD); - + // Does the variable have global storage? If so, it is always live. if (VD->hasGlobalStorage()) - AlwaysLive.push_back(VD); + AlwaysLive.push_back(VD); } - + CFG& getCFG() { return AD.getCFG(); } }; } // end anonymous namespace @@ -82,14 +82,14 @@ LiveVariables::LiveVariables(ASTContext& Ctx, CFG& cfg) { // Register all referenced VarDecls. getAnalysisData().setCFG(cfg); getAnalysisData().setContext(Ctx); - + RegisterDecls R(getAnalysisData()); cfg.VisitBlockStmts(R); } //===----------------------------------------------------------------------===// // Transfer functions. -//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// namespace { @@ -101,85 +101,85 @@ public: LiveVariables::ValTy& getVal() { return LiveState; } CFG& getCFG() { return AD.getCFG(); } - + void VisitDeclRefExpr(DeclRefExpr* DR); void VisitBinaryOperator(BinaryOperator* B); void VisitAssign(BinaryOperator* B); void VisitDeclStmt(DeclStmt* DS); void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S); void VisitUnaryOperator(UnaryOperator* U); - void Visit(Stmt *S); - void VisitTerminator(CFGBlock* B); - + void Visit(Stmt *S); + void VisitTerminator(CFGBlock* B); + void SetTopValue(LiveVariables::ValTy& V) { V = AD.AlwaysLive; } - + }; - + void TransferFuncs::Visit(Stmt *S) { - + if (S == getCurrentBlkStmt()) { - + if (AD.Observer) AD.Observer->ObserveStmt(S,AD,LiveState); - + if (getCFG().isBlkExpr(S)) LiveState(S,AD) = Dead; StmtVisitor::Visit(S); } else if (!getCFG().isBlkExpr(S)) { - + if (AD.Observer) AD.Observer->ObserveStmt(S,AD,LiveState); - + StmtVisitor::Visit(S); - + } else { // For block-level expressions, mark that they are live. LiveState(S,AD) = Alive; } } - + void TransferFuncs::VisitTerminator(CFGBlock* B) { - + const Stmt* E = B->getTerminatorCondition(); if (!E) return; - + assert (getCFG().isBlkExpr(E)); LiveState(E, AD) = Alive; } void TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) { - if (VarDecl* V = dyn_cast(DR->getDecl())) + if (VarDecl* V = dyn_cast(DR->getDecl())) LiveState(V,AD) = Alive; } - -void TransferFuncs::VisitBinaryOperator(BinaryOperator* B) { + +void TransferFuncs::VisitBinaryOperator(BinaryOperator* B) { if (B->isAssignmentOp()) VisitAssign(B); else VisitStmt(B); } void TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { - + // This is a block-level expression. Its value is 'dead' before this point. LiveState(S, AD) = Dead; // This represents a 'use' of the collection. Visit(S->getCollection()); - + // This represents a 'kill' for the variable. Stmt* Element = S->getElement(); DeclRefExpr* DR = 0; VarDecl* VD = 0; - + if (DeclStmt* DS = dyn_cast(Element)) VD = cast(DS->getSingleDecl()); else { - Expr* ElemExpr = cast(Element)->IgnoreParens(); + Expr* ElemExpr = cast(Element)->IgnoreParens(); if ((DR = dyn_cast(ElemExpr))) VD = cast(DR->getDecl()); else { @@ -194,10 +194,10 @@ TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { } } - + void TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { Expr *E = U->getSubExpr(); - + switch (U->getOpcode()) { case UnaryOperator::PostInc: case UnaryOperator::PostDec: @@ -206,7 +206,7 @@ void TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { // Walk through the subexpressions, blasting through ParenExprs // until we either find a DeclRefExpr or some non-DeclRefExpr // expression. - if (DeclRefExpr* DR = dyn_cast(E->IgnoreParens())) + if (DeclRefExpr* DR = dyn_cast(E->IgnoreParens())) if (VarDecl* VD = dyn_cast(DR->getDecl())) { // Treat the --/++ operator as a kill. if (AD.Observer) { AD.Observer->ObserverKill(DR); } @@ -215,24 +215,24 @@ void TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { } // Fall-through. - + default: return Visit(E); } } - -void TransferFuncs::VisitAssign(BinaryOperator* B) { + +void TransferFuncs::VisitAssign(BinaryOperator* B) { Expr* LHS = B->getLHS(); // Assigning to a variable? if (DeclRefExpr* DR = dyn_cast(LHS->IgnoreParens())) { - + // Update liveness inforamtion. unsigned bit = AD.getIdx(DR->getDecl()); LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit); - + if (AD.Observer) { AD.Observer->ObserverKill(DR); } - + // Handle things like +=, etc., which also generate "uses" // of a variable. Do this just by visiting the subexpression. if (B->getOpcode() != BinaryOperator::Assign) @@ -240,7 +240,7 @@ void TransferFuncs::VisitAssign(BinaryOperator* B) { } else // Not assigning to a variable. Process LHS as usual. Visit(LHS); - + Visit(B->getRHS()); } @@ -255,44 +255,44 @@ void TransferFuncs::VisitDeclStmt(DeclStmt* DS) { // transfer function for this expression first. if (Expr* Init = VD->getInit()) Visit(Init); - + if (const VariableArrayType* VT = AD.getContext().getAsVariableArrayType(VD->getType())) { StmtIterator I(const_cast(VT)); - StmtIterator E; + StmtIterator E; for (; I != E; ++I) Visit(*I); } - + // Update liveness information by killing the VarDecl. unsigned bit = AD.getIdx(VD); LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit); } } - + } // end anonymous namespace //===----------------------------------------------------------------------===// // Merge operator: if something is live on any successor block, it is live // in the current block (a set union). -//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// namespace { struct Merge { - typedef StmtDeclBitVector_Types::ValTy ValTy; - + typedef StmtDeclBitVector_Types::ValTy ValTy; + void operator()(ValTy& Dst, const ValTy& Src) { Dst.OrDeclBits(Src); Dst.OrBlkExprBits(Src); } }; - + typedef DataflowSolver Solver; } // end anonymous namespace //===----------------------------------------------------------------------===// // External interface to run Liveness analysis. -//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// void LiveVariables::runOnCFG(CFG& cfg) { Solver S(*this); @@ -337,22 +337,22 @@ bool LiveVariables::isLive(const Stmt* Loc, const VarDecl* D) const { void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const { const AnalysisDataTy& AD = getAnalysisData(); - + for (AnalysisDataTy::decl_iterator I = AD.begin_decl(), E = AD.end_decl(); I!=E; ++I) - if (V.getDeclBit(I->second)) { + if (V.getDeclBit(I->second)) { fprintf(stderr, " %s <", I->first->getIdentifier()->getName()); I->first->getLocation().dump(SM); fprintf(stderr, ">\n"); } -} +} void LiveVariables::dumpBlockLiveness(SourceManager& M) const { for (BlockDataMapTy::iterator I = getBlockDataMap().begin(), E = getBlockDataMap().end(); I!=E; ++I) { fprintf(stderr, "\n[ B%d (live variables at block exit) ]\n", I->first->getBlockID()); - + dumpLiveness(I->second,M); } diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp index 45305403585a..353e63240294 100644 --- a/lib/Analysis/MemRegion.cpp +++ b/lib/Analysis/MemRegion.cpp @@ -15,6 +15,8 @@ #include "llvm/Support/raw_ostream.h" #include "clang/Analysis/PathSensitive/MemRegion.h" +#include "clang/Analysis/PathSensitive/ValueManager.h" +#include "clang/Analysis/PathSensitive/AnalysisContext.h" using namespace clang; @@ -37,7 +39,6 @@ bool SubRegion::isSubRegionOf(const MemRegion* R) const { return false; } - MemRegionManager* SubRegion::getMemRegionManager() const { const SubRegion* r = this; do { @@ -54,8 +55,8 @@ void MemSpaceRegion::Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger((unsigned)getKind()); } -void StringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, - const StringLiteral* Str, +void StringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, + const StringLiteral* Str, const MemRegion* superRegion) { ID.AddInteger((unsigned) StringRegionKind); ID.AddPointer(Str); @@ -74,13 +75,6 @@ void AllocaRegion::Profile(llvm::FoldingSetNodeID& ID) const { ProfileRegion(ID, Ex, Cnt, superRegion); } -void TypedViewRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, QualType T, - const MemRegion* superRegion) { - ID.AddInteger((unsigned) TypedViewRegionKind); - ID.Add(T); - ID.AddPointer(superRegion); -} - void CompoundLiteralRegion::Profile(llvm::FoldingSetNodeID& ID) const { CompoundLiteralRegion::ProfileRegion(ID, CL, superRegion); } @@ -104,6 +98,10 @@ void DeclRegion::Profile(llvm::FoldingSetNodeID& ID) const { DeclRegion::ProfileRegion(ID, D, superRegion, getKind()); } +void VarRegion::Profile(llvm::FoldingSetNodeID &ID) const { + VarRegion::ProfileRegion(ID, getDecl(), LC, superRegion); +} + void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym, const MemRegion *sreg) { ID.AddInteger((unsigned) MemRegion::SymbolicRegionKind); @@ -116,7 +114,7 @@ void SymbolicRegion::Profile(llvm::FoldingSetNodeID& ID) const { } void ElementRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, - QualType ElementType, SVal Idx, + QualType ElementType, SVal Idx, const MemRegion* superRegion) { ID.AddInteger(MemRegion::ElementRegionKind); ID.Add(ElementType); @@ -128,90 +126,88 @@ void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const { ElementRegion::ProfileRegion(ID, ElementType, Index, superRegion); } -void CodeTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const void* data, - QualType t, const MemRegion*) { +void CodeTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, + const FunctionDecl *FD, + const MemRegion*) { ID.AddInteger(MemRegion::CodeTextRegionKind); - ID.AddPointer(data); - ID.Add(t); + ID.AddPointer(FD); } void CodeTextRegion::Profile(llvm::FoldingSetNodeID& ID) const { - CodeTextRegion::ProfileRegion(ID, Data, LocationType, superRegion); + CodeTextRegion::ProfileRegion(ID, FD, superRegion); } //===----------------------------------------------------------------------===// // Region pretty-printing. //===----------------------------------------------------------------------===// -void MemRegion::printStdErr() const { - print(llvm::errs()); +void MemRegion::dump() const { + dumpToStream(llvm::errs()); } std::string MemRegion::getString() const { std::string s; llvm::raw_string_ostream os(s); - print(os); + dumpToStream(os); return os.str(); } -void MemRegion::print(llvm::raw_ostream& os) const { +void MemRegion::dumpToStream(llvm::raw_ostream& os) const { os << ""; } -void AllocaRegion::print(llvm::raw_ostream& os) const { +void AllocaRegion::dumpToStream(llvm::raw_ostream& os) const { os << "alloca{" << (void*) Ex << ',' << Cnt << '}'; } -void CodeTextRegion::print(llvm::raw_ostream& os) const { - os << "code{"; - if (isDeclared()) - os << getDecl()->getDeclName().getAsString(); - else - os << '$' << getSymbol(); - - os << '}'; +void CodeTextRegion::dumpToStream(llvm::raw_ostream& os) const { + os << "code{" << getDecl()->getDeclName().getAsString() << '}'; } -void CompoundLiteralRegion::print(llvm::raw_ostream& os) const { +void CompoundLiteralRegion::dumpToStream(llvm::raw_ostream& os) const { // FIXME: More elaborate pretty-printing. os << "{ " << (void*) CL << " }"; } -void ElementRegion::print(llvm::raw_ostream& os) const { - superRegion->print(os); - os << '['; Index.print(os); os << ']'; +void ElementRegion::dumpToStream(llvm::raw_ostream& os) const { + os << "element{" << superRegion << ',' + << Index << ',' << getElementType().getAsString() << '}'; } -void FieldRegion::print(llvm::raw_ostream& os) const { - superRegion->print(os); - os << "->" << getDecl()->getNameAsString(); +void FieldRegion::dumpToStream(llvm::raw_ostream& os) const { + os << superRegion << "->" << getDecl()->getNameAsString(); } -void StringRegion::print(llvm::raw_ostream& os) const { - LangOptions LO; // FIXME. - Str->printPretty(os, 0, PrintingPolicy(LO)); +void ObjCIvarRegion::dumpToStream(llvm::raw_ostream& os) const { + os << "ivar{" << superRegion << ',' << getDecl()->getNameAsString() << '}'; } -void SymbolicRegion::print(llvm::raw_ostream& os) const { - os << "SymRegion-" << sym; +void StringRegion::dumpToStream(llvm::raw_ostream& os) const { + Str->printPretty(os, 0, PrintingPolicy(getContext().getLangOptions())); } -void TypedViewRegion::print(llvm::raw_ostream& os) const { - os << "typed_view{" << LValueType.getAsString() << ','; - getSuperRegion()->print(os); - os << '}'; +void SymbolicRegion::dumpToStream(llvm::raw_ostream& os) const { + os << "SymRegion{" << sym << '}'; } -void VarRegion::print(llvm::raw_ostream& os) const { +void VarRegion::dumpToStream(llvm::raw_ostream& os) const { os << cast(D)->getNameAsString(); } +void RegionRawOffset::dump() const { + dumpToStream(llvm::errs()); +} + +void RegionRawOffset::dumpToStream(llvm::raw_ostream& os) const { + os << "raw_offset{" << getRegion() << ',' << getByteOffset() << '}'; +} + //===----------------------------------------------------------------------===// // MemRegionManager methods. //===----------------------------------------------------------------------===// - -MemSpaceRegion* MemRegionManager::LazyAllocate(MemSpaceRegion*& region) { - if (!region) { + +MemSpaceRegion* MemRegionManager::LazyAllocate(MemSpaceRegion*& region) { + if (!region) { region = (MemSpaceRegion*) A.Allocate(); new (region) MemSpaceRegion(this); } @@ -251,8 +247,16 @@ StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str) { return getRegion(Str); } -VarRegion* MemRegionManager::getVarRegion(const VarDecl* d) { - return getRegion(d); +VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, + const LocationContext *LC) { + + // FIXME: Once we implement scope handling, we will need to properly lookup + // 'D' to the proper LocationContext. For now, just strip down to the + // StackFrame. + while (!isa(LC)) + LC = LC->getParent(); + + return getRegion(D, LC); } CompoundLiteralRegion* @@ -262,7 +266,8 @@ MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL) { ElementRegion* MemRegionManager::getElementRegion(QualType elementType, SVal Idx, - const MemRegion* superRegion, ASTContext& Ctx){ + const MemRegion* superRegion, + ASTContext& Ctx){ QualType T = Ctx.getCanonicalType(elementType); @@ -282,13 +287,8 @@ MemRegionManager::getElementRegion(QualType elementType, SVal Idx, return R; } -CodeTextRegion* MemRegionManager::getCodeTextRegion(const FunctionDecl* fd, - QualType t) { - return getRegion(fd, t); -} - -CodeTextRegion* MemRegionManager::getCodeTextRegion(SymbolRef sym, QualType t) { - return getRegion(sym, t); +CodeTextRegion *MemRegionManager::getCodeTextRegion(const FunctionDecl *FD) { + return getRegion(FD); } /// getSymbolicRegion - Retrieve or create a "symbolic" memory region. @@ -298,40 +298,34 @@ SymbolicRegion* MemRegionManager::getSymbolicRegion(SymbolRef sym) { FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl* d, const MemRegion* superRegion) { - return getRegion(d, superRegion); + return getSubRegion(d, superRegion); } ObjCIvarRegion* MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d, const MemRegion* superRegion) { - return getRegion(d, superRegion); + return getSubRegion(d, superRegion); } ObjCObjectRegion* MemRegionManager::getObjCObjectRegion(const ObjCInterfaceDecl* d, const MemRegion* superRegion) { - return getRegion(d, superRegion); -} - -TypedViewRegion* -MemRegionManager::getTypedViewRegion(QualType t, const MemRegion* superRegion) { - return getRegion(t, superRegion); + return getSubRegion(d, superRegion); } AllocaRegion* MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt) { return getRegion(E, cnt); } - const MemSpaceRegion *MemRegion::getMemorySpace() const { const MemRegion *R = this; const SubRegion* SR = dyn_cast(this); - + while (SR) { R = SR->getSuperRegion(); SR = dyn_cast(R); } - + return dyn_cast(R); } @@ -371,7 +365,7 @@ bool MemRegion::hasGlobalsStorage() const { bool MemRegion::hasParametersStorage() const { if (const MemSpaceRegion *MS = getMemorySpace()) return MS == getMemRegionManager()->getStackArgumentsRegion(); - + return false; } @@ -388,12 +382,76 @@ bool MemRegion::hasGlobalsOrParametersStorage() const { // View handling. //===----------------------------------------------------------------------===// -const MemRegion *TypedViewRegion::removeViews() const { - const SubRegion *SR = this; - const MemRegion *R = SR; - while (SR && isa(SR)) { - R = SR->getSuperRegion(); - SR = dyn_cast(R); +const MemRegion *MemRegion::getBaseRegion() const { + const MemRegion *R = this; + while (true) { + if (const ElementRegion *ER = dyn_cast(R)) { + // FIXME: generalize. Essentially we want to strip away ElementRegions + // that were layered on a symbolic region because of casts. We only + // want to strip away ElementRegions, however, where the index is 0. + SVal index = ER->getIndex(); + if (nonloc::ConcreteInt *CI = dyn_cast(&index)) { + if (CI->getValue().getSExtValue() == 0) { + R = ER->getSuperRegion(); + continue; + } + } + } + break; } return R; } + +// FIXME: Merge with the implementation of the same method in Store.cpp +static bool IsCompleteType(ASTContext &Ctx, QualType Ty) { + if (const RecordType *RT = Ty->getAs()) { + const RecordDecl *D = RT->getDecl(); + if (!D->getDefinition(Ctx)) + return false; + } + + return true; +} + +RegionRawOffset ElementRegion::getAsRawOffset() const { + int64_t offset = 0; + const ElementRegion *ER = this; + const MemRegion *superR = NULL; + ASTContext &C = getContext(); + + // FIXME: Handle multi-dimensional arrays. + + while (ER) { + superR = ER->getSuperRegion(); + + // FIXME: generalize to symbolic offsets. + SVal index = ER->getIndex(); + if (nonloc::ConcreteInt *CI = dyn_cast(&index)) { + // Update the offset. + int64_t i = CI->getValue().getSExtValue(); + + if (i != 0) { + QualType elemType = ER->getElementType(); + + // If we are pointing to an incomplete type, go no further. + if (!IsCompleteType(C, elemType)) { + superR = ER; + break; + } + + int64_t size = (int64_t) (C.getTypeSize(elemType) / 8); + offset += (i * size); + } + + // Go to the next ElementRegion (if any). + ER = dyn_cast(superR); + continue; + } + + return NULL; + } + + assert(superR && "super region cannot be NULL"); + return RegionRawOffset(superR, offset); +} + diff --git a/lib/Analysis/PathDiagnostic.cpp b/lib/Analysis/PathDiagnostic.cpp index a608ce0d5884..800496a16142 100644 --- a/lib/Analysis/PathDiagnostic.cpp +++ b/lib/Analysis/PathDiagnostic.cpp @@ -27,7 +27,7 @@ bool PathDiagnosticMacroPiece::containsEvent() const { for (const_iterator I = begin(), E = end(); I!=E; ++I) { if (isa(*I)) return true; - + if (PathDiagnosticMacroPiece *MP = dyn_cast(*I)) if (MP->containsEvent()) return true; @@ -38,14 +38,14 @@ bool PathDiagnosticMacroPiece::containsEvent() const { static size_t GetNumCharsToLastNonPeriod(const char *s) { const char *start = s; - const char *lastNonPeriod = 0; + const char *lastNonPeriod = 0; for ( ; *s != '\0' ; ++s) if (*s != '.') lastNonPeriod = s; - + if (!lastNonPeriod) return 0; - + return (lastNonPeriod - start) + 1; } @@ -84,7 +84,7 @@ void PathDiagnostic::resetPath(bool deletePieces) { if (deletePieces) for (iterator I=begin(), E=end(); I!=E; ++I) delete &*I; - + path.clear(); } @@ -97,7 +97,7 @@ PathDiagnostic::PathDiagnostic(const char* bugtype, const char* desc, Category(category, GetNumCharsToLastNonPeriod(category)) {} PathDiagnostic::PathDiagnostic(const std::string& bugtype, - const std::string& desc, + const std::string& desc, const std::string& category) : Size(0), BugType(bugtype, 0, GetNumCharsToLastNonPeriod(bugtype)), @@ -106,11 +106,11 @@ PathDiagnostic::PathDiagnostic(const std::string& bugtype, void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel, const DiagnosticInfo &Info) { - + // Create a PathDiagnostic with a single piece. - + PathDiagnostic* D = new PathDiagnostic(); - + const char *LevelStr; switch (DiagLevel) { default: @@ -124,18 +124,18 @@ void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel, llvm::SmallString<100> StrC; StrC += LevelStr; Info.FormatDiagnostic(StrC); - + PathDiagnosticPiece *P = new PathDiagnosticEventPiece(Info.getLocation(), std::string(StrC.begin(), StrC.end())); - + for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) P->addRange(Info.getRange(i)); for (unsigned i = 0, e = Info.getNumCodeModificationHints(); i != e; ++i) P->addCodeModificationHint(Info.getCodeModificationHint(i)); D->push_front(P); - HandlePathDiagnostic(D); + HandlePathDiagnostic(D); } //===----------------------------------------------------------------------===// @@ -155,7 +155,7 @@ FullSourceLoc PathDiagnosticLocation::asLocation() const { case DeclK: return FullSourceLoc(D->getLocation(), const_cast(*SM)); } - + return FullSourceLoc(R.getBegin(), const_cast(*SM)); } @@ -178,7 +178,7 @@ PathDiagnosticRange PathDiagnosticLocation::asRange() const { if (DS->isSingleDecl()) { // Should always be the case, but we'll be defensive. return SourceRange(DS->getLocStart(), - DS->getSingleDecl()->getLocation()); + DS->getSingleDecl()->getLocation()); } break; } @@ -197,7 +197,7 @@ PathDiagnosticRange PathDiagnosticLocation::asRange() const { return SourceRange(L, L); } } - + return S->getSourceRange(); } case DeclK: @@ -207,7 +207,7 @@ PathDiagnosticRange PathDiagnosticLocation::asRange() const { // FIXME: We would like to always get the function body, even // when it needs to be de-serialized, but getting the // ASTContext here requires significant changes. - if (Stmt *Body = FD->getBodyIfAvailable()) { + if (Stmt *Body = FD->getBody()) { if (CompoundStmt *CS = dyn_cast(Body)) return CS->getSourceRange(); else @@ -219,7 +219,7 @@ PathDiagnosticRange PathDiagnosticLocation::asRange() const { return PathDiagnosticRange(SourceRange(L, L), true); } } - + return R; } @@ -239,4 +239,66 @@ void PathDiagnosticLocation::flatten() { } } +//===----------------------------------------------------------------------===// +// FoldingSet profiling methods. +//===----------------------------------------------------------------------===// + +void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger((unsigned) K); + switch (K) { + case RangeK: + ID.AddInteger(R.getBegin().getRawEncoding()); + ID.AddInteger(R.getEnd().getRawEncoding()); + break; + case SingleLocK: + ID.AddInteger(R.getBegin().getRawEncoding()); + break; + case StmtK: + ID.Add(S); + break; + case DeclK: + ID.Add(D); + break; + } + return; +} + +void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger((unsigned) getKind()); + ID.AddString(str); + // FIXME: Add profiling support for code hints. + ID.AddInteger((unsigned) getDisplayHint()); + for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) { + ID.AddInteger(I->getBegin().getRawEncoding()); + ID.AddInteger(I->getEnd().getRawEncoding()); + } +} +void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { + PathDiagnosticPiece::Profile(ID); + ID.Add(Pos); +} + +void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { + PathDiagnosticPiece::Profile(ID); + for (const_iterator I = begin(), E = end(); I != E; ++I) + ID.Add(*I); +} + +void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { + PathDiagnosticSpotPiece::Profile(ID); + for (const_iterator I = begin(), E = end(); I != E; ++I) + ID.Add(**I); +} + +void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(Size); + ID.AddString(BugType); + ID.AddString(Desc); + ID.AddString(Category); + for (const_iterator I = begin(), E = end(); I != E; ++I) + ID.Add(*I); + + for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) + ID.AddString(*I); +} diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp index 079462e8d19f..73b445e6ab36 100644 --- a/lib/Analysis/RangeConstraintManager.cpp +++ b/lib/Analysis/RangeConstraintManager.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines RangeConstraintManager, a class that tracks simple +// This file defines RangeConstraintManager, a class that tracks simple // equality and inequality constraints on symbolic values of GRState. // //===----------------------------------------------------------------------===// @@ -66,7 +66,7 @@ public: // consistent (instead of comparing by pointer values) and can potentially // be used to speed up some of the operations in RangeSet. static inline bool isLess(key_type_ref lhs, key_type_ref rhs) { - return *lhs.first < *rhs.first || (!(*rhs.first < *lhs.first) && + return *lhs.first < *rhs.first || (!(*rhs.first < *lhs.first) && *lhs.second < *rhs.second); } }; @@ -78,7 +78,7 @@ class VISIBILITY_HIDDEN RangeSet { typedef llvm::ImmutableSet PrimRangeSet; PrimRangeSet ranges; // no need to make const, since it is an // ImmutableSet - this allows default operator= - // to work. + // to work. public: typedef PrimRangeSet::Factory Factory; typedef PrimRangeSet::iterator iterator; @@ -88,13 +88,13 @@ public: iterator begin() const { return ranges.begin(); } iterator end() const { return ranges.end(); } - + bool isEmpty() const { return ranges.isEmpty(); } - + /// Construct a new RangeSet representing '{ [from, to] }'. RangeSet(Factory &F, const llvm::APSInt &from, const llvm::APSInt &to) : ranges(F.Add(F.GetEmptySet(), Range(from, to))) {} - + /// Profile - Generates a hash profile of this RangeSet for use /// by FoldingSet. void Profile(llvm::FoldingSetNodeID &ID) const { ranges.Profile(ID); } @@ -122,7 +122,7 @@ public: /// value be not be equal to V. RangeSet AddNE(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) { PrimRangeSet newRanges = ranges; - + // FIXME: We can perhaps enhance ImmutableSet to do this search for us // in log(N) time using the sorted property of the internal AVL tree. for (iterator i = begin(), e = end(); i != e; ++i) { @@ -134,11 +134,11 @@ public: newRanges = F.Add(newRanges, Range(i->From(), BV.Sub1(V))); if (V != i->To()) newRanges = F.Add(newRanges, Range(BV.Add1(V), i->To())); - // All of the ranges are non-overlapping, so we can stop. + // All of the ranges are non-overlapping, so we can stop. break; } } - + return newRanges; } @@ -153,7 +153,7 @@ public: else if (i->To() < V) newRanges = F.Add(newRanges, *i); } - + return newRanges; } @@ -168,7 +168,7 @@ public: else if (i->To() <= V) newRanges = F.Add(newRanges, *i); } - + return newRanges; } @@ -181,7 +181,7 @@ public: else if (i->From() > V) newRanges = F.Add(newRanges, *i); } - + return newRanges; } @@ -208,13 +208,13 @@ public: isFirst = false; else os << ", "; - + os << '[' << i->From().toString(10) << ", " << i->To().toString(10) << ']'; } - os << " }"; + os << " }"; } - + bool operator==(const RangeSet &other) const { return ranges == other.ranges; } @@ -227,13 +227,13 @@ namespace clang { template<> struct GRStateTrait : public GRStatePartialTrait { - static inline void* GDMIndex() { return &ConstraintRangeIndex; } + static inline void* GDMIndex() { return &ConstraintRangeIndex; } }; -} - +} + namespace { class VISIBILITY_HIDDEN RangeConstraintManager : public SimpleConstraintManager{ - RangeSet GetRange(const GRState *state, SymbolRef sym); + RangeSet GetRange(const GRState *state, SymbolRef sym); public: RangeConstraintManager() {} @@ -256,7 +256,7 @@ public: const llvm::APSInt& V); const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) const; - + // FIXME: Refactor into SimpleConstraintManager? bool isEqual(const GRState* St, SymbolRef sym, const llvm::APSInt& V) const { const llvm::APSInt *i = getSymVal(St, sym); @@ -265,7 +265,7 @@ public: const GRState* RemoveDeadBindings(const GRState* St, SymbolReaper& SymReaper); - void print(const GRState* St, llvm::raw_ostream& Out, + void print(const GRState* St, llvm::raw_ostream& Out, const char* nl, const char *sep); private: @@ -294,11 +294,11 @@ RangeConstraintManager::RemoveDeadBindings(const GRState* state, ConstraintRangeTy::Factory& CRFactory = state->get_context(); for (ConstraintRangeTy::iterator I = CR.begin(), E = CR.end(); I != E; ++I) { - SymbolRef sym = I.getKey(); + SymbolRef sym = I.getKey(); if (SymReaper.maybeDead(sym)) CR = CRFactory.Remove(CR, sym); } - + return state->set(CR); } @@ -310,11 +310,11 @@ RangeSet RangeConstraintManager::GetRange(const GRState *state, SymbolRef sym) { if (ConstraintRangeTy::data_type* V = state->get(sym)) return *V; - + // Lazily generate a new RangeSet representing all possible values for the // given symbol type. QualType T = state->getSymbolManager().getType(sym); - BasicValueFactory& BV = state->getBasicVals(); + BasicValueFactory& BV = state->getBasicVals(); return RangeSet(F, BV.getMinValue(T), BV.getMaxValue(T)); } @@ -341,16 +341,16 @@ AssumeX(GE) // Pretty-printing. //===------------------------------------------------------------------------===/ -void RangeConstraintManager::print(const GRState* St, llvm::raw_ostream& Out, +void RangeConstraintManager::print(const GRState* St, llvm::raw_ostream& Out, const char* nl, const char *sep) { - + ConstraintRangeTy Ranges = St->get(); - + if (Ranges.isEmpty()) return; - + Out << nl << sep << "ranges of symbol values:"; - + for (ConstraintRangeTy::iterator I=Ranges.begin(), E=Ranges.end(); I!=E; ++I){ Out << nl << ' ' << I.getKey() << " : "; I.getData().print(Out); diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index 23e8b738b601..3844d6a6149c 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -15,9 +15,11 @@ // //===----------------------------------------------------------------------===// #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/Analysis/Analyses/LiveVariables.h" +#include "clang/Analysis/Support/Optional.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/ImmutableMap.h" @@ -27,8 +29,57 @@ using namespace clang; +#define HEAP_UNDEFINED 0 +#define USE_EXPLICIT_COMPOUND 0 + +namespace { +class BindingVal { +public: + enum BindingKind { Direct, Default }; +private: + SVal Value; + BindingKind Kind; + +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; } + + void Profile(llvm::FoldingSetNodeID& ID) const { + Value.Profile(ID); + ID.AddInteger(Kind); + } + + 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 + // Actual Store type. -typedef llvm::ImmutableMap RegionBindingsTy; +typedef llvm::ImmutableMap RegionBindings; //===----------------------------------------------------------------------===// // Fine-grained control of RegionStoreManager. @@ -36,56 +87,26 @@ typedef llvm::ImmutableMap RegionBindingsTy; namespace { struct VISIBILITY_HIDDEN minimal_features_tag {}; -struct VISIBILITY_HIDDEN maximal_features_tag {}; - +struct VISIBILITY_HIDDEN maximal_features_tag {}; + class VISIBILITY_HIDDEN RegionStoreFeatures { bool SupportsFields; bool SupportsRemaining; - + public: RegionStoreFeatures(minimal_features_tag) : SupportsFields(false), SupportsRemaining(false) {} - + RegionStoreFeatures(maximal_features_tag) : SupportsFields(true), SupportsRemaining(false) {} - + void enableFields(bool t) { SupportsFields = t; } - + bool supportsFields() const { return SupportsFields; } bool supportsRemaining() const { return SupportsRemaining; } }; } -//===----------------------------------------------------------------------===// -// Region "Views" -//===----------------------------------------------------------------------===// -// -// MemRegions can be layered on top of each other. This GDM entry tracks -// what are the MemRegions that layer a given MemRegion. -// -typedef llvm::ImmutableSet RegionViews; -namespace { class VISIBILITY_HIDDEN RegionViewMap {}; } -static int RegionViewMapIndex = 0; -namespace clang { - template<> struct GRStateTrait - : public GRStatePartialTrait > { - - static void* GDMIndex() { return &RegionViewMapIndex; } - }; -} - -// RegionCasts records the current cast type of a region. -namespace { class VISIBILITY_HIDDEN RegionCasts {}; } -static int RegionCastsIndex = 0; -namespace clang { - template<> struct GRStateTrait - : public GRStatePartialTrait > { - static void* GDMIndex() { return &RegionCastsIndex; } - }; -} - //===----------------------------------------------------------------------===// // Region "Extents" //===----------------------------------------------------------------------===// @@ -103,19 +124,15 @@ namespace clang { } //===----------------------------------------------------------------------===// -// Regions with default values. +// Utility functions. //===----------------------------------------------------------------------===// -// -// This GDM entry tracks what regions have a default value if they have no bound -// value and have not been killed. -// -namespace { class VISIBILITY_HIDDEN RegionDefaultValue {}; } -static int RegionDefaultValueIndex = 0; -namespace clang { - template<> struct GRStateTrait - : public GRStatePartialTrait > { - static void* GDMIndex() { return &RegionDefaultValueIndex; } - }; + +static bool IsAnyPointerOrIntptr(QualType ty, ASTContext &Ctx) { + if (ty->isAnyPointerType()) + return true; + + return ty->isIntegerType() && ty->isScalarType() && + Ctx.getTypeSize(ty) == Ctx.getTypeSize(Ctx.VoidPtrTy); } //===----------------------------------------------------------------------===// @@ -125,87 +142,104 @@ namespace clang { namespace { class VISIBILITY_HIDDEN RegionStoreSubRegionMap : public SubRegionMap { - typedef llvm::DenseMap > Map; - - llvm::ImmutableSet::Factory F; + typedef llvm::ImmutableSet SetTy; + typedef llvm::DenseMap Map; + SetTy::Factory F; Map M; - public: - void add(const MemRegion* Parent, const MemRegion* SubRegion) { + bool add(const MemRegion* Parent, const MemRegion* SubRegion) { Map::iterator I = M.find(Parent); - M.insert(std::make_pair(Parent, - F.Add(I == M.end() ? F.GetEmptySet() : I->second, SubRegion))); + + if (I == M.end()) { + M.insert(std::make_pair(Parent, F.Add(F.GetEmptySet(), SubRegion))); + return true; + } + + I->second = F.Add(I->second, SubRegion); + return false; } - + + void process(llvm::SmallVectorImpl &WL, const SubRegion *R); + ~RegionStoreSubRegionMap() {} - + bool iterSubRegions(const MemRegion* Parent, Visitor& V) const { Map::iterator I = M.find(Parent); if (I == M.end()) return true; - + llvm::ImmutableSet S = I->second; for (llvm::ImmutableSet::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 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 VISIBILITY_HIDDEN RegionStoreManager : public StoreManager { const RegionStoreFeatures Features; - RegionBindingsTy::Factory RBFactory; - RegionViews::Factory RVFactory; - - const MemRegion* SelfRegion; - const ImplicitParamDecl *SelfDecl; + RegionBindings::Factory RBFactory; + + typedef llvm::DenseMap SMCache; + SMCache SC; public: - RegionStoreManager(GRStateManager& mgr, const RegionStoreFeatures &f) + RegionStoreManager(GRStateManager& mgr, const RegionStoreFeatures &f) : StoreManager(mgr), Features(f), - RBFactory(mgr.getAllocator()), - RVFactory(mgr.getAllocator()), - SelfRegion(0), SelfDecl(0) { - if (const ObjCMethodDecl* MD = - dyn_cast(&StateMgr.getCodeDecl())) - SelfDecl = MD->getSelfDecl(); + RBFactory(mgr.getAllocator()) {} + + virtual ~RegionStoreManager() { + for (SMCache::iterator I = SC.begin(), E = SC.end(); I != E; ++I) + delete (*I).second; } - virtual ~RegionStoreManager() {} + SubRegionMap *getSubRegionMap(const GRState *state); + + RegionStoreSubRegionMap *getRegionStoreSubRegionMap(Store store); + + Optional getBinding(RegionBindings B, const MemRegion *R); + Optional getDirectBinding(RegionBindings B, const MemRegion *R); + /// getDefaultBinding - Returns an SVal* representing an optional default + /// binding associated with a region and its subregions. + Optional getDefaultBinding(RegionBindings B, const MemRegion *R); - SubRegionMap* getSubRegionMap(const GRState *state); - /// 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 GRState *state, const StringLiteral* S); + 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 GRState *state, const CompoundLiteralExpr*); + 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 GRState *state, const VarDecl* VD); - - SVal getLValueIvar(const GRState *state, const ObjCIvarDecl* D, SVal Base); + SVal getLValueVar(const VarDecl *VD, const LocationContext *LC); - SVal getLValueField(const GRState *state, SVal Base, const FieldDecl* D); - - SVal getLValueFieldOrIvar(const GRState *state, SVal Base, const Decl* D); + SVal getLValueIvar(const ObjCIvarDecl* D, SVal Base); - SVal getLValueElement(const GRState *state, QualType elementType, - SVal Base, SVal Offset); + SVal getLValueField(const FieldDecl* D, SVal Base); + + SVal getLValueFieldOrIvar(const Decl* D, SVal Base); + + SVal getLValueElement(QualType elementType, SVal Offset, SVal Base); /// ArrayToPointer - Emulates the "decay" of an array to a pointer @@ -216,61 +250,52 @@ public: /// casts from arrays to pointers. SVal ArrayToPointer(Loc Array); - CastResult CastRegion(const GRState *state, const MemRegion* R, - QualType CastToTy); - SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op,Loc L, NonLoc R, QualType resultTy); - Store getInitialStore() { return RBFactory.GetEmptyMap().getRoot(); } - - /// getSelfRegion - Returns the region for the 'self' (Objective-C) or - /// 'this' object (C++). When used when analyzing a normal function this - /// method returns NULL. - const MemRegion* getSelfRegion(Store) { - if (!SelfDecl) - return 0; - - if (!SelfRegion) { - const ObjCMethodDecl *MD = cast(&StateMgr.getCodeDecl()); - SelfRegion = MRMgr.getObjCObjectRegion(MD->getClassInterface(), - MRMgr.getHeapRegion()); - } - - return SelfRegion; + Store getInitialStore(const LocationContext *InitLoc) { + return RBFactory.GetEmptyMap().getRoot(); } - + //===-------------------------------------------------------------------===// // Binding values to regions. //===-------------------------------------------------------------------===// + const GRState *InvalidateRegion(const GRState *state, const MemRegion *R, + const Expr *E, unsigned Count); + +private: + void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R, + RegionStoreSubRegionMap &M); + +public: const GRState *Bind(const GRState *state, Loc LV, SVal V); const GRState *BindCompoundLiteral(const GRState *state, - const CompoundLiteralExpr* CL, SVal V); - - const GRState *BindDecl(const GRState *state, const VarDecl* VD, SVal InitVal); + const CompoundLiteralExpr* CL, SVal V); - const GRState *BindDeclWithNoInit(const GRState *state, const VarDecl* VD) { + const GRState *BindDecl(const GRState *ST, const VarDecl *VD, + const LocationContext *LC, SVal InitVal); + + const GRState *BindDeclWithNoInit(const GRState *state, const VarDecl*, + const LocationContext *) { return state; } /// BindStruct - Bind a compound value to a structure. const GRState *BindStruct(const GRState *, const TypedRegion* R, SVal V); - + const GRState *BindArray(const GRState *state, const TypedRegion* R, SVal V); - - /// KillStruct - Set the entire struct to unknown. - const GRState *KillStruct(const GRState *state, const TypedRegion* R); - const GRState *setDefaultValue(const GRState *state, const MemRegion* R, SVal V); + /// KillStruct - Set the entire struct to unknown. + Store KillStruct(Store store, const TypedRegion* R); Store Remove(Store store, Loc LV); //===------------------------------------------------------------------===// // Loading values from regions. //===------------------------------------------------------------------===// - + /// The high level logic for this method is this: /// Retrieve (L) /// if L has binding @@ -282,55 +307,66 @@ public: /// return undefined /// else /// return symbolic - SVal Retrieve(const GRState *state, Loc L, QualType T = QualType()); + SValuator::CastResult Retrieve(const GRState *state, Loc L, + QualType T = QualType()); + + SVal RetrieveElement(const GRState *state, const ElementRegion *R); + + SVal RetrieveField(const GRState *state, const FieldRegion *R); - SVal RetrieveElement(const GRState* state, const ElementRegion* R); + SVal RetrieveObjCIvar(const GRState *state, const ObjCIvarRegion *R); - SVal RetrieveField(const GRState* state, const FieldRegion* R); + SVal RetrieveVar(const GRState *state, const VarRegion *R); + + SVal RetrieveLazySymbol(const GRState *state, const TypedRegion *R); + + SVal RetrieveFieldOrElementCommon(const GRState *state, const TypedRegion *R, + QualType Ty, const MemRegion *superR); /// Retrieve the values in a struct and return a CompoundVal, used when doing - /// struct copy: - /// struct s x, y; + /// struct copy: + /// struct s x, y; /// x = y; /// y's value is retrieved by this method. SVal RetrieveStruct(const GRState *St, const TypedRegion* R); - + SVal RetrieveArray(const GRState *St, const TypedRegion* R); + std::pair + GetLazyBinding(RegionBindings B, const MemRegion *R); + + const GRState* CopyLazyBindings(nonloc::LazyCompoundVal V, + const GRState *state, + const TypedRegion *R); + + const ElementRegion *GetElementZeroRegion(const SymbolicRegion *SR, + QualType T); + //===------------------------------------------------------------------===// // State pruning. //===------------------------------------------------------------------===// - + /// RemoveDeadBindings - Scans the RegionStore of 'state' for dead values. /// It returns a new Store with these values removed. - Store RemoveDeadBindings(const GRState *state, Stmt* Loc, SymbolReaper& SymReaper, + void RemoveDeadBindings(GRState &state, Stmt* Loc, SymbolReaper& SymReaper, llvm::SmallVectorImpl& RegionRoots); + const GRState *EnterStackFrame(const GRState *state, + const StackFrameContext *frame); + //===------------------------------------------------------------------===// // Region "extents". //===------------------------------------------------------------------===// - + const GRState *setExtent(const GRState *state, const MemRegion* R, SVal Extent); SVal getSizeInElements(const GRState *state, const MemRegion* R); - //===------------------------------------------------------------------===// - // Region "views". - //===------------------------------------------------------------------===// - - const GRState *AddRegionView(const GRState *state, const MemRegion* View, - const MemRegion* Base); - - const GRState *RemoveRegionView(const GRState *state, const MemRegion* View, - const MemRegion* Base); - //===------------------------------------------------------------------===// // Utility methods. //===------------------------------------------------------------------===// - - const GRState *setCastType(const GRState *state, const MemRegion* R, QualType T); - static inline RegionBindingsTy GetRegionBindings(Store store) { - return RegionBindingsTy(static_cast(store)); + static inline RegionBindings GetRegionBindings(Store store) { + return RegionBindings(static_cast(store)); } void print(Store store, llvm::raw_ostream& Out, const char* nl, @@ -344,7 +380,7 @@ public: BasicValueFactory& getBasicVals() { return StateMgr.getBasicVals(); } - + // FIXME: Remove. ASTContext& getContext() { return StateMgr.getContext(); } }; @@ -366,18 +402,155 @@ StoreManager *clang::CreateFieldsOnlyRegionStoreManager(GRStateManager &StMgr) { return new RegionStoreManager(StMgr, F); } -SubRegionMap* RegionStoreManager::getSubRegionMap(const GRState *state) { - RegionBindingsTy B = GetRegionBindings(state->getStore()); +void +RegionStoreSubRegionMap::process(llvm::SmallVectorImpl &WL, + const SubRegion *R) { + const MemRegion *superR = R->getSuperRegion(); + if (add(superR, R)) + if (const SubRegion *sr = dyn_cast(superR)) + WL.push_back(sr); +} + +RegionStoreSubRegionMap* +RegionStoreManager::getRegionStoreSubRegionMap(Store store) { + RegionBindings B = GetRegionBindings(store); RegionStoreSubRegionMap *M = new RegionStoreSubRegionMap(); - - for (RegionBindingsTy::iterator I=B.begin(), E=B.end(); I!=E; ++I) { - if (const SubRegion* R = dyn_cast(I.getKey())) - M->add(R->getSuperRegion(), R); + + llvm::SmallVector WL; + + for (RegionBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) + if (const SubRegion *R = dyn_cast(I.getKey())) + M->process(WL, R); + + // We also need to record in the subregion map "intermediate" regions that + // don't have direct bindings but are super regions of those that do. + while (!WL.empty()) { + const SubRegion *R = WL.back(); + WL.pop_back(); + M->process(WL, R); } - + return M; } +SubRegionMap *RegionStoreManager::getSubRegionMap(const GRState *state) { + return getRegionStoreSubRegionMap(state->getStore()); +} + +//===----------------------------------------------------------------------===// +// Binding invalidation. +//===----------------------------------------------------------------------===// + +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); + + B = RBFactory.Remove(B, R); +} + +const GRState *RegionStoreManager::InvalidateRegion(const GRState *state, + const MemRegion *R, + const Expr *Ex, + unsigned Count) { + ASTContext& Ctx = StateMgr.getContext(); + + // Strip away casts. + R = R->getBaseRegion(); + + // Get the mapping of regions -> subregions. + llvm::OwningPtr + SubRegions(getRegionStoreSubRegionMap(state->getStore())); + + RegionBindings B = GetRegionBindings(state->getStore()); + + llvm::DenseMap Visited; + llvm::SmallVector WorkList; + WorkList.push_back(R); + + while (!WorkList.empty()) { + R = WorkList.back(); + WorkList.pop_back(); + + // Have we visited this region before? + unsigned &visited = Visited[R]; + if (visited) + continue; + visited = 1; + + // 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); + + // Get the old binding. Is it a region? If so, add it to the worklist. + if (Optional V = getDirectBinding(B, R)) { + if (const MemRegion *RV = V->getAsRegion()) + WorkList.push_back(RV); + } + + // Handle region. + if (isa(R) || isa(R) || + isa(R)) { + // 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, + Count); + B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default)); + continue; + } + + if (!R->isBoundable()) + continue; + + const TypedRegion *TR = cast(R); + QualType T = TR->getValueType(Ctx); + + if (const RecordType *RT = T->getAsStructureType()) { + const RecordDecl *RD = RT->getDecl()->getDefinition(Ctx); + + // No record definition. There is nothing we can do. + if (!RD) + 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, + Count); + B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default)); + 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 = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default)); + continue; + } + + if ((isa(R)||isa(R)||isa(R)) + && Visited[cast(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 = RBFactory.Remove(B, R); + continue; + } + + // Invalidate the binding. + DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, T, Count); + assert(SymbolManager::canSymbolicate(T) || V.isUnknown()); + B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)); + } + + // Create a new state with the updated bindings. + return state->makeWithStore(B.getRoot()); +} + //===----------------------------------------------------------------------===// // getLValueXXX methods. //===----------------------------------------------------------------------===// @@ -386,40 +559,36 @@ SubRegionMap* RegionStoreManager::getSubRegionMap(const GRState *state) { /// 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 GRState *St, - const StringLiteral* S) { +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 GRState *St, const VarDecl* VD) { - return loc::MemRegionVal(MRMgr.getVarRegion(VD)); +SVal RegionStoreManager::getLValueVar(const VarDecl *VD, + const LocationContext *LC) { + return loc::MemRegionVal(MRMgr.getVarRegion(VD, LC)); } /// 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 -RegionStoreManager::getLValueCompoundLiteral(const GRState *St, - const CompoundLiteralExpr* CL) { +SVal +RegionStoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL) { return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL)); } -SVal RegionStoreManager::getLValueIvar(const GRState *St, const ObjCIvarDecl* D, - SVal Base) { - return getLValueFieldOrIvar(St, Base, D); +SVal RegionStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) { + return getLValueFieldOrIvar(D, Base); } -SVal RegionStoreManager::getLValueField(const GRState *St, SVal Base, - const FieldDecl* D) { - return getLValueFieldOrIvar(St, Base, D); +SVal RegionStoreManager::getLValueField(const FieldDecl* D, SVal Base) { + return getLValueFieldOrIvar(D, Base); } -SVal RegionStoreManager::getLValueFieldOrIvar(const GRState *St, SVal Base, - const Decl* D) { +SVal RegionStoreManager::getLValueFieldOrIvar(const Decl* D, SVal Base) { if (Base.isUnknownOrUndef()) return Base; @@ -446,7 +615,7 @@ SVal RegionStoreManager::getLValueFieldOrIvar(const GRState *St, SVal Base, 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(D)) @@ -455,9 +624,8 @@ SVal RegionStoreManager::getLValueFieldOrIvar(const GRState *St, SVal Base, return loc::MemRegionVal(MRMgr.getFieldRegion(cast(D), BaseR)); } -SVal RegionStoreManager::getLValueElement(const GRState *St, - QualType elementType, - SVal Base, SVal Offset) { +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 @@ -474,7 +642,10 @@ SVal RegionStoreManager::getLValueElement(const GRState *St, // Pointer of any type can be cast and used as array base. const ElementRegion *ElemR = dyn_cast(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. @@ -485,54 +656,26 @@ SVal RegionStoreManager::getLValueElement(const GRState *St, // // Observe that 'p' binds to an AllocaRegion. // - - // Offset might be unsigned. We have to convert it to signed ConcreteInt. - if (nonloc::ConcreteInt* CI = dyn_cast(&Offset)) { - const llvm::APSInt& OffI = CI->getValue(); - if (OffI.isUnsigned()) { - llvm::APSInt Tmp = OffI; - Tmp.setIsSigned(true); - Offset = ValMgr.makeIntVal(Tmp); - } - } return loc::MemRegionVal(MRMgr.getElementRegion(elementType, Offset, BaseRegion, getContext())); } - + SVal BaseIdx = ElemR->getIndex(); - + if (!isa(BaseIdx)) return UnknownVal(); - + const llvm::APSInt& BaseIdxI = cast(BaseIdx).getValue(); const llvm::APSInt& OffI = cast(Offset).getValue(); assert(BaseIdxI.isSigned()); - - // FIXME: This appears to be the assumption of this code. We should review - // whether or not BaseIdxI.getBitWidth() < OffI.getBitWidth(). If it - // can't we need to put a comment here. If it can, we should handle it. - assert(BaseIdxI.getBitWidth() >= OffI.getBitWidth()); - const MemRegion *ArrayR = ElemR->getSuperRegion(); - SVal NewIdx; - - if (OffI.isUnsigned() || OffI.getBitWidth() < BaseIdxI.getBitWidth()) { - // 'Offset' might be unsigned. We have to convert it to signed and - // possibly extend it. - llvm::APSInt Tmp = OffI; - - if (OffI.getBitWidth() < BaseIdxI.getBitWidth()) - Tmp.extend(BaseIdxI.getBitWidth()); - - Tmp.setIsSigned(true); - Tmp += BaseIdxI; // Compute the new offset. - NewIdx = ValMgr.makeIntVal(Tmp); - } - else - NewIdx = nonloc::ConcreteInt(getBasicVals().getValue(BaseIdxI + OffI)); + // 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())); + getContext())); } //===----------------------------------------------------------------------===// @@ -540,64 +683,62 @@ SVal RegionStoreManager::getLValueElement(const GRState *St, //===----------------------------------------------------------------------===// SVal RegionStoreManager::getSizeInElements(const GRState *state, - const MemRegion* R) { - if (const VarRegion* VR = dyn_cast(R)) { - // Get the type of the variable. - QualType T = VR->getDesugaredValueType(getContext()); + const MemRegion *R) { - // FIXME: Handle variable-length arrays. - if (isa(T)) + switch (R->getKind()) { + case MemRegion::MemSpaceRegionKind: + assert(0 && "Cannot index into a MemSpace"); return UnknownVal(); - - if (const ConstantArrayType* CAT = dyn_cast(T)) { - // return the size as signed integer. - return ValMgr.makeIntVal(CAT->getSize(), false); - } - const QualType* CastTy = state->get(VR); - - // If the VarRegion is cast to other type, compute the size with respect to - // that type. - if (CastTy) { - QualType EleTy =cast(CastTy->getTypePtr())->getPointeeType(); - QualType VarTy = VR->getValueType(getContext()); - uint64_t EleSize = getContext().getTypeSize(EleTy); - uint64_t VarSize = getContext().getTypeSize(VarTy); - assert(VarSize != 0); - return ValMgr.makeIntVal(VarSize/EleSize, false); - } + case MemRegion::CodeTextRegionKind: + // Technically this can happen if people do funny things with casts. + return UnknownVal(); - // Clients can use ordinary variables as if they were arrays. These - // essentially are arrays of size 1. - return ValMgr.makeIntVal(1, false); - } + // Not yet handled. + case MemRegion::AllocaRegionKind: + case MemRegion::CompoundLiteralRegionKind: + case MemRegion::ElementRegionKind: + case MemRegion::FieldRegionKind: + case MemRegion::ObjCIvarRegionKind: + case MemRegion::ObjCObjectRegionKind: + case MemRegion::SymbolicRegionKind: + return UnknownVal(); - if (const StringRegion* SR = dyn_cast(R)) { - const StringLiteral* Str = SR->getStringLiteral(); - // We intentionally made the size value signed because it participates in - // operations with signed indices. - return ValMgr.makeIntVal(Str->getByteLength()+1, false); - } + case MemRegion::StringRegionKind: { + const StringLiteral* Str = cast(R)->getStringLiteral(); + // We intentionally made the size value signed because it participates in + // operations with signed indices. + return ValMgr.makeIntVal(Str->getByteLength()+1, false); + } - if (const FieldRegion* FR = dyn_cast(R)) { - // FIXME: Unsupported yet. - FR = 0; - return UnknownVal(); - } + case MemRegion::VarRegionKind: { + const VarRegion* VR = cast(R); + // Get the type of the variable. + QualType T = VR->getDesugaredValueType(getContext()); - if (isa(R)) { - return UnknownVal(); - } + // FIXME: Handle variable-length arrays. + if (isa(T)) + return UnknownVal(); - if (isa(R)) { - return UnknownVal(); - } + if (const ConstantArrayType* CAT = dyn_cast(T)) { + // return the size as signed integer. + return ValMgr.makeIntVal(CAT->getSize(), false); + } - if (isa(R)) { - return UnknownVal(); + // Clients can use ordinary variables as if they were arrays. These + // essentially are arrays of size 1. + return ValMgr.makeIntVal(1, false); + } + + case MemRegion::BEG_DECL_REGIONS: + case MemRegion::END_DECL_REGIONS: + case MemRegion::BEG_TYPED_REGIONS: + case MemRegion::END_TYPED_REGIONS: + assert(0 && "Infeasible region"); + return UnknownVal(); } - assert(0 && "Other regions are not supported yet."); + assert(0 && "Unreachable"); return UnknownVal(); } @@ -620,105 +761,29 @@ const GRState *RegionStoreManager::setExtent(const GRState *state, SVal RegionStoreManager::ArrayToPointer(Loc Array) { if (!isa(Array)) return UnknownVal(); - + const MemRegion* R = cast(&Array)->getRegion(); const TypedRegion* ArrayR = dyn_cast(R); - + if (!ArrayR) return UnknownVal(); - + // Strip off typedefs from the ArrayRegion's ValueType. - QualType T = ArrayR->getValueType(getContext())->getDesugaredType(); + QualType T = ArrayR->getValueType(getContext()).getDesugaredType(); ArrayType *AT = cast(T); T = AT->getElementType(); - - nonloc::ConcreteInt Idx(getBasicVals().getZeroWithPtrWidth(false)); - ElementRegion* ER = MRMgr.getElementRegion(T, Idx, ArrayR, getContext()); - - return loc::MemRegionVal(ER); -} - -RegionStoreManager::CastResult -RegionStoreManager::CastRegion(const GRState *state, const MemRegion* R, - QualType CastToTy) { - - ASTContext& Ctx = StateMgr.getContext(); - - // We need to know the real type of CastToTy. - QualType ToTy = Ctx.getCanonicalType(CastToTy); - - // Check cast to ObjCQualifiedID type. - if (ToTy->isObjCQualifiedIdType()) { - // FIXME: Record the type information aside. - return CastResult(state, R); - } - - // CodeTextRegion should be cast to only function pointer type. - if (isa(R)) { - assert(CastToTy->isFunctionPointerType() || CastToTy->isBlockPointerType() - || (CastToTy->isPointerType() - && CastToTy->getAsPointerType()->getPointeeType()->isVoidType())); - return CastResult(state, R); - } - - // Now assume we are casting from pointer to pointer. Other cases should - // already be handled. - QualType PointeeTy = cast(ToTy.getTypePtr())->getPointeeType(); - - // Process region cast according to the kind of the region being cast. - - // FIXME: Need to handle arbitrary downcasts. - if (isa(R) || isa(R)) { - state = setCastType(state, R, ToTy); - return CastResult(state, R); - } - - // VarRegion, ElementRegion, and FieldRegion has an inherent type. Normally - // they should not be cast. We only layer an ElementRegion when the cast-to - // pointee type is of smaller size. In other cases, we return the original - // VarRegion. - if (isa(R) || isa(R) || isa(R) - || isa(R) || isa(R)) { - // If the pointee type is incomplete, do not compute its size, and return - // the original region. - if (const RecordType *RT = dyn_cast(PointeeTy.getTypePtr())) { - const RecordDecl *D = RT->getDecl(); - if (!D->getDefinition(getContext())) - return CastResult(state, R); - } - - QualType ObjTy = cast(R)->getValueType(getContext()); - uint64_t PointeeTySize = getContext().getTypeSize(PointeeTy); - uint64_t ObjTySize = getContext().getTypeSize(ObjTy); - - if ((PointeeTySize > 0 && PointeeTySize < ObjTySize) || - (ObjTy->isAggregateType() && PointeeTy->isScalarType()) || - ObjTySize == 0 /* R has 'void*' type. */) { - // Record the cast type of the region. - state = setCastType(state, R, ToTy); - - SVal Idx = ValMgr.makeZeroArrayIndex(); - ElementRegion* ER = MRMgr.getElementRegion(PointeeTy, Idx,R,getContext()); - return CastResult(state, ER); - } else { - state = setCastType(state, R, ToTy); - return CastResult(state, R); - } - } - if (isa(R)) { - return CastResult(state, R); - } + SVal ZeroIdx = ValMgr.makeZeroArrayIndex(); + ElementRegion* ER = MRMgr.getElementRegion(T, ZeroIdx, ArrayR, getContext()); - assert(0 && "Unprocessed region."); - return 0; + return loc::MemRegionVal(ER); } //===----------------------------------------------------------------------===// // Pointer arithmetic. //===----------------------------------------------------------------------===// -SVal RegionStoreManager::EvalBinOp(const GRState *state, +SVal RegionStoreManager::EvalBinOp(const GRState *state, BinaryOperator::Opcode Op, Loc L, NonLoc R, QualType resultTy) { // Assume the base location is MemRegionVal. @@ -728,64 +793,89 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state, const MemRegion* MR = cast(L).getRegion(); const ElementRegion *ER = 0; - // If the operand is a symbolic or alloca region, create the first element - // region on it. - if (const SymbolicRegion *SR = dyn_cast(MR)) { - QualType T; - // If the SymbolicRegion was cast to another type, use that type. - if (const QualType *t = state->get(SR)) { - T = *t; - } else { - // Otherwise use the symbol's type. + switch (MR->getKind()) { + case MemRegion::SymbolicRegionKind: { + const SymbolicRegion *SR = cast(MR); SymbolRef Sym = SR->getSymbol(); - T = Sym->getType(getContext()); + QualType T = Sym->getType(getContext()); + QualType EleTy; + + if (const PointerType *PT = T->getAs()) + EleTy = PT->getPointeeType(); + else + EleTy = T->getAs()->getPointeeType(); + + SVal ZeroIdx = ValMgr.makeZeroArrayIndex(); + ER = MRMgr.getElementRegion(EleTy, ZeroIdx, SR, getContext()); + break; + } + case MemRegion::AllocaRegionKind: { + const AllocaRegion *AR = cast(MR); + QualType T = getContext().CharTy; // Create an ElementRegion of bytes. + QualType EleTy = T->getAs()->getPointeeType(); + SVal ZeroIdx = ValMgr.makeZeroArrayIndex(); + ER = MRMgr.getElementRegion(EleTy, ZeroIdx, AR, getContext()); + break; } - QualType EleTy = T->getAsPointerType()->getPointeeType(); - SVal ZeroIdx = ValMgr.makeZeroArrayIndex(); - ER = MRMgr.getElementRegion(EleTy, ZeroIdx, SR, getContext()); - } - else if (const AllocaRegion *AR = dyn_cast(MR)) { - // Get the alloca region's current cast type. + case MemRegion::ElementRegionKind: { + ER = cast(MR); + break; + } + // Not yet handled. + case MemRegion::VarRegionKind: + case MemRegion::StringRegionKind: { + + } + // Fall-through. + case MemRegion::CompoundLiteralRegionKind: + case MemRegion::FieldRegionKind: + case MemRegion::ObjCObjectRegionKind: + case MemRegion::ObjCIvarRegionKind: + return UnknownVal(); - GRStateTrait::lookup_type T = state->get(AR); - assert(T && "alloca region has no type."); - QualType EleTy = cast(T->getTypePtr())->getPointeeType(); - SVal ZeroIdx = ValMgr.makeZeroArrayIndex(); - ER = MRMgr.getElementRegion(EleTy, ZeroIdx, AR, getContext()); - } - else if (isa(MR)) { - // Not track pointer arithmetic on struct fields. - return UnknownVal(); - } - else { - ER = cast(MR); - } + case MemRegion::CodeTextRegionKind: + // Technically this can happen if people do funny things with casts. + return UnknownVal(); - SVal Idx = ER->getIndex(); + case MemRegion::MemSpaceRegionKind: + assert(0 && "Cannot perform pointer arithmetic on a MemSpace"); + return UnknownVal(); + case MemRegion::BEG_DECL_REGIONS: + case MemRegion::END_DECL_REGIONS: + case MemRegion::BEG_TYPED_REGIONS: + case MemRegion::END_TYPED_REGIONS: + assert(0 && "Infeasible region"); + return UnknownVal(); + } + + SVal Idx = ER->getIndex(); nonloc::ConcreteInt* Base = dyn_cast(&Idx); - nonloc::ConcreteInt* Offset = dyn_cast(&R); - - // Only support concrete integer indexes for now. - if (Base && Offset) { - // FIXME: For now, convert the signedness and bitwidth of offset in case - // they don't match. This can result from pointer arithmetic. In reality, - // we should figure out what are the proper semantics and implement them. - // - // This addresses the test case test/Analysis/ptr-arith.c - // - nonloc::ConcreteInt OffConverted(getBasicVals().Convert(Base->getValue(), - Offset->getValue())); - SVal NewIdx = Base->evalBinOp(ValMgr, Op, OffConverted); - const MemRegion* NewER = - MRMgr.getElementRegion(ER->getElementType(), NewIdx,ER->getSuperRegion(), - getContext()); - return ValMgr.makeLoc(NewER); + // For now, only support: + // (a) concrete integer indices that can easily be resolved + // (b) 0 + symbolic index + if (Base) { + if (nonloc::ConcreteInt *Offset = dyn_cast(&R)) { + // FIXME: Should use SValuator here. + SVal NewIdx = + Base->evalBinOp(ValMgr, Op, + cast(ValMgr.convertToArrayIndex(*Offset))); + const MemRegion* NewER = + MRMgr.getElementRegion(ER->getElementType(), NewIdx, + ER->getSuperRegion(), getContext()); + return ValMgr.makeLoc(NewER); + } + if (0 == Base->getValue()) { + const MemRegion* NewER = + MRMgr.getElementRegion(ER->getElementType(), R, + ER->getSuperRegion(), getContext()); + return ValMgr.makeLoc(NewER); + } } - + return UnknownVal(); } @@ -793,7 +883,71 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state, // Loading values from regions. //===----------------------------------------------------------------------===// -SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { +Optional RegionStoreManager::getDirectBinding(RegionBindings B, + const MemRegion *R) { + if (const BindingVal *BV = B.lookup(R)) + return Optional::create(BV->getDirectValue()); + + return Optional(); +} + +Optional RegionStoreManager::getDefaultBinding(RegionBindings B, + const MemRegion *R) { + + if (R->isBoundable()) + if (const TypedRegion *TR = dyn_cast(R)) + if (TR->getValueType(getContext())->isUnionType()) + return UnknownVal(); + + if (BindingVal const *V = B.lookup(R)) + return Optional::create(V->getDefaultValue()); + + return Optional(); +} + +Optional RegionStoreManager::getBinding(RegionBindings B, + const MemRegion *R) { + if (const BindingVal *BV = B.lookup(R)) + return Optional::create(BV->getValue()); + + return Optional(); +} + +static bool IsReinterpreted(QualType RTy, QualType UsedTy, ASTContext &Ctx) { + RTy = Ctx.getCanonicalType(RTy); + UsedTy = Ctx.getCanonicalType(UsedTy); + + if (RTy == UsedTy) + return false; + + + // Recursively check the types. We basically want to see if a pointer value + // is ever reinterpreted as a non-pointer, e.g. void** and intptr_t* + // represents a reinterpretation. + if (Loc::IsLocType(RTy) && Loc::IsLocType(UsedTy)) { + const PointerType *PRTy = RTy->getAs(); + const PointerType *PUsedTy = UsedTy->getAs(); + + return PUsedTy && PRTy && + IsReinterpreted(PRTy->getPointeeType(), + PUsedTy->getPointeeType(), Ctx); + } + + return true; +} + +const ElementRegion * +RegionStoreManager::GetElementZeroRegion(const SymbolicRegion *SR, QualType T) { + ASTContext &Ctx = getContext(); + SVal idx = ValMgr.makeZeroArrayIndex(); + assert(!T.isNull()); + return MRMgr.getElementRegion(T, idx, SR, Ctx); +} + + + +SValuator::CastResult +RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { assert(!isa(L) && "location unknown"); assert(!isa(L) && "location undefined"); @@ -801,7 +955,7 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { // FIXME: Is this even possible? Shouldn't this be treated as a null // dereference at a higher level? if (isa(L)) - return UndefinedVal(); + return SValuator::CastResult(state, UndefinedVal()); const MemRegion *MR = cast(L).getRegion(); @@ -811,13 +965,19 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { // char* p = alloca(); // read(p); // c = *p; - if (isa(MR) || isa(MR)) - return UnknownVal(); + if (isa(MR)) + return SValuator::CastResult(state, UnknownVal()); + + if (const SymbolicRegion *SR = dyn_cast(MR)) + MR = GetElementZeroRegion(SR, T); + + if (isa(MR)) + return SValuator::CastResult(state, 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. const TypedRegion *R = cast(MR); - assert(R && "bad region"); + QualType RTy = R->getValueType(getContext()); // FIXME: We should eventually handle funny addressing. e.g.: // @@ -828,197 +988,319 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { // // Such funny addressing will occur due to layering of regions. - QualType RTy = R->getValueType(getContext()); +#if 0 + ASTContext &Ctx = getContext(); + if (!T.isNull() && IsReinterpreted(RTy, T, Ctx)) { + SVal ZeroIdx = ValMgr.makeZeroArrayIndex(); + R = MRMgr.getElementRegion(T, ZeroIdx, R, Ctx); + RTy = T; + assert(Ctx.getCanonicalType(RTy) == + Ctx.getCanonicalType(R->getValueType(Ctx))); + } +#endif if (RTy->isStructureType()) - return RetrieveStruct(state, R); + return SValuator::CastResult(state, RetrieveStruct(state, R)); + + // FIXME: Handle unions. + if (RTy->isUnionType()) + return SValuator::CastResult(state, UnknownVal()); if (RTy->isArrayType()) - return RetrieveArray(state, R); + return SValuator::CastResult(state, RetrieveArray(state, R)); // FIXME: handle Vector types. if (RTy->isVectorType()) - return UnknownVal(); + return SValuator::CastResult(state, UnknownVal()); if (const FieldRegion* FR = dyn_cast(R)) - return RetrieveField(state, FR); + return CastRetrievedVal(RetrieveField(state, FR), state, FR, T); if (const ElementRegion* ER = dyn_cast(R)) - return RetrieveElement(state, ER); - - RegionBindingsTy B = GetRegionBindings(state->getStore()); - RegionBindingsTy::data_type* V = B.lookup(R); + return CastRetrievedVal(RetrieveElement(state, ER), state, ER, T); - // Check if the region has a binding. - if (V) - return *V; + if (const ObjCIvarRegion *IVR = dyn_cast(R)) + return CastRetrievedVal(RetrieveObjCIvar(state, IVR), state, IVR, T); - if (const ObjCIvarRegion *IVR = dyn_cast(R)) { - const MemRegion *SR = IVR->getSuperRegion(); + if (const VarRegion *VR = dyn_cast(R)) + return CastRetrievedVal(RetrieveVar(state, VR), state, VR, T); - // If the super region is 'self' then return the symbol representing - // the value of the ivar upon entry to the method. - if (SR == SelfRegion) { - // FIXME: Do we need to handle the case where the super region - // has a view? We want to canonicalize the bindings. - return ValMgr.getRegionValueSymbolVal(R); - } - - // Otherwise, we need a new symbol. For now return Unknown. - return UnknownVal(); - } + RegionBindings B = GetRegionBindings(state->getStore()); + RegionBindings::data_type* V = B.lookup(R); + + // Check if the region has a binding. + if (V) + if (SVal const *SV = V->getValue()) + return SValuator::CastResult(state, *SV); // 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 // function/method. These are either symbolic values or 'undefined'. - // We treat function parameters as symbolic values. - if (const VarRegion* VR = dyn_cast(R)) { - const VarDecl *VD = VR->getDecl(); - - if (VD == SelfDecl) - return loc::MemRegionVal(getSelfRegion(0)); - - if (VR->hasGlobalsOrParametersStorage()) - return ValMgr.getRegionValueSymbolValOrUnknown(VR, VD->getType()); - } - +#if HEAP_UNDEFINED if (R->hasHeapOrStackStorage()) { +#else + if (R->hasStackStorage()) { +#endif // All stack variables are considered to have undefined values // upon creation. All heap allocated blocks are considered to // have undefined values as well unless they are explicitly bound // to specific values. - return UndefinedVal(); + return SValuator::CastResult(state, UndefinedVal()); + } + + // All other values are symbolic. + return SValuator::CastResult(state, + ValMgr.getRegionValueSymbolValOrUnknown(R, RTy)); +} + +std::pair +RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R) { + if (Optional OV = getDirectBinding(B, R)) + if (const nonloc::LazyCompoundVal *V = + dyn_cast(OV.getPointer())) + return std::make_pair(V->getState(), V->getRegion()); + + if (const ElementRegion *ER = dyn_cast(R)) { + const std::pair &X = + GetLazyBinding(B, ER->getSuperRegion()); + + if (X.first) + return std::make_pair(X.first, + MRMgr.getElementRegionWithSuper(ER, X.second)); } + else if (const FieldRegion *FR = dyn_cast(R)) { + const std::pair &X = + GetLazyBinding(B, FR->getSuperRegion()); - // If the region is already cast to another type, use that type to create the - // symbol value. - if (const QualType *p = state->get(R)) { - QualType T = *p; - RTy = T->getAsPointerType()->getPointeeType(); + if (X.first) + return std::make_pair(X.first, + MRMgr.getFieldRegionWithSuper(FR, X.second)); } - // All other values are symbolic. - return ValMgr.getRegionValueSymbolValOrUnknown(R, RTy); + return std::make_pair((const GRState*) 0, (const MemRegion *) 0); } SVal RegionStoreManager::RetrieveElement(const GRState* state, const ElementRegion* R) { // Check if the region has a binding. - RegionBindingsTy B = GetRegionBindings(state->getStore()); - if (const SVal* V = B.lookup(R)) + RegionBindings B = GetRegionBindings(state->getStore()); + if (Optional V = getDirectBinding(B, R)) return *V; const MemRegion* superR = R->getSuperRegion(); // Check if the region is an element region of a string literal. if (const StringRegion *StrR=dyn_cast(superR)) { + // FIXME: Handle loads from strings where the literal is treated as + // an integer, e.g., *((unsigned int*)"hello") + ASTContext &Ctx = getContext(); + QualType T = StrR->getValueType(Ctx)->getAs()->getElementType(); + if (T != Ctx.getCanonicalType(R->getElementType())) + return UnknownVal(); + const StringLiteral *Str = StrR->getStringLiteral(); SVal Idx = R->getIndex(); if (nonloc::ConcreteInt *CI = dyn_cast(&Idx)) { int64_t i = CI->getValue().getSExtValue(); - char c; - if (i == Str->getByteLength()) - c = '\0'; - else - c = Str->getStrData()[i]; - return ValMgr.makeIntVal(c, getContext().CharTy); + int64_t byteLength = Str->getByteLength(); + if (i > byteLength) { + // Buffer overflow checking in GRExprEngine should handle this case, + // but we shouldn't rely on it to not overflow here if that checking + // is disabled. + return UnknownVal(); + } + char c = (i == byteLength) ? '\0' : Str->getStrData()[i]; + return ValMgr.makeIntVal(c, T); } } - // Check if the super region has a default value. - if (const SVal *D = state->get(superR)) { - if (D->hasConjuredSymbol()) - return ValMgr.getRegionValueSymbolVal(R); - else - return *D; + // 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 + // retrieve from the super region and appropriately "cast" the value. + // This is needed to support OSAtomicCompareAndSwap and friends or other + // loads that treat integers as pointers and vis versa. + if (R->getIndex().isZeroConstant()) { + if (const TypedRegion *superTR = dyn_cast(superR)) { + ASTContext &Ctx = getContext(); + if (IsAnyPointerOrIntptr(superTR->getValueType(Ctx), Ctx)) { + QualType valTy = R->getValueType(Ctx); + if (IsAnyPointerOrIntptr(valTy, Ctx)) { + // Retrieve the value from the super region. This will be casted to + // valTy when we return to 'Retrieve'. + const SValuator::CastResult &cr = Retrieve(state, + loc::MemRegionVal(superR), + valTy); + return cr.getSVal(); + } + } + } } - // Check if the super region has a binding. - if (B.lookup(superR)) { - // We do not extract the bit value from super region for now. + // Check if the immediate super region has a direct binding. + if (Optional V = getDirectBinding(B, superR)) { + if (SymbolRef parentSym = V->getAsSymbol()) + return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R); + + if (V->isUnknownOrUndef()) + return *V; + + // Handle LazyCompoundVals for the immediate super region. Other cases + // are handled in 'RetrieveFieldOrElementCommon'. + if (const nonloc::LazyCompoundVal *LCV = + dyn_cast(V)) { + + R = MRMgr.getElementRegionWithSuper(R, LCV->getRegion()); + return RetrieveElement(LCV->getState(), R); + } + + // Other cases: give up. return UnknownVal(); } - if (R->hasHeapStorage()) { - // FIXME: If the region has heap storage and we know nothing special - // about its bindings, should we instead return UnknownVal? Seems like - // we should only return UndefinedVal in the cases where we know the value - // will be undefined. - return UndefinedVal(); + return RetrieveFieldOrElementCommon(state, R, R->getElementType(), superR); +} + +SVal RegionStoreManager::RetrieveField(const GRState* state, + const FieldRegion* R) { + + // Check if the region has a binding. + RegionBindings B = GetRegionBindings(state->getStore()); + if (Optional V = getDirectBinding(B, R)) + return *V; + + QualType Ty = R->getValueType(getContext()); + return RetrieveFieldOrElementCommon(state, R, Ty, R->getSuperRegion()); +} + +SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state, + const TypedRegion *R, + QualType Ty, + const MemRegion *superR) { + + // At this point we have already checked in either RetrieveElement or + // RetrieveField if 'R' has a direct binding. + + RegionBindings B = GetRegionBindings(state->getStore()); + + while (superR) { + if (const Optional &D = getDefaultBinding(B, superR)) { + if (SymbolRef parentSym = D->getAsSymbol()) + return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R); + + if (D->isZeroConstant()) + return ValMgr.makeZeroVal(Ty); + + if (D->isUnknown()) + return *D; + + assert(0 && "Unknown default value"); + } + + // If our super region is a field or element itself, walk up the region + // hierarchy to see if there is a default value installed in an ancestor. + if (isa(superR) || isa(superR)) { + superR = cast(superR)->getSuperRegion(); + continue; + } + + break; + } + + // Lazy binding? + const GRState *lazyBindingState = NULL; + const MemRegion *lazyBindingRegion = NULL; + llvm::tie(lazyBindingState, lazyBindingRegion) = GetLazyBinding(B, R); + + if (lazyBindingState) { + assert(lazyBindingRegion && "Lazy-binding region not set"); + + if (isa(R)) + return RetrieveElement(lazyBindingState, + cast(lazyBindingRegion)); + + return RetrieveField(lazyBindingState, + cast(lazyBindingRegion)); } if (R->hasStackStorage() && !R->hasParametersStorage()) { - // Currently we don't reason specially about Clang-style vectors. Check - // if superR is a vector and if so return Unknown. - if (const TypedRegion *typedSuperR = dyn_cast(superR)) { - if (typedSuperR->getValueType(getContext())->isVectorType()) - return UnknownVal(); + + if (isa(R)) { + // Currently we don't reason specially about Clang-style vectors. Check + // if superR is a vector and if so return Unknown. + if (const TypedRegion *typedSuperR = dyn_cast(superR)) { + if (typedSuperR->getValueType(getContext())->isVectorType()) + return UnknownVal(); + } } return UndefinedVal(); } - QualType Ty = R->getValueType(getContext()); + // All other values are symbolic. + return ValMgr.getRegionValueSymbolValOrUnknown(R, Ty); +} - // If the region is already cast to another type, use that type to create the - // symbol value. - if (const QualType *p = state->get(R)) - Ty = (*p)->getAsPointerType()->getPointeeType(); +SVal RegionStoreManager::RetrieveObjCIvar(const GRState* state, + const ObjCIvarRegion* R) { - return ValMgr.getRegionValueSymbolValOrUnknown(R, Ty); + // Check if the region has a binding. + RegionBindings B = GetRegionBindings(state->getStore()); + + if (Optional V = getDirectBinding(B, R)) + return *V; + + const MemRegion *superR = R->getSuperRegion(); + + // Check if the super region has a binding. + if (Optional V = getDirectBinding(B, superR)) { + if (SymbolRef parentSym = V->getAsSymbol()) + return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R); + + // Other cases: give up. + return UnknownVal(); + } + + return RetrieveLazySymbol(state, R); } -SVal RegionStoreManager::RetrieveField(const GRState* state, - const FieldRegion* R) { - QualType Ty = R->getValueType(getContext()); +SVal RegionStoreManager::RetrieveVar(const GRState *state, + const VarRegion *R) { // Check if the region has a binding. - RegionBindingsTy B = GetRegionBindings(state->getStore()); - if (const SVal* V = B.lookup(R)) + RegionBindings B = GetRegionBindings(state->getStore()); + + if (Optional V = getDirectBinding(B, R)) return *V; - const MemRegion* superR = R->getSuperRegion(); - if (const SVal* D = state->get(superR)) { - if (D->hasConjuredSymbol()) - return ValMgr.getRegionValueSymbolVal(R); + // Lazily derive a value for the VarRegion. + const VarDecl *VD = R->getDecl(); - if (D->isZeroConstant()) - return ValMgr.makeZeroVal(Ty); + if (R->hasGlobalsOrParametersStorage()) + return ValMgr.getRegionValueSymbolValOrUnknown(R, VD->getType()); - if (D->isUnknown()) - return *D; + return UndefinedVal(); +} - assert(0 && "Unknown default value"); - } +SVal RegionStoreManager::RetrieveLazySymbol(const GRState *state, + const TypedRegion *R) { - // FIXME: Is this correct? Should it be UnknownVal? - if (R->hasHeapStorage()) - return UndefinedVal(); - - if (R->hasStackStorage() && !R->hasParametersStorage()) - return UndefinedVal(); - - // If the region is already cast to another type, use that type to create the - // symbol value. - if (const QualType *p = state->get(R)) { - QualType tmp = *p; - Ty = tmp->getAsPointerType()->getPointeeType(); - } + QualType valTy = R->getValueType(getContext()); // All other values are symbolic. - return ValMgr.getRegionValueSymbolValOrUnknown(R, Ty); + return ValMgr.getRegionValueSymbolValOrUnknown(R, valTy); } -SVal RegionStoreManager::RetrieveStruct(const GRState *state, - const TypedRegion* R){ +SVal RegionStoreManager::RetrieveStruct(const GRState *state, + const TypedRegion* R) { QualType T = R->getValueType(getContext()); assert(T->isStructureType()); const RecordType* RT = T->getAsStructureType(); RecordDecl* RD = RT->getDecl(); assert(RD->isDefinition()); - + (void)RD; +#if USE_EXPLICIT_COMPOUND llvm::ImmutableList StructVal = getBasicVals().getEmptySValList(); // FIXME: We shouldn't use a std::vector. If RecordDecl doesn't have a @@ -1030,33 +1312,38 @@ 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); + SVal FieldValue = Retrieve(state, loc::MemRegionVal(FR), FTy).getSVal(); StructVal = getBasicVals().consVals(FieldValue, StructVal); } return ValMgr.makeCompoundVal(T, StructVal); +#else + return ValMgr.makeLazyCompoundVal(state, R); +#endif } SVal RegionStoreManager::RetrieveArray(const GRState *state, const TypedRegion * R) { - +#if USE_EXPLICIT_COMPOUND QualType T = R->getValueType(getContext()); ConstantArrayType* CAT = cast(T.getTypePtr()); llvm::ImmutableList ArrayVal = getBasicVals().getEmptySValList(); - llvm::APSInt Size(CAT->getSize(), false); - llvm::APSInt i = getBasicVals().getZeroWithPtrWidth(false); - - for (; i < Size; ++i) { - SVal Idx = ValMgr.makeIntVal(i); + uint64_t size = CAT->getSize().getZExtValue(); + for (uint64_t i = 0; i < size; ++i) { + SVal Idx = ValMgr.makeArrayIndex(i); ElementRegion* ER = MRMgr.getElementRegion(CAT->getElementType(), Idx, R, - getContext()); + getContext()); QualType ETy = ER->getElementType(); - SVal ElementVal = Retrieve(state, loc::MemRegionVal(ER), ETy); + SVal ElementVal = Retrieve(state, loc::MemRegionVal(ER), ETy).getSVal(); ArrayVal = getBasicVals().consVals(ElementVal, ArrayVal); } return ValMgr.makeCompoundVal(T, ArrayVal); +#else + assert(isa(R->getValueType(getContext()))); + return ValMgr.makeLazyCompoundVal(state, R); +#endif } //===----------------------------------------------------------------------===// @@ -1065,15 +1352,15 @@ SVal RegionStoreManager::RetrieveArray(const GRState *state, Store RegionStoreManager::Remove(Store store, Loc L) { const MemRegion* R = 0; - + if (isa(L)) R = cast(L).getRegion(); - + if (R) { - RegionBindingsTy B = GetRegionBindings(store); + RegionBindings B = GetRegionBindings(store); return RBFactory.Remove(B, R).getRoot(); } - + return store; } @@ -1082,32 +1369,67 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) { return state; // If we get here, the location should be a region. - const MemRegion* R = cast(L).getRegion(); - + const MemRegion *R = cast(L).getRegion(); + // Check if the region is a struct region. if (const TypedRegion* TR = dyn_cast(R)) if (TR->getValueType(getContext())->isStructureType()) return BindStruct(state, TR, V); - - RegionBindingsTy B = GetRegionBindings(state->getStore()); - - B = RBFactory.Add(B, R, V); - - return state->makeWithStore(B.getRoot()); + + // 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 + // bind to the super region. + // This is needed to support OSAtomicCompareAndSwap and friends or other + // loads that treat integers as pointers and vis versa. + if (const ElementRegion *ER = dyn_cast(R)) { + if (ER->getIndex().isZeroConstant()) { + if (const TypedRegion *superR = + dyn_cast(ER->getSuperRegion())) { + ASTContext &Ctx = getContext(); + QualType superTy = superR->getValueType(Ctx); + QualType erTy = ER->getValueType(Ctx); + + 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()); + } + // 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); + } + } + } + else if (const SymbolicRegion *SR = dyn_cast(R)) { + // Binding directly to a symbolic region should be treated as binding + // to element 0. + QualType T = SR->getSymbol()->getType(getContext()); + T = T->getAs()->getPointeeType(); + R = GetElementZeroRegion(SR, T); + } + + // Perform the binding. + RegionBindings B = GetRegionBindings(state->getStore()); + return state->makeWithStore( + RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot()); } -const GRState *RegionStoreManager::BindDecl(const GRState *state, - const VarDecl* VD, SVal InitVal) { +const GRState *RegionStoreManager::BindDecl(const GRState *ST, + const VarDecl *VD, + const LocationContext *LC, + SVal InitVal) { QualType T = VD->getType(); - VarRegion* VR = MRMgr.getVarRegion(VD); + VarRegion* VR = MRMgr.getVarRegion(VD, LC); if (T->isArrayType()) - return BindArray(state, VR, InitVal); + return BindArray(ST, VR, InitVal); if (T->isStructureType()) - return BindStruct(state, VR, InitVal); + return BindStruct(ST, VR, InitVal); - return Bind(state, ValMgr.makeLoc(VR), InitVal); + return Bind(ST, ValMgr.makeLoc(VR), InitVal); } // FIXME: this method should be merged into Bind(). @@ -1115,21 +1437,20 @@ const GRState * RegionStoreManager::BindCompoundLiteral(const GRState *state, const CompoundLiteralExpr* CL, SVal V) { - + CompoundLiteralRegion* R = MRMgr.getCompoundLiteralRegion(CL); return Bind(state, loc::MemRegionVal(R), V); } const GRState *RegionStoreManager::BindArray(const GRState *state, - const TypedRegion* R, + const TypedRegion* R, SVal Init) { QualType T = R->getValueType(getContext()); ConstantArrayType* CAT = cast(T.getTypePtr()); QualType ElementTy = CAT->getElementType(); - llvm::APSInt Size(CAT->getSize(), false); - llvm::APSInt i(llvm::APInt::getNullValue(Size.getBitWidth()), false); + uint64_t size = CAT->getSize().getZExtValue(); // Check if the init expr is a StringLiteral. if (isa(Init)) { @@ -1142,12 +1463,13 @@ 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. - for (; i < Size; ++i, ++j) { + for (uint64_t i = 0; i < size; ++i, ++j) { if (j >= len) break; - SVal Idx = ValMgr.makeIntVal(i); - ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx,R,getContext()); + SVal Idx = ValMgr.makeArrayIndex(i); + ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R, + getContext()); SVal V = ValMgr.makeIntVal(str[j], sizeof(char)*8, true); state = Bind(state, loc::MemRegionVal(ER), V); @@ -1156,29 +1478,39 @@ const GRState *RegionStoreManager::BindArray(const GRState *state, return state; } + // Handle lazy compound values. + if (nonloc::LazyCompoundVal *LCV = dyn_cast(&Init)) + return CopyLazyBindings(*LCV, state, R); + + // Remaining case: explicit compound values. nonloc::CompoundVal& CV = cast(Init); nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end(); + uint64_t i = 0; - for (; i < Size; ++i, ++VI) { + for (; i < size; ++i, ++VI) { // The init list might be shorter than the array length. if (VI == VE) break; - SVal Idx = ValMgr.makeIntVal(i); + SVal Idx = ValMgr.makeArrayIndex(i); ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext()); if (CAT->getElementType()->isStructureType()) state = BindStruct(state, ER, *VI); else + // FIXME: Do we need special handling of nested arrays? state = Bind(state, ValMgr.makeLoc(ER), *VI); } // If the init list is shorter than the array length, set the array default // value. - if (i < Size) { + if (i < size) { if (ElementTy->isIntegerType()) { SVal V = ValMgr.makeZeroVal(ElementTy); - state = setDefaultValue(state, R, V); + Store store = state->getStore(); + RegionBindings B = GetRegionBindings(store); + B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default)); + state = state->makeWithStore(B.getRoot()); } } @@ -1188,23 +1520,27 @@ const GRState *RegionStoreManager::BindArray(const GRState *state, const GRState * RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R, SVal V) { - + if (!Features.supportsFields()) return state; - + QualType T = R->getValueType(getContext()); assert(T->isStructureType()); - const RecordType* RT = T->getAsRecordType(); + const RecordType* RT = T->getAs(); RecordDecl* RD = RT->getDecl(); if (!RD->isDefinition()) return state; + // Handle lazy compound values. + if (const nonloc::LazyCompoundVal *LCV=dyn_cast(&V)) + return CopyLazyBindings(*LCV, state, R); + // We may get non-CompoundVal accidentally due to imprecise cast logic. // Ignore them and kill the field values. if (V.isUnknown() || !isa(V)) - return KillStruct(state, R); + return state->makeWithStore(KillStruct(state->getStore(), R)); nonloc::CompoundVal& CV = cast(V); nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end(); @@ -1217,253 +1553,286 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R, break; QualType FTy = (*FI)->getType(); - FieldRegion* FR = MRMgr.getFieldRegion(*FI, R); + const FieldRegion* FR = MRMgr.getFieldRegion(*FI, R); - if (Loc::IsLocType(FTy) || FTy->isIntegerType()) - state = Bind(state, ValMgr.makeLoc(FR), *VI); - else if (FTy->isArrayType()) + if (FTy->isArrayType()) state = BindArray(state, FR, *VI); else if (FTy->isStructureType()) state = BindStruct(state, FR, *VI); + else + state = Bind(state, ValMgr.makeLoc(FR), *VI); } // There may be fewer values in the initialize list than the fields of struct. - if (FI != FE) - state = setDefaultValue(state, R, ValMgr.makeIntVal(0, false)); + if (FI != FE) { + Store store = state->getStore(); + RegionBindings B = GetRegionBindings(store); + B = RBFactory.Add(B, R, + BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default)); + state = state->makeWithStore(B.getRoot()); + } return state; } -const GRState *RegionStoreManager::KillStruct(const GRState *state, - const TypedRegion* R){ +Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R) { + RegionBindings B = GetRegionBindings(store); + llvm::OwningPtr + SubRegions(getRegionStoreSubRegionMap(store)); + RemoveSubRegionBindings(B, R, *SubRegions); // Set the default value of the struct region to "unknown". - state = state->set(R, UnknownVal()); - - // Remove all bindings for the subregions of the struct. - Store store = state->getStore(); - RegionBindingsTy B = GetRegionBindings(store); - for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) { - const MemRegion* R = I.getKey(); - if (const SubRegion* subRegion = dyn_cast(R)) - if (subRegion->isSubRegionOf(R)) - store = Remove(store, ValMgr.makeLoc(subRegion)); - } - - return state->makeWithStore(store); -} - -//===----------------------------------------------------------------------===// -// Region views. -//===----------------------------------------------------------------------===// + B = RBFactory.Add(B, R, BindingVal(UnknownVal(), BindingVal::Default)); -const GRState *RegionStoreManager::AddRegionView(const GRState *state, - const MemRegion* View, - const MemRegion* Base) { - - // First, retrieve the region view of the base region. - const RegionViews* d = state->get(Base); - RegionViews L = d ? *d : RVFactory.GetEmptySet(); - - // Now add View to the region view. - L = RVFactory.Add(L, View); - - // Create a new state with the new region view. - return state->set(Base, L); + return B.getRoot(); } -const GRState *RegionStoreManager::RemoveRegionView(const GRState *state, - const MemRegion* View, - const MemRegion* Base) { - // Retrieve the region view of the base region. - const RegionViews* d = state->get(Base); +const GRState* +RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V, + const GRState *state, + const TypedRegion *R) { - // If the base region has no view, return. - if (!d) - return state; + // Nuke the old bindings stemming from R. + RegionBindings B = GetRegionBindings(state->getStore()); - // Remove the view. - return state->set(Base, RVFactory.Remove(*d, View)); -} + llvm::OwningPtr + SubRegions(getRegionStoreSubRegionMap(state->getStore())); -const GRState *RegionStoreManager::setCastType(const GRState *state, - const MemRegion* R, QualType T) { - return state->set(R, T); -} + // B and DVM are updated after the call to RemoveSubRegionBindings. + RemoveSubRegionBindings(B, R, *SubRegions.get()); -const GRState *RegionStoreManager::setDefaultValue(const GRState *state, - const MemRegion* R, SVal V) { - return state->set(R, V); + // Now copy the bindings. This amounts to just binding 'V' to 'R'. This + // results in a zero-copy algorithm. + return state->makeWithStore( + RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot()); } //===----------------------------------------------------------------------===// // State pruning. //===----------------------------------------------------------------------===// -static void UpdateLiveSymbols(SVal X, SymbolReaper& SymReaper) { - if (loc::MemRegionVal *XR = dyn_cast(&X)) { - const MemRegion *R = XR->getRegion(); - - while (R) { - if (const SymbolicRegion *SR = dyn_cast(R)) { - SymReaper.markLive(SR->getSymbol()); - return; - } - - if (const SubRegion *SR = dyn_cast(R)) { - R = SR->getSuperRegion(); - continue; - } - - break; - } - - return; - } +namespace { +class VISIBILITY_HIDDEN RBDNode + : public std::pair { +public: + RBDNode(const GRState *st, const MemRegion *r) + : std::pair(st, r) {} - for (SVal::symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end();SI!=SE;++SI) - SymReaper.markLive(*SI); -} + const GRState *getState() const { return first; } + const MemRegion *getRegion() const { return second; } +}; -Store RegionStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc, - SymbolReaper& SymReaper, - llvm::SmallVectorImpl& RegionRoots) -{ - Store store = state->getStore(); - RegionBindingsTy B = GetRegionBindings(store); - - // Lazily constructed backmap from MemRegions to SubRegions. - typedef llvm::ImmutableSet SubRegionsTy; - typedef llvm::ImmutableMap SubRegionsMapTy; - - // FIXME: As a future optimization we can modifiy BumpPtrAllocator to have - // the ability to reuse memory. This way we can keep TmpAlloc around as - // an instance variable of RegionStoreManager (avoiding repeated malloc - // overhead). - llvm::BumpPtrAllocator TmpAlloc; +enum VisitFlag { NotVisited = 0, VisitedFromSubRegion, VisitedFromSuperRegion }; + +class RBDItem : public RBDNode { +private: + const VisitFlag VF; - // Factory objects. - SubRegionsMapTy::Factory SubRegMapF(TmpAlloc); - SubRegionsTy::Factory SubRegF(TmpAlloc); +public: + RBDItem(const GRState *st, const MemRegion *r, VisitFlag vf) + : RBDNode(st, r), VF(vf) {} + + VisitFlag getVisitFlag() const { return VF; } +}; +} // end anonymous namespace +void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, + SymbolReaper& SymReaper, + llvm::SmallVectorImpl& RegionRoots) +{ + Store store = state.getStore(); + RegionBindings B = GetRegionBindings(store); + // The backmap from regions to subregions. - SubRegionsMapTy SubRegMap = SubRegMapF.GetEmptyMap(); + llvm::OwningPtr + SubRegions(getRegionStoreSubRegionMap(store)); - // Do a pass over the regions in the store. For VarRegions we check if - // the variable is still live and if so add it to the list of live roots. - // For other regions we populate our region backmap. + // Do a pass over the regions in the store. For VarRegions we check if + // the variable is still live and if so add it to the list of live roots. + // For other regions we populate our region backmap. llvm::SmallVector IntermediateRoots; - for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) { - IntermediateRoots.push_back(I.getKey()); + // Scan the direct bindings for "intermediate" roots. + for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { + const MemRegion *R = I.getKey(); + IntermediateRoots.push_back(R); } + // Process the "intermediate" roots to find if they are referenced by + // real roots. + llvm::SmallVector WorkList; + llvm::DenseMap IntermediateVisited; + while (!IntermediateRoots.empty()) { const MemRegion* R = IntermediateRoots.back(); IntermediateRoots.pop_back(); + unsigned &visited = IntermediateVisited[R]; + if (visited) + continue; + visited = 1; + if (const VarRegion* VR = dyn_cast(R)) { - if (SymReaper.isLive(Loc, VR->getDecl())) { - RegionRoots.push_back(VR); // This is a live "root". - } - } - else if (const SymbolicRegion* SR = dyn_cast(R)) { - if (SymReaper.isLive(SR->getSymbol())) - RegionRoots.push_back(SR); + if (SymReaper.isLive(Loc, VR->getDecl())) + WorkList.push_back(RBDItem(&state, VR, VisitedFromSuperRegion)); + continue; } - else { - // Get the super region for R. - const MemRegion* superR = cast(R)->getSuperRegion(); - - // Get the current set of subregions for SuperR. - const SubRegionsTy* SRptr = SubRegMap.lookup(superR); - SubRegionsTy SRs = SRptr ? *SRptr : SubRegF.GetEmptySet(); - - // Add R to the subregions of SuperR. - SubRegMap = SubRegMapF.Add(SubRegMap, superR, SubRegF.Add(SRs, R)); - - // Super region may be VarRegion or subregion of another VarRegion. Add it - // to the work list. - if (isa(superR)) - IntermediateRoots.push_back(superR); + + if (const SymbolicRegion* SR = dyn_cast(R)) { + if (SymReaper.isLive(SR->getSymbol())) + WorkList.push_back(RBDItem(&state, SR, VisitedFromSuperRegion)); + continue; } + + // Add the super region for R to the worklist if it is a subregion. + if (const SubRegion* superR = + dyn_cast(cast(R)->getSuperRegion())) + IntermediateRoots.push_back(superR); + } + + // Enqueue the RegionRoots onto WorkList. + for (llvm::SmallVectorImpl::iterator I=RegionRoots.begin(), + E=RegionRoots.end(); I!=E; ++I) { + WorkList.push_back(RBDItem(&state, *I, VisitedFromSuperRegion)); } + RegionRoots.clear(); - // Process the worklist of RegionRoots. This performs a "mark-and-sweep" - // of the store. We want to find all live symbols and dead regions. - llvm::SmallPtrSet Marked; + // Process the worklist. + typedef llvm::DenseMap, VisitFlag> + VisitMap; + + VisitMap Visited; - while (!RegionRoots.empty()) { - // Dequeue the next region on the worklist. - const MemRegion* R = RegionRoots.back(); - RegionRoots.pop_back(); + while (!WorkList.empty()) { + RBDItem N = WorkList.back(); + WorkList.pop_back(); - // Check if we have already processed this region. - if (Marked.count(R)) continue; + // Have we visited this node before? + VisitFlag &VF = Visited[N]; + if (VF >= N.getVisitFlag()) + continue; - // Mark this region as processed. This is needed for termination in case - // a region is referenced more than once. - Marked.insert(R); + const MemRegion *R = N.getRegion(); + const GRState *state_N = N.getState(); + // Enqueue subregions? + if (N.getVisitFlag() == VisitedFromSuperRegion) { + RegionStoreSubRegionMap *M; + + if (&state == state_N) + M = SubRegions.get(); + else { + RegionStoreSubRegionMap *& SM = SC[state_N]; + if (!SM) + SM = getRegionStoreSubRegionMap(state_N->getStore()); + M = SM; + } + + RegionStoreSubRegionMap::iterator I, E; + for (llvm::tie(I, E) = M->begin_end(R); I != E; ++I) + WorkList.push_back(RBDItem(state_N, *I, VisitedFromSuperRegion)); + } + + // At this point, if we have already visited this region before, we are + // done. + if (VF != NotVisited) { + VF = N.getVisitFlag(); + continue; + } + VF = N.getVisitFlag(); + + // Enqueue the super region. + if (const SubRegion *SR = dyn_cast(R)) { + const MemRegion *superR = SR->getSuperRegion(); + if (!isa(superR)) { + // If 'R' is a field or an element, we want to keep the bindings + // for the other fields and elements around. The reason is that + // pointer arithmetic can get us to the other fields or elements. + // FIXME: add an assertion that this is always true. + VisitFlag NewVisit = + isa(R) || isa(R) || isa(R) + ? VisitedFromSuperRegion : VisitedFromSubRegion; + + WorkList.push_back(RBDItem(state_N, superR, NewVisit)); + } + } + // Mark the symbol for any live SymbolicRegion as "live". This means we // should continue to track that symbol. if (const SymbolicRegion* SymR = dyn_cast(R)) SymReaper.markLive(SymR->getSymbol()); + + Store store_N = state_N->getStore(); + RegionBindings B_N = GetRegionBindings(store_N); // Get the data binding for R (if any). - RegionBindingsTy::data_type* Xptr = B.lookup(R); - if (Xptr) { - SVal X = *Xptr; - UpdateLiveSymbols(X, SymReaper); // Update the set of live symbols. + Optional V = getBinding(B_N, R); + + if (V) { + // Check for lazy bindings. + if (const nonloc::LazyCompoundVal *LCV = + dyn_cast(V.getPointer())) { - // If X is a region, then add it to the RegionRoots. - if (const MemRegion *RX = X.getAsRegion()) { - RegionRoots.push_back(RX); - - // Mark the super region of the RX as live. - // e.g.: int x; char *y = (char*) &x; if (*y) ... - // 'y' => element region. 'x' is its super region. - // We only add one level super region for now. - // FIXME: maybe multiple level of super regions should be added. - if (const SubRegion *SR = dyn_cast(RX)) { - RegionRoots.push_back(SR->getSuperRegion()); - } + const LazyCompoundValData *D = LCV->getCVData(); + WorkList.push_back(RBDItem(D->getState(), D->getRegion(), + VisitedFromSuperRegion)); + } + else { + // Update the set of live symbols. + for (SVal::symbol_iterator SI=V->symbol_begin(), SE=V->symbol_end(); + SI!=SE;++SI) + SymReaper.markLive(*SI); + + // If V is a region, then add it to the worklist. + if (const MemRegion *RX = V->getAsRegion()) + WorkList.push_back(RBDItem(state_N, RX, VisitedFromSuperRegion)); } } - - // Get the subregions of R. These are RegionRoots as well since they - // represent values that are also bound to R. - const SubRegionsTy* SRptr = SubRegMap.lookup(R); - if (!SRptr) continue; - SubRegionsTy SR = *SRptr; - - for (SubRegionsTy::iterator I=SR.begin(), E=SR.end(); I!=E; ++I) - RegionRoots.push_back(*I); - } // 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. - for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) { + // as well as update DSymbols with the set symbols that are now dead. + for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { const MemRegion* R = I.getKey(); // If this region live? Is so, none of its symbols are dead. - if (Marked.count(R)) + if (Visited.find(std::make_pair(&state, R)) != Visited.end()) continue; - + // Remove this dead region from the store. store = Remove(store, ValMgr.makeLoc(R)); - + // Mark all non-live symbols that this region references as dead. if (const SymbolicRegion* SymR = dyn_cast(R)) SymReaper.maybeDead(SymR->getSymbol()); - - SVal X = I.getData(); + + SVal X = *I.getData().getValue(); SVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end(); - for (; SI != SE; ++SI) SymReaper.maybeDead(*SI); + for (; SI != SE; ++SI) + SymReaper.maybeDead(*SI); } - - return store; + + // Write the store back. + state.setStore(store); +} + +GRState const *RegionStoreManager::EnterStackFrame(GRState const *state, + StackFrameContext const *frame) { + FunctionDecl const *FD = cast(frame->getDecl()); + CallExpr const *CE = cast(frame->getCallSite()); + + FunctionDecl::param_const_iterator PI = FD->param_begin(); + + CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end(); + + // Copy the arg expression value to the arg variables. + for (; AI != AE; ++AI, ++PI) { + SVal ArgVal = state->getSVal(*AI); + MemRegion *R = MRMgr.getVarRegion(*PI, frame); + state = Bind(state, ValMgr.makeLoc(R), ArgVal); + } + + return state; } //===----------------------------------------------------------------------===// @@ -1472,11 +1841,9 @@ Store RegionStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc, void RegionStoreManager::print(Store store, llvm::raw_ostream& OS, const char* nl, const char *sep) { - RegionBindingsTy B = GetRegionBindings(store); - OS << "Store:" << nl; - - for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) { - OS << ' '; I.getKey()->print(OS); OS << " : "; - I.getData().print(OS); OS << nl; - } + RegionBindings B = GetRegionBindings(store); + OS << "Store (direct bindings):" << nl; + + for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) + OS << ' ' << I.getKey() << " : " << I.getData() << nl; } diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp index d711ce0a225e..688b7ff6e1e3 100644 --- a/lib/Analysis/SVals.cpp +++ b/lib/Analysis/SVals.cpp @@ -14,7 +14,6 @@ #include "clang/Analysis/PathSensitive/GRState.h" #include "clang/Basic/IdentifierTable.h" -#include "llvm/Support/Streams.h" using namespace clang; using llvm::dyn_cast; @@ -43,52 +42,32 @@ bool SVal::hasConjuredSymbol() const { SymbolRef sym = SR->getSymbol(); if (isa(sym)) return true; - } else if (const CodeTextRegion *CTR = dyn_cast(R)) { - if (CTR->isSymbolic()) { - SymbolRef sym = CTR->getSymbol(); - if (isa(sym)) - return true; - } } } return false; } -const FunctionDecl* SVal::getAsFunctionDecl() const { +const FunctionDecl *SVal::getAsFunctionDecl() const { if (const loc::MemRegionVal* X = dyn_cast(this)) { const MemRegion* R = X->getRegion(); - if (const CodeTextRegion* CTR = R->getAs()) { - if (CTR->isDeclared()) - return CTR->getDecl(); - } + if (const CodeTextRegion *CTR = R->getAs()) + return CTR->getDecl(); } - return 0; + return NULL; } -/// getAsLocSymbol - If this SVal is a location (subclasses Loc) and +/// getAsLocSymbol - If this SVal is a location (subclasses Loc) and /// wraps a symbol, return that SymbolRef. Otherwise return 0. // FIXME: should we consider SymbolRef wrapped in CodeTextRegion? SymbolRef SVal::getAsLocSymbol() const { if (const loc::MemRegionVal *X = dyn_cast(this)) { - const MemRegion *R = X->getRegion(); - - while (R) { - // Blast through region views. - if (const TypedViewRegion *View = dyn_cast(R)) { - R = View->getSuperRegion(); - continue; - } - - if (const SymbolicRegion *SymR = dyn_cast(R)) - return SymR->getSymbol(); - - break; - } + const MemRegion *R = X->getBaseRegion(); + if (const SymbolicRegion *SymR = dyn_cast(R)) + return SymR->getSymbol(); } - - return 0; + return NULL; } /// getAsSymbol - If this Sval wraps a symbol return that SymbolRef. @@ -97,11 +76,11 @@ SymbolRef SVal::getAsLocSymbol() const { SymbolRef SVal::getAsSymbol() const { if (const nonloc::SymbolVal *X = dyn_cast(this)) return X->getSymbol(); - + if (const nonloc::SymExprVal *X = dyn_cast(this)) if (SymbolRef Y = dyn_cast(X->getSymbolicExpression())) return Y; - + return getAsLocSymbol(); } @@ -110,7 +89,7 @@ SymbolRef SVal::getAsSymbol() const { const SymExpr *SVal::getAsSymbolicExpression() const { if (const nonloc::SymExprVal *X = dyn_cast(this)) return X->getSymbolicExpression(); - + return getAsSymbol(); } @@ -121,6 +100,11 @@ const MemRegion *SVal::getAsRegion() const { return 0; } +const MemRegion *loc::MemRegionVal::getBaseRegion() const { + const MemRegion *R = getRegion(); + return R ? R->getBaseRegion() : NULL; +} + bool SVal::symbol_iterator::operator==(const symbol_iterator &X) const { return itr == X.itr; } @@ -131,13 +115,13 @@ bool SVal::symbol_iterator::operator!=(const symbol_iterator &X) const { SVal::symbol_iterator::symbol_iterator(const SymExpr *SE) { itr.push_back(SE); - while (!isa(itr.back())) expand(); + while (!isa(itr.back())) expand(); } SVal::symbol_iterator& SVal::symbol_iterator::operator++() { assert(!itr.empty() && "attempting to iterate on an 'end' iterator"); assert(isa(itr.back())); - itr.pop_back(); + itr.pop_back(); if (!itr.empty()) while (!isa(itr.back())) expand(); return *this; @@ -151,20 +135,28 @@ SymbolRef SVal::symbol_iterator::operator*() { void SVal::symbol_iterator::expand() { const SymExpr *SE = itr.back(); itr.pop_back(); - + if (const SymIntExpr *SIE = dyn_cast(SE)) { itr.push_back(SIE->getLHS()); return; - } + } else if (const SymSymExpr *SSE = dyn_cast(SE)) { itr.push_back(SSE->getLHS()); itr.push_back(SSE->getRHS()); return; } - + assert(false && "unhandled expansion case"); } +const GRState *nonloc::LazyCompoundVal::getState() const { + return static_cast(Data)->getState(); +} + +const TypedRegion *nonloc::LazyCompoundVal::getRegion() const { + return static_cast(Data)->getRegion(); +} + //===----------------------------------------------------------------------===// // Other Iterators. //===----------------------------------------------------------------------===// @@ -197,10 +189,10 @@ bool SVal::isZeroConstant() const { SVal nonloc::ConcreteInt::evalBinOp(ValueManager &ValMgr, BinaryOperator::Opcode Op, - const nonloc::ConcreteInt& R) const { + const nonloc::ConcreteInt& R) const { const llvm::APSInt* X = ValMgr.getBasicValueFactory().EvaluateAPSInt(Op, getValue(), R.getValue()); - + if (X) return nonloc::ConcreteInt(*X); else @@ -223,12 +215,12 @@ nonloc::ConcreteInt nonloc::ConcreteInt::evalMinus(ValueManager &ValMgr) const { SVal loc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, const loc::ConcreteInt& R) const { - + assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub || (Op >= BinaryOperator::LT && Op <= BinaryOperator::NE)); - + const llvm::APSInt* X = BasicVals.EvaluateAPSInt(Op, getValue(), R.getValue()); - + if (X) return loc::ConcreteInt(*X); else @@ -239,98 +231,89 @@ SVal loc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals, // Pretty-Printing. //===----------------------------------------------------------------------===// -void SVal::printStdErr() const { print(llvm::errs()); } - -void SVal::print(llvm::raw_ostream& Out) const { +void SVal::dump() const { dumpToStream(llvm::errs()); } +void SVal::dumpToStream(llvm::raw_ostream& os) const { switch (getBaseKind()) { - case UnknownKind: - Out << "Invalid"; break; - + os << "Invalid"; + break; case NonLocKind: - cast(this)->print(Out); break; - + cast(this)->dumpToStream(os); + break; case LocKind: - cast(this)->print(Out); break; - + cast(this)->dumpToStream(os); + break; case UndefinedKind: - Out << "Undefined"; break; - + os << "Undefined"; + break; default: assert (false && "Invalid SVal."); } } -void NonLoc::print(llvm::raw_ostream& Out) const { - - switch (getSubKind()) { - +void NonLoc::dumpToStream(llvm::raw_ostream& os) const { + switch (getSubKind()) { case nonloc::ConcreteIntKind: - Out << cast(this)->getValue().getZExtValue(); - + os << cast(this)->getValue().getZExtValue(); if (cast(this)->getValue().isUnsigned()) - Out << 'U'; - + os << 'U'; break; - case nonloc::SymbolValKind: - Out << '$' << cast(this)->getSymbol(); + os << '$' << cast(this)->getSymbol(); break; - case nonloc::SymExprValKind: { const nonloc::SymExprVal& C = *cast(this); const SymExpr *SE = C.getSymbolicExpression(); - Out << SE; + os << SE; break; } - case nonloc::LocAsIntegerKind: { const nonloc::LocAsInteger& C = *cast(this); - C.getLoc().print(Out); - Out << " [as " << C.getNumBits() << " bit integer]"; + os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]"; break; } - case nonloc::CompoundValKind: { const nonloc::CompoundVal& C = *cast(this); - Out << " {"; + os << "compoundVal{"; bool first = true; for (nonloc::CompoundVal::iterator I=C.begin(), E=C.end(); I!=E; ++I) { - if (first) { Out << ' '; first = false; } - else Out << ", "; - (*I).print(Out); + if (first) { + os << ' '; first = false; + } + else + os << ", "; + + (*I).dumpToStream(os); } - Out << " }"; + os << "}"; + break; + } + case nonloc::LazyCompoundValKind: { + const nonloc::LazyCompoundVal &C = *cast(this); + os << "lazyCompoundVal{" << (void*) C.getState() << ',' << C.getRegion() + << '}'; break; } - default: assert (false && "Pretty-printed not implemented for this NonLoc."); break; } } -void Loc::print(llvm::raw_ostream& Out) const { - - switch (getSubKind()) { - +void Loc::dumpToStream(llvm::raw_ostream& os) const { + switch (getSubKind()) { case loc::ConcreteIntKind: - Out << cast(this)->getValue().getZExtValue() - << " (Loc)"; + os << cast(this)->getValue().getZExtValue() << " (Loc)"; break; - case loc::GotoLabelKind: - Out << "&&" - << cast(this)->getLabel()->getID()->getName(); + os << "&&" << cast(this)->getLabel()->getID()->getName(); break; - case loc::MemRegionKind: - Out << '&' << cast(this)->getRegion()->getString(); + os << '&' << cast(this)->getRegion()->getString(); break; - default: - assert (false && "Pretty-printing not implemented for this Loc."); + assert(false && "Pretty-printing not implemented for this Loc."); break; } } diff --git a/lib/Analysis/SValuator.cpp b/lib/Analysis/SValuator.cpp new file mode 100644 index 000000000000..573cac315b3a --- /dev/null +++ b/lib/Analysis/SValuator.cpp @@ -0,0 +1,160 @@ +// SValuator.cpp - Basic class for all SValuator implementations --*- 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 SValuator, the base class for all (complete) SValuator +// implementations. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/SValuator.h" +#include "clang/Analysis/PathSensitive/GRState.h" + +using namespace clang; + + +SVal SValuator::EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op, + SVal L, SVal R, QualType T) { + + if (L.isUndef() || R.isUndef()) + return UndefinedVal(); + + if (L.isUnknown() || R.isUnknown()) + return UnknownVal(); + + if (isa(L)) { + if (isa(R)) + return EvalBinOpLL(Op, cast(L), cast(R), T); + + return EvalBinOpLN(ST, Op, cast(L), cast(R), T); + } + + if (isa(R)) { + // Support pointer arithmetic where the increment/decrement operand + // is on the left and the pointer on the right. + assert(Op == BinaryOperator::Add || Op == BinaryOperator::Sub); + + // Commute the operands. + return EvalBinOpLN(ST, Op, cast(R), cast(L), T); + } + + return EvalBinOpNN(ST, Op, cast(L), cast(R), T); +} + +DefinedOrUnknownSVal SValuator::EvalEQ(const GRState *ST, + DefinedOrUnknownSVal L, + DefinedOrUnknownSVal R) { + return cast(EvalBinOp(ST, BinaryOperator::EQ, L, R, + ValMgr.getContext().IntTy)); +} + +SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state, + QualType castTy, QualType originalTy){ + + if (val.isUnknownOrUndef() || castTy == originalTy) + return CastResult(state, val); + + ASTContext &C = ValMgr.getContext(); + + // For const casts, just propagate the value. + if (C.getCanonicalType(castTy).getUnqualifiedType() == + C.getCanonicalType(originalTy).getUnqualifiedType()) + return CastResult(state, val); + + // Check for casts from pointers to integers. + if (castTy->isIntegerType() && Loc::IsLocType(originalTy)) + return CastResult(state, EvalCastL(cast(val), castTy)); + + // Check for casts from integers to pointers. + if (Loc::IsLocType(castTy) && originalTy->isIntegerType()) { + if (nonloc::LocAsInteger *LV = dyn_cast(&val)) { + // Just unpackage the lval and return it. + return CastResult(state, LV->getLoc()); + } + + goto DispatchCast; + } + + // Just pass through function and block pointers. + if (originalTy->isBlockPointerType() || originalTy->isFunctionPointerType()) { + assert(Loc::IsLocType(castTy)); + return CastResult(state, val); + } + + // Check for casts from array type to another type. + if (originalTy->isArrayType()) { + // We will always decay to a pointer. + val = ValMgr.getStateManager().ArrayToPointer(cast(val)); + + // Are we casting from an array to a pointer? If so just pass on + // the decayed value. + if (castTy->isPointerType()) + return CastResult(state, val); + + // Are we casting from an array to an integer? If so, cast the decayed + // pointer value to an integer. + assert(castTy->isIntegerType()); + + // FIXME: Keep these here for now in case we decide soon that we + // need the original decayed type. + // QualType elemTy = cast(originalTy)->getElementType(); + // QualType pointerTy = C.getPointerType(elemTy); + return CastResult(state, EvalCastL(cast(val), castTy)); + } + + // Check for casts from a region to a specific type. + if (const MemRegion *R = val.getAsRegion()) { + // FIXME: We should handle the case where we strip off view layers to get + // to a desugared type. + + assert(Loc::IsLocType(castTy)); + // We get a symbolic function pointer for a dereference of a function + // pointer, but it is of function type. Example: + + // struct FPRec { + // void (*my_func)(int * x); + // }; + // + // int bar(int x); + // + // int f1_a(struct FPRec* foo) { + // int x; + // (*foo->my_func)(&x); + // return bar(x)+1; // no-warning + // } + + assert(Loc::IsLocType(originalTy) || originalTy->isFunctionType() || + originalTy->isBlockPointerType()); + + StoreManager &storeMgr = ValMgr.getStateManager().getStoreManager(); + + // Delegate to store manager to get the result of casting a region to a + // different type. If the MemRegion* returned is NULL, this expression + // evaluates to UnknownVal. + R = storeMgr.CastRegion(R, castTy); + + if (R) + return CastResult(state, loc::MemRegionVal(R)); + + return CastResult(state, UnknownVal()); + } + + // All other cases. +DispatchCast: + return CastResult(state, + isa(val) ? EvalCastL(cast(val), castTy) + : EvalCastNL(cast(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(X.getSVal())); +} diff --git a/lib/Analysis/SimpleConstraintManager.cpp b/lib/Analysis/SimpleConstraintManager.cpp index 82801eb05d38..015db76080df 100644 --- a/lib/Analysis/SimpleConstraintManager.cpp +++ b/lib/Analysis/SimpleConstraintManager.cpp @@ -23,10 +23,10 @@ SimpleConstraintManager::~SimpleConstraintManager() {} bool SimpleConstraintManager::canReasonAbout(SVal X) const { if (nonloc::SymExprVal *SymVal = dyn_cast(&X)) { const SymExpr *SE = SymVal->getSymbolicExpression(); - + if (isa(SE)) return true; - + if (const SymIntExpr *SIE = dyn_cast(SE)) { switch (SIE->getOpcode()) { // We don't reason yet about bitwise-constraints on symbolic values. @@ -46,7 +46,7 @@ bool SimpleConstraintManager::canReasonAbout(SVal X) const { // All other cases. default: return true; - } + } } return false; @@ -54,13 +54,10 @@ bool SimpleConstraintManager::canReasonAbout(SVal X) const { return true; } - -const GRState *SimpleConstraintManager::Assume(const GRState *state, - SVal Cond, bool Assumption) { - if (Cond.isUnknown()) { - return state; - } +const GRState *SimpleConstraintManager::Assume(const GRState *state, + DefinedSVal Cond, + bool Assumption) { if (isa(Cond)) return Assume(state, cast(Cond), Assumption); else @@ -74,14 +71,14 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state, Loc Cond, // EvalAssume is used to call into the GRTransferFunction object to perform // any checker-specific update of the state based on this assumption being - // true or false. + // true or false. return state ? state->getTransferFuncs().EvalAssume(state, Cond, Assumption) : NULL; } const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, Loc Cond, bool Assumption) { - + BasicValueFactory &BasicVals = state->getBasicVals(); switch (Cond.getSubKind()) { @@ -91,7 +88,7 @@ const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, case loc::MemRegionKind: { // FIXME: Should this go into the storemanager? - + const MemRegion *R = cast(Cond).getRegion(); const SubRegion *SubR = dyn_cast(R); @@ -99,7 +96,7 @@ const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, // FIXME: now we only find the first symbolic region. if (const SymbolicRegion *SymR = dyn_cast(SubR)) { if (Assumption) - return AssumeSymNE(state, SymR->getSymbol(), + return AssumeSymNE(state, SymR->getSymbol(), BasicVals.getZeroWithPtrWidth()); else return AssumeSymEQ(state, SymR->getSymbol(), @@ -107,15 +104,15 @@ const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, } SubR = dyn_cast(SubR->getSuperRegion()); } - + // FALL-THROUGH. } - + case loc::GotoLabelKind: return Assumption ? state : NULL; case loc::ConcreteIntKind: { - bool b = cast(Cond).getValue() != 0; + bool b = cast(Cond).getValue() != 0; bool isFeasible = b ? Assumption : !Assumption; return isFeasible ? state : NULL; } @@ -130,7 +127,7 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state, // EvalAssume is used to call into the GRTransferFunction object to perform // any checker-specific update of the state based on this assumption being - // true or false. + // true or false. return state ? state->getTransferFuncs().EvalAssume(state, Cond, Assumption) : NULL; } @@ -138,13 +135,13 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state, const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, NonLoc Cond, bool Assumption) { - + // We cannot reason about SymIntExpr and SymSymExpr. if (!canReasonAbout(Cond)) { // Just return the current state indicating that the path is feasible. // This may be an over-approximation of what is possible. return state; - } + } BasicValueFactory &BasicVals = state->getBasicVals(); SymbolManager &SymMgr = state->getSymbolManager(); @@ -156,7 +153,7 @@ const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, case nonloc::SymbolValKind: { nonloc::SymbolVal& SV = cast(Cond); SymbolRef sym = SV.getSymbol(); - QualType T = SymMgr.getType(sym); + QualType T = SymMgr.getType(sym); const llvm::APSInt &zero = BasicVals.getValue(0, T); return Assumption ? AssumeSymNE(state, sym, zero) @@ -165,9 +162,20 @@ const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, case nonloc::SymExprValKind: { nonloc::SymExprVal V = cast(Cond); - if (const SymIntExpr *SE = dyn_cast(V.getSymbolicExpression())) - return AssumeSymInt(state, Assumption, SE); - + if (const SymIntExpr *SE = dyn_cast(V.getSymbolicExpression())){ + // FIXME: This is a hack. It silently converts the RHS integer to be + // of the same type as on the left side. This should be removed once + // we support truncation/extension of symbolic values. + GRStateManager &StateMgr = state->getStateManager(); + ASTContext &Ctx = StateMgr.getContext(); + QualType LHSType = SE->getLHS()->getType(Ctx); + BasicValueFactory &BasicVals = StateMgr.getBasicVals(); + const llvm::APSInt &RHS = BasicVals.Convert(LHSType, SE->getRHS()); + SymIntExpr SENew(SE->getLHS(), SE->getOpcode(), RHS, SE->getType(Ctx)); + + return AssumeSymInt(state, Assumption, &SENew); + } + // For all other symbolic expressions, over-approximate and consider // the constraint feasible. return state; @@ -194,7 +202,7 @@ const GRState *SimpleConstraintManager::AssumeSymInt(const GRState *state, // rest of the constraint manager logic. SymbolRef Sym = cast(SE->getLHS()); const llvm::APSInt &Int = SE->getRHS(); - + switch (SE->getOpcode()) { default: // No logic yet for other operators. Assume the constraint is feasible. @@ -218,7 +226,7 @@ const GRState *SimpleConstraintManager::AssumeSymInt(const GRState *state, case BinaryOperator::LT: return Assumption ? AssumeSymLT(state, Sym, Int) : AssumeSymGE(state, Sym, Int); - + case BinaryOperator::LE: return Assumption ? AssumeSymLE(state, Sym, Int) : AssumeSymGT(state, Sym, Int); @@ -226,9 +234,9 @@ const GRState *SimpleConstraintManager::AssumeSymInt(const GRState *state, } const GRState *SimpleConstraintManager::AssumeInBound(const GRState *state, - SVal Idx, - SVal UpperBound, - bool Assumption) { + DefinedSVal Idx, + DefinedSVal UpperBound, + bool Assumption) { // Only support ConcreteInt for now. if (!(isa(Idx) && isa(UpperBound))) diff --git a/lib/Analysis/SimpleConstraintManager.h b/lib/Analysis/SimpleConstraintManager.h index 1e1a10da030f..0c58440ac0b6 100644 --- a/lib/Analysis/SimpleConstraintManager.h +++ b/lib/Analysis/SimpleConstraintManager.h @@ -22,15 +22,16 @@ namespace clang { class SimpleConstraintManager : public ConstraintManager { public: SimpleConstraintManager() {} - virtual ~SimpleConstraintManager(); - + virtual ~SimpleConstraintManager(); + //===------------------------------------------------------------------===// // Common implementation for the interface provided by ConstraintManager. //===------------------------------------------------------------------===// bool canReasonAbout(SVal X) const; - const GRState *Assume(const GRState *state, SVal Cond, bool Assumption); + const GRState *Assume(const GRState *state, DefinedSVal Cond, + bool Assumption); const GRState *Assume(const GRState *state, Loc Cond, bool Assumption); @@ -38,16 +39,17 @@ public: const GRState *AssumeSymInt(const GRState *state, bool Assumption, const SymIntExpr *SE); - - const GRState *AssumeInBound(const GRState *state, SVal Idx, SVal UpperBound, + + const GRState *AssumeInBound(const GRState *state, DefinedSVal Idx, + DefinedSVal UpperBound, bool Assumption); - + protected: - + //===------------------------------------------------------------------===// // Interface that subclasses must implement. //===------------------------------------------------------------------===// - + virtual const GRState *AssumeSymNE(const GRState *state, SymbolRef sym, const llvm::APSInt& V) = 0; @@ -65,13 +67,13 @@ protected: virtual const GRState *AssumeSymGE(const GRState *state, SymbolRef sym, const llvm::APSInt& V) = 0; - + //===------------------------------------------------------------------===// // Internal implementation. //===------------------------------------------------------------------===// - + const GRState *AssumeAux(const GRState *state, Loc Cond,bool Assumption); - + const GRState *AssumeAux(const GRState *state, NonLoc Cond, bool Assumption); }; diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp index 76a8bc782eb5..636ce15c3326 100644 --- a/lib/Analysis/SimpleSValuator.cpp +++ b/lib/Analysis/SimpleSValuator.cpp @@ -19,21 +19,23 @@ using namespace clang; namespace { class VISIBILITY_HIDDEN SimpleSValuator : public SValuator { +protected: + virtual SVal EvalCastNL(NonLoc val, QualType castTy); + virtual SVal EvalCastL(Loc val, QualType castTy); + public: SimpleSValuator(ValueManager &valMgr) : SValuator(valMgr) {} virtual ~SimpleSValuator() {} - - virtual SVal EvalCast(NonLoc val, QualType castTy); - virtual SVal EvalCast(Loc val, QualType castTy); - virtual SVal EvalMinus(NonLoc val); - virtual SVal EvalComplement(NonLoc val); - virtual SVal EvalBinOpNN(BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, - QualType resultTy); + + virtual SVal EvalMinus(NonLoc val); + virtual SVal EvalComplement(NonLoc val); + virtual SVal EvalBinOpNN(const GRState *state, BinaryOperator::Opcode op, + NonLoc lhs, NonLoc rhs, QualType resultTy); virtual SVal EvalBinOpLL(BinaryOperator::Opcode op, Loc lhs, Loc rhs, QualType resultTy); virtual SVal EvalBinOpLN(const GRState *state, BinaryOperator::Opcode op, Loc lhs, NonLoc rhs, QualType resultTy); -}; +}; } // end anonymous namespace SValuator *clang::CreateSimpleSValuator(ValueManager &valMgr) { @@ -44,16 +46,48 @@ SValuator *clang::CreateSimpleSValuator(ValueManager &valMgr) { // Transfer function for Casts. //===----------------------------------------------------------------------===// -SVal SimpleSValuator::EvalCast(NonLoc val, QualType castTy) { +SVal SimpleSValuator::EvalCastNL(NonLoc val, QualType castTy) { + + bool isLocType = Loc::IsLocType(castTy); + + if (nonloc::LocAsInteger *LI = dyn_cast(&val)) { + if (isLocType) + return LI->getLoc(); + + ASTContext &Ctx = ValMgr.getContext(); + + // FIXME: Support promotions/truncations. + if (Ctx.getTypeSize(castTy) == Ctx.getTypeSize(Ctx.VoidPtrTy)) + return val; + + return UnknownVal(); + } + + if (const SymExpr *se = val.getAsSymbolicExpression()) { + ASTContext &Ctx = ValMgr.getContext(); + QualType T = Ctx.getCanonicalType(se->getType(Ctx)); + if (T == Ctx.getCanonicalType(castTy)) + return val; + + // FIXME: Remove this hack when we support symbolic truncation/extension. + // HACK: If both castTy and T are integers, ignore the cast. This is + // not a permanent solution. Eventually we want to precisely handle + // extension/truncation of symbolic integers. This prevents us from losing + // precision when we assign 'x = y' and 'y' is symbolic and x and y are + // different integer types. + if (T->isIntegerType() && castTy->isIntegerType()) + return val; + + return UnknownVal(); + } + if (!isa(val)) return UnknownVal(); - bool isLocType = Loc::IsLocType(castTy); - // Only handle casts from integers to integers. if (!isLocType && !castTy->isIntegerType()) return UnknownVal(); - + llvm::APSInt i = cast(val).getValue(); i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy)); i.extOrTrunc(ValMgr.getContext().getTypeSize(castTy)); @@ -64,30 +98,28 @@ SVal SimpleSValuator::EvalCast(NonLoc val, QualType castTy) { return ValMgr.makeIntVal(i); } -SVal SimpleSValuator::EvalCast(Loc val, QualType castTy) { - +SVal SimpleSValuator::EvalCastL(Loc val, QualType castTy) { + // Casts from pointers -> pointers, just return the lval. // // Casts from pointers -> references, just return the lval. These // can be introduced by the frontend for corner cases, e.g // casting from va_list* to __builtin_va_list&. // - assert(!val.isUnknownOrUndef()); - if (Loc::IsLocType(castTy) || castTy->isReferenceType()) return val; - + // FIXME: Handle transparent unions where a value can be "transparently" // lifted into a union type. if (castTy->isUnionType()) return UnknownVal(); - + assert(castTy->isIntegerType()); unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy); if (!isa(val)) return ValMgr.makeLocAsInteger(val, BitWidth); - + llvm::APSInt i = cast(val).getValue(); i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy)); i.extOrTrunc(BitWidth); @@ -99,7 +131,7 @@ SVal SimpleSValuator::EvalCast(Loc val, QualType castTy) { //===----------------------------------------------------------------------===// SVal SimpleSValuator::EvalMinus(NonLoc val) { - switch (val.getSubKind()) { + switch (val.getSubKind()) { case nonloc::ConcreteIntKind: return cast(val).evalMinus(ValMgr); default: @@ -133,18 +165,18 @@ static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) { } } -// Equality operators for Locs. +// Equality operators for Locs. // FIXME: All this logic will be revamped when we have MemRegion::getLocation() // implemented. static SVal EvalEquality(ValueManager &ValMgr, Loc lhs, Loc rhs, bool isEqual, QualType resultTy) { - + switch (lhs.getSubKind()) { default: assert(false && "EQ/NE not implemented for this Loc."); return UnknownVal(); - + case loc::ConcreteIntKind: { if (SymbolRef rSym = rhs.getAsSymbol()) return ValMgr.makeNonLoc(rSym, @@ -153,7 +185,7 @@ static SVal EvalEquality(ValueManager &ValMgr, Loc lhs, Loc rhs, bool isEqual, cast(lhs).getValue(), resultTy); break; - } + } case loc::MemRegionKind: { if (SymbolRef lSym = lhs.getAsLocSymbol()) { if (isa(rhs)) { @@ -166,27 +198,43 @@ static SVal EvalEquality(ValueManager &ValMgr, Loc lhs, Loc rhs, bool isEqual, } break; } - + case loc::GotoLabelKind: break; } - + return ValMgr.makeTruthVal(isEqual ? lhs == rhs : lhs != rhs, resultTy); } -SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op, +SVal SimpleSValuator::EvalBinOpNN(const GRState *state, + BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, - QualType resultTy) { + QualType resultTy) { + // Handle trivial case where left-side and right-side are the same. + if (lhs == rhs) + switch (op) { + default: + break; + case BinaryOperator::EQ: + case BinaryOperator::LE: + case BinaryOperator::GE: + return ValMgr.makeTruthVal(true, resultTy); + case BinaryOperator::LT: + case BinaryOperator::GT: + case BinaryOperator::NE: + return ValMgr.makeTruthVal(false, resultTy); + } + while (1) { switch (lhs.getSubKind()) { default: - return UnknownVal(); + return UnknownVal(); case nonloc::LocAsIntegerKind: { - Loc lhsL = cast(lhs).getLoc(); + Loc lhsL = cast(lhs).getLoc(); switch (rhs.getSubKind()) { case nonloc::LocAsIntegerKind: return EvalBinOpLL(op, lhsL, cast(rhs).getLoc(), - resultTy); + resultTy); case nonloc::ConcreteIntKind: { // Transform the integer into a location and compare. ASTContext& Ctx = ValMgr.getContext(); @@ -195,7 +243,7 @@ SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op, i.extOrTrunc(Ctx.getTypeSize(Ctx.VoidPtrTy)); return EvalBinOpLL(op, lhsL, ValMgr.makeLoc(i), resultTy); } - default: + default: switch (op) { case BinaryOperator::EQ: return ValMgr.makeTruthVal(false, resultTy); @@ -206,15 +254,15 @@ SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op, return UnknownVal(); } } - } + } case nonloc::SymExprValKind: { - // Logical not? + // Logical not? if (!(op == BinaryOperator::EQ && rhs.isZeroConstant())) return UnknownVal(); const SymExpr *symExpr = cast(lhs).getSymbolicExpression(); - + // Only handle ($sym op constant) for now. if (const SymIntExpr *symIntExpr = dyn_cast(symExpr)) { BinaryOperator::Opcode opc = symIntExpr->getOpcode(); @@ -257,7 +305,7 @@ SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op, case BinaryOperator::GT: case BinaryOperator::LE: case BinaryOperator::GE: - case BinaryOperator::EQ: + case BinaryOperator::EQ: case BinaryOperator::NE: opc = NegateComparison(opc); assert(symIntExpr->getType(ValMgr.getContext()) == resultTy); @@ -266,7 +314,7 @@ SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op, } } } - case nonloc::ConcreteIntKind: { + case nonloc::ConcreteIntKind: { if (isa(rhs)) { const nonloc::ConcreteInt& lhsInt = cast(lhs); return lhsInt.evalBinOp(ValMgr, op, cast(rhs)); @@ -278,7 +326,7 @@ SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op, NonLoc tmp = rhs; rhs = lhs; lhs = tmp; - + switch (op) { case BinaryOperator::LT: op = BinaryOperator::GT; continue; case BinaryOperator::GT: op = BinaryOperator::LT; continue; @@ -291,12 +339,27 @@ SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op, continue; default: return UnknownVal(); - } + } } } case nonloc::SymbolValKind: { + nonloc::SymbolVal *slhs = cast(&lhs); + SymbolRef Sym = slhs->getSymbol(); + + // Does the symbol simplify to a constant? + if (Sym->getType(ValMgr.getContext())->isIntegerType()) + if (const llvm::APSInt *Constant = state->getSymVal(Sym)) { + // What should we convert it to? + if (nonloc::ConcreteInt *rhs_I = dyn_cast(&rhs)){ + BasicValueFactory &BVF = ValMgr.getBasicValueFactory(); + lhs = nonloc::ConcreteInt(BVF.Convert(rhs_I->getValue(), + *Constant)); + continue; + } + } + if (isa(rhs)) { - return ValMgr.makeNonLoc(cast(lhs).getSymbol(), op, + return ValMgr.makeNonLoc(slhs->getSymbol(), op, cast(rhs).getValue(), resultTy); } @@ -308,19 +371,26 @@ SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op, } SVal SimpleSValuator::EvalBinOpLL(BinaryOperator::Opcode op, Loc lhs, Loc rhs, - QualType resultTy) { + QualType resultTy) { switch (op) { default: return UnknownVal(); case BinaryOperator::EQ: case BinaryOperator::NE: return EvalEquality(ValMgr, lhs, rhs, op == BinaryOperator::EQ, resultTy); + case BinaryOperator::LT: + case BinaryOperator::GT: + // FIXME: Generalize. For now, just handle the trivial case where + // the two locations are identical. + if (lhs == rhs) + return ValMgr.makeTruthVal(false, resultTy); + return UnknownVal(); } } SVal SimpleSValuator::EvalBinOpLN(const GRState *state, BinaryOperator::Opcode op, - Loc lhs, NonLoc rhs, QualType resultTy) { + Loc lhs, NonLoc rhs, QualType resultTy) { // Special case: 'rhs' is an integer that has the same width as a pointer and // we are using the integer location in a comparison. Normally this cannot be // triggered, but transfer functions like those for OSCommpareAndSwapBarrier32 @@ -333,13 +403,13 @@ SVal SimpleSValuator::EvalBinOpLN(const GRState *state, if (ctx.getTypeSize(ctx.VoidPtrTy) == x->getBitWidth()) { // Convert the signedness of the integer (if necessary). if (x->isSigned()) - x = &ValMgr.getBasicValueFactory().getValue(*x, true); + x = &ValMgr.getBasicValueFactory().getValue(*x, true); return EvalBinOpLL(op, lhs, loc::ConcreteInt(*x), resultTy); } } } - + // Delegate pointer arithmetic to the StoreManager. return state->getStateManager().getStoreManager().EvalBinOp(state, op, lhs, rhs, resultTy); diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp index cb099862f055..4b4ae6580820 100644 --- a/lib/Analysis/Store.cpp +++ b/lib/Analysis/Store.cpp @@ -17,95 +17,189 @@ using namespace clang; StoreManager::StoreManager(GRStateManager &stateMgr) - : ValMgr(stateMgr.getValueManager()), - StateMgr(stateMgr), + : ValMgr(stateMgr.getValueManager()), StateMgr(stateMgr), MRMgr(ValMgr.getRegionManager()) {} -StoreManager::CastResult -StoreManager::CastRegion(const GRState* state, const MemRegion* R, - QualType CastToTy) { - +const MemRegion *StoreManager::MakeElementRegion(const MemRegion *Base, + QualType EleTy, uint64_t index) { + SVal idx = ValMgr.makeArrayIndex(index); + return MRMgr.getElementRegion(EleTy, idx, Base, ValMgr.getContext()); +} + +// FIXME: Merge with the implementation of the same method in MemRegion.cpp +static bool IsCompleteType(ASTContext &Ctx, QualType Ty) { + if (const RecordType *RT = Ty->getAs()) { + const RecordDecl *D = RT->getDecl(); + if (!D->getDefinition(Ctx)) + return false; + } + + return true; +} + +const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) { + ASTContext& Ctx = StateMgr.getContext(); - // We need to know the real type of CastToTy. - QualType ToTy = Ctx.getCanonicalType(CastToTy); + // Handle casts to Objective-C objects. + if (CastToTy->isObjCObjectPointerType()) + return R->getBaseRegion(); - // Return the same region if the region types are compatible. - if (const TypedRegion* TR = dyn_cast(R)) { - QualType Ta = Ctx.getCanonicalType(TR->getLocationType(Ctx)); + if (CastToTy->isBlockPointerType()) { + // FIXME: We may need different solutions, depending on the symbol + // involved. Blocks can be casted to/from 'id', as they can be treated + // as Objective-C objects. This could possibly be handled by enhancing + // our reasoning of downcasts of symbolic objects. + if (isa(R) || isa(R)) + return R; - if (Ta == ToTy) - return CastResult(state, R); + // We don't know what to make of it. Return a NULL region, which + // will be interpretted as UnknownVal. + return NULL; } - - if (const PointerType* PTy = dyn_cast(ToTy.getTypePtr())) { - // Check if we are casting to 'void*'. - // FIXME: Handle arbitrary upcasts. - QualType Pointee = PTy->getPointeeType(); - if (Pointee->isVoidType()) { - - do { - if (const TypedViewRegion *TR = dyn_cast(R)) { - // Casts to void* removes TypedViewRegion. This happens when: - // - // void foo(void*); - // ... - // void bar() { - // int x; - // foo(&x); - // } - // - R = TR->removeViews(); - continue; + + // Now assume we are casting from pointer to pointer. Other cases should + // already be handled. + QualType PointeeTy = CastToTy->getAs()->getPointeeType(); + QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy); + + // Handle casts to void*. We just pass the region through. + if (CanonPointeeTy.getUnqualifiedType() == Ctx.VoidTy) + return R; + + // Handle casts from compatible types. + if (R->isBoundable()) + if (const TypedRegion *TR = dyn_cast(R)) { + QualType ObjTy = Ctx.getCanonicalType(TR->getValueType(Ctx)); + if (CanonPointeeTy == ObjTy) + return R; + } + + // Process region cast according to the kind of the region being cast. + switch (R->getKind()) { + case MemRegion::BEG_TYPED_REGIONS: + case MemRegion::MemSpaceRegionKind: + case MemRegion::BEG_DECL_REGIONS: + case MemRegion::END_DECL_REGIONS: + case MemRegion::END_TYPED_REGIONS: { + assert(0 && "Invalid region cast"); + break; + } + case MemRegion::CodeTextRegionKind: { + // CodeTextRegion should be cast to only a function or block pointer type, + // although they can in practice be casted to anything, e.g, void*, char*, + // etc. + // Just return the region. + return R; + } + + case MemRegion::StringRegionKind: + case MemRegion::ObjCObjectRegionKind: + // FIXME: Need to handle arbitrary downcasts. + case MemRegion::SymbolicRegionKind: + case MemRegion::AllocaRegionKind: + case MemRegion::CompoundLiteralRegionKind: + case MemRegion::FieldRegionKind: + case MemRegion::ObjCIvarRegionKind: + case MemRegion::VarRegionKind: + return MakeElementRegion(R, PointeeTy); + + case MemRegion::ElementRegionKind: { + // If we are casting from an ElementRegion to another type, the + // algorithm is as follows: + // + // (1) Compute the "raw offset" of the ElementRegion from the + // base region. This is done by calling 'getAsRawOffset()'. + // + // (2a) If we get a 'RegionRawOffset' after calling + // 'getAsRawOffset()', determine if the absolute offset + // can be exactly divided into chunks of the size of the + // casted-pointee type. If so, create a new ElementRegion with + // the pointee-cast type as the new ElementType and the index + // being the offset divded by the chunk size. If not, create + // a new ElementRegion at offset 0 off the raw offset region. + // + // (2b) If we don't a get a 'RegionRawOffset' after calling + // 'getAsRawOffset()', it means that we are at offset 0. + // + // FIXME: Handle symbolic raw offsets. + + const ElementRegion *elementR = cast(R); + const RegionRawOffset &rawOff = elementR->getAsRawOffset(); + const MemRegion *baseR = rawOff.getRegion(); + + // If we cannot compute a raw offset, throw up our hands and return + // a NULL MemRegion*. + if (!baseR) + return NULL; + + int64_t off = rawOff.getByteOffset(); + + if (off == 0) { + // Edge case: we are at 0 bytes off the beginning of baseR. We + // check to see if type we are casting to is the same as the base + // region. If so, just return the base region. + if (const TypedRegion *TR = dyn_cast(baseR)) { + QualType ObjTy = Ctx.getCanonicalType(TR->getValueType(Ctx)); + QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy); + if (CanonPointeeTy == ObjTy) + return baseR; } - else if (const ElementRegion *ER = dyn_cast(R)) { - // Casts to void* also removes ElementRegions. This happens when: - // - // void foo(void*); - // ... - // void bar() { - // int x; - // foo((char*)&x); - // } - // - R = ER->getSuperRegion(); - continue; + + // Otherwise, create a new ElementRegion at offset 0. + return MakeElementRegion(baseR, PointeeTy); + } + + // We have a non-zero offset from the base region. We want to determine + // if the offset can be evenly divided by sizeof(PointeeTy). If so, + // we create an ElementRegion whose index is that value. Otherwise, we + // create two ElementRegions, one that reflects a raw offset and the other + // that reflects the cast. + + // Compute the index for the new ElementRegion. + int64_t newIndex = 0; + const MemRegion *newSuperR = 0; + + // We can only compute sizeof(PointeeTy) if it is a complete type. + if (IsCompleteType(Ctx, PointeeTy)) { + // Compute the size in **bytes**. + int64_t pointeeTySize = (int64_t) (Ctx.getTypeSize(PointeeTy) / 8); + + // Is the offset a multiple of the size? If so, we can layer the + // ElementRegion (with elementType == PointeeTy) directly on top of + // the base region. + if (off % pointeeTySize == 0) { + newIndex = off / pointeeTySize; + newSuperR = baseR; } - else - break; } - while (0); - - return CastResult(state, R); - } - else if (Pointee->isIntegerType()) { - // FIXME: At some point, it stands to reason that this 'dyn_cast' should - // become a 'cast' and that 'R' will always be a TypedRegion. - if (const TypedRegion *TR = dyn_cast(R)) { - // Check if we are casting to a region with an integer type. We now - // the types aren't the same, so we construct an ElementRegion. - SVal Idx = ValMgr.makeZeroArrayIndex(); - - // If the super region is an element region, strip it away. - // FIXME: Is this the right thing to do in all cases? - const MemRegion *Base = isa(TR) ? TR->getSuperRegion() - : TR; - ElementRegion* ER = MRMgr.getElementRegion(Pointee, Idx, Base, - StateMgr.getContext()); - return CastResult(state, ER); + + if (!newSuperR) { + // Create an intermediate ElementRegion to represent the raw byte. + // This will be the super region of the final ElementRegion. + newSuperR = MakeElementRegion(baseR, Ctx.CharTy, off); } + + return MakeElementRegion(newSuperR, PointeeTy, newIndex); } } - // FIXME: Need to handle arbitrary downcasts. - // FIXME: Handle the case where a TypedViewRegion (layering a SymbolicRegion - // or an AllocaRegion is cast to another view, thus causing the memory - // to be re-used for a different purpose. + assert(0 && "unreachable"); + return 0; +} + - if (isa(R) || isa(R)) { - const MemRegion* ViewR = MRMgr.getTypedViewRegion(CastToTy, R); - return CastResult(AddRegionView(state, ViewR, R), ViewR); - } - - return CastResult(state, R); +/// CastRetrievedVal - Used by subclasses of StoreManager to implement +/// implicit casts that arise from loads from regions that are reinterpreted +/// as another region. +SValuator::CastResult StoreManager::CastRetrievedVal(SVal V, + const GRState *state, + const TypedRegion *R, + QualType castTy) { + if (castTy.isNull()) + return SValuator::CastResult(state, V); + + ASTContext &Ctx = ValMgr.getContext(); + return ValMgr.getSValuator().EvalCast(V, state, castTy, R->getValueType(Ctx)); } + diff --git a/lib/Analysis/SymbolManager.cpp b/lib/Analysis/SymbolManager.cpp index 275f30a2963e..22e110192956 100644 --- a/lib/Analysis/SymbolManager.cpp +++ b/lib/Analysis/SymbolManager.cpp @@ -18,9 +18,11 @@ using namespace clang; -static void print(llvm::raw_ostream& os, const SymExpr *SE); +void SymExpr::dump() const { + dumpToStream(llvm::errs()); +} -static void print(llvm::raw_ostream& os, BinaryOperator::Opcode Op) { +static void print(llvm::raw_ostream& os, BinaryOperator::Opcode Op) { switch (Op) { default: assert(false && "operator printing not implemented"); @@ -35,92 +37,100 @@ static void print(llvm::raw_ostream& os, BinaryOperator::Opcode Op) { case BinaryOperator::LT: os << "<" ; break; case BinaryOperator::GT: os << '>' ; break; case BinaryOperator::LE: os << "<=" ; break; - case BinaryOperator::GE: os << ">=" ; break; + case BinaryOperator::GE: os << ">=" ; break; case BinaryOperator::EQ: os << "==" ; break; case BinaryOperator::NE: os << "!=" ; break; case BinaryOperator::And: os << '&' ; break; case BinaryOperator::Xor: os << '^' ; break; case BinaryOperator::Or: os << '|' ; break; - } + } } -static void print(llvm::raw_ostream& os, const SymIntExpr *SE) { +void SymIntExpr::dumpToStream(llvm::raw_ostream& os) const { os << '('; - print(os, SE->getLHS()); + getLHS()->dumpToStream(os); os << ") "; - print(os, SE->getOpcode()); - os << ' ' << SE->getRHS().getZExtValue(); - if (SE->getRHS().isUnsigned()) os << 'U'; + print(os, getOpcode()); + os << ' ' << getRHS().getZExtValue(); + if (getRHS().isUnsigned()) os << 'U'; } - -static void print(llvm::raw_ostream& os, const SymSymExpr *SE) { + +void SymSymExpr::dumpToStream(llvm::raw_ostream& os) const { os << '('; - print(os, SE->getLHS()); + getLHS()->dumpToStream(os); os << ") "; os << '('; - print(os, SE->getRHS()); - os << ')'; -} - -static void print(llvm::raw_ostream& os, const SymExpr *SE) { - switch (SE->getKind()) { - case SymExpr::BEGIN_SYMBOLS: - case SymExpr::RegionValueKind: - case SymExpr::ConjuredKind: - case SymExpr::END_SYMBOLS: - os << '$' << cast(SE)->getSymbolID(); - return; - case SymExpr::SymIntKind: - print(os, cast(SE)); - return; - case SymExpr::SymSymKind: - print(os, cast(SE)); - return; - } + getRHS()->dumpToStream(os); + os << ')'; } +void SymbolConjured::dumpToStream(llvm::raw_ostream& os) const { + os << "conj_$" << getSymbolID() << '{' << T.getAsString() << '}'; +} + +void SymbolDerived::dumpToStream(llvm::raw_ostream& os) const { + os << "derived_$" << getSymbolID() << '{' + << getParentSymbol() << ',' << getRegion() << '}'; +} -llvm::raw_ostream& llvm::operator<<(llvm::raw_ostream& os, const SymExpr *SE) { - print(os, SE); - return os; +void SymbolRegionValue::dumpToStream(llvm::raw_ostream& os) const { + os << "reg_$" << getSymbolID() << "<" << R << ">"; } -const SymbolRegionValue* +const SymbolRegionValue* SymbolManager::getRegionValueSymbol(const MemRegion* R, QualType T) { llvm::FoldingSetNodeID profile; SymbolRegionValue::Profile(profile, R, T); - void* InsertPos; - SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); - if (!SD) { + void* InsertPos; + SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); + if (!SD) { SD = (SymExpr*) BPAlloc.Allocate(); - new (SD) SymbolRegionValue(SymbolCounter, R, T); + new (SD) SymbolRegionValue(SymbolCounter, R, T); DataSet.InsertNode(SD, InsertPos); ++SymbolCounter; } - + return cast(SD); } const SymbolConjured* SymbolManager::getConjuredSymbol(const Stmt* E, QualType T, unsigned Count, const void* SymbolTag) { - + llvm::FoldingSetNodeID profile; SymbolConjured::Profile(profile, E, T, Count, SymbolTag); - void* InsertPos; - SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); - if (!SD) { + void* InsertPos; + SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); + if (!SD) { SD = (SymExpr*) BPAlloc.Allocate(); - new (SD) SymbolConjured(SymbolCounter, E, T, Count, SymbolTag); - DataSet.InsertNode(SD, InsertPos); + new (SD) SymbolConjured(SymbolCounter, E, T, Count, SymbolTag); + DataSet.InsertNode(SD, InsertPos); ++SymbolCounter; } - + return cast(SD); } +const SymbolDerived* +SymbolManager::getDerivedSymbol(SymbolRef parentSymbol, + const TypedRegion *R) { + + llvm::FoldingSetNodeID profile; + SymbolDerived::Profile(profile, parentSymbol, R); + void* InsertPos; + SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); + if (!SD) { + SD = (SymExpr*) BPAlloc.Allocate(); + new (SD) SymbolDerived(SymbolCounter, parentSymbol, R); + DataSet.InsertNode(SD, InsertPos); + ++SymbolCounter; + } + + return cast(SD); +} + const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs, - BinaryOperator::Opcode op, + BinaryOperator::Opcode op, const llvm::APSInt& v, QualType t) { llvm::FoldingSetNodeID ID; @@ -133,7 +143,7 @@ const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs, new (data) SymIntExpr(lhs, op, v, t); DataSet.InsertNode(data, InsertPos); } - + return cast(data); } @@ -151,7 +161,7 @@ const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs, new (data) SymSymExpr(lhs, op, rhs, t); DataSet.InsertNode(data, InsertPos); } - + return cast(data); } @@ -159,39 +169,52 @@ QualType SymbolConjured::getType(ASTContext&) const { return T; } + +QualType SymbolDerived::getType(ASTContext& Ctx) const { + return R->getValueType(Ctx); +} + QualType SymbolRegionValue::getType(ASTContext& C) const { if (!T.isNull()) return T; if (const TypedRegion* TR = dyn_cast(R)) return TR->getValueType(C); - + return QualType(); } SymbolManager::~SymbolManager() {} bool SymbolManager::canSymbolicate(QualType T) { - return Loc::IsLocType(T) || T->isIntegerType(); + return Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType()); } void SymbolReaper::markLive(SymbolRef sym) { - TheLiving = F.Add(TheLiving, sym); - TheDead = F.Remove(TheDead, sym); + TheLiving.insert(sym); + TheDead.erase(sym); } bool SymbolReaper::maybeDead(SymbolRef sym) { if (isLive(sym)) return false; - - TheDead = F.Add(TheDead, sym); + + TheDead.insert(sym); return true; } bool SymbolReaper::isLive(SymbolRef sym) { - if (TheLiving.contains(sym)) + if (TheLiving.count(sym)) return true; - + + if (const SymbolDerived *derived = dyn_cast(sym)) { + if (isLive(derived->getParentSymbol())) { + markLive(sym); + return true; + } + return false; + } + // Interogate the symbol. It may derive from an input value to // the analyzed function/method. return isa(sym); diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp index 014ea8255e68..8e7b15862d66 100644 --- a/lib/Analysis/UninitializedValues.cpp +++ b/lib/Analysis/UninitializedValues.cpp @@ -25,21 +25,21 @@ using namespace clang; //===----------------------------------------------------------------------===// // Dataflow initialization logic. -//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// namespace { class VISIBILITY_HIDDEN RegisterDecls - : public CFGRecStmtDeclVisitor { + : public CFGRecStmtDeclVisitor { UninitializedValues::AnalysisDataTy& AD; public: RegisterDecls(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {} - + void VisitVarDecl(VarDecl* VD) { AD.Register(VD); } CFG& getCFG() { return AD.getCFG(); } }; - + } // end anonymous namespace void UninitializedValues::InitializeValues(const CFG& cfg) { @@ -49,25 +49,25 @@ void UninitializedValues::InitializeValues(const CFG& cfg) { //===----------------------------------------------------------------------===// // Transfer functions. -//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// namespace { class VISIBILITY_HIDDEN TransferFuncs : public CFGStmtVisitor { - + UninitializedValues::ValTy V; UninitializedValues::AnalysisDataTy& AD; public: TransferFuncs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {} - + UninitializedValues::ValTy& getVal() { return V; } CFG& getCFG() { return AD.getCFG(); } - + void SetTopValue(UninitializedValues::ValTy& X) { X.setDeclValues(AD); X.resetBlkExprValues(AD); } - + bool VisitDeclRefExpr(DeclRefExpr* DR); bool VisitBinaryOperator(BinaryOperator* B); bool VisitUnaryOperator(UnaryOperator* U); @@ -76,24 +76,24 @@ public: bool VisitDeclStmt(DeclStmt* D); bool VisitConditionalOperator(ConditionalOperator* C); bool BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S); - + bool Visit(Stmt *S); bool BlockStmt_VisitExpr(Expr* E); - + void VisitTerminator(CFGBlock* B) { } }; - + static const bool Initialized = false; -static const bool Uninitialized = true; +static const bool Uninitialized = true; bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) { - + if (VarDecl* VD = dyn_cast(DR->getDecl())) if (VD->isBlockVarDecl()) { - + if (AD.Observer) AD.Observer->ObserveDeclRefExpr(V, AD, DR, VD); - + // Pseudo-hack to prevent cascade of warnings. If an accessed variable // is uninitialized, then we are already going to flag a warning for // this variable, which a "source" of uninitialized values. @@ -103,17 +103,17 @@ bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) { if (AD.FullUninitTaint) return V(VD,AD); } - + return Initialized; } static VarDecl* FindBlockVarDecl(Expr* E) { - + // Blast through casts and parentheses to find any DeclRefExprs that // refer to a block VarDecl. - + if (DeclRefExpr* DR = dyn_cast(E->IgnoreParenCasts())) - if (VarDecl* VD = dyn_cast(DR->getDecl())) + if (VarDecl* VD = dyn_cast(DR->getDecl())) if (VD->isBlockVarDecl()) return VD; return NULL; @@ -136,7 +136,7 @@ bool TransferFuncs::VisitDeclStmt(DeclStmt* S) { for (DeclStmt::decl_iterator I=S->decl_begin(), E=S->decl_end(); I!=E; ++I) { VarDecl *VD = dyn_cast(*I); if (VD && VD->isBlockVarDecl()) { - if (Stmt* I = VD->getInit()) + if (Stmt* I = VD->getInit()) V(VD,AD) = AD.FullUninitTaint ? V(cast(I),AD) : Initialized; else { // Special case for declarations of array types. For things like: @@ -145,20 +145,20 @@ bool TransferFuncs::VisitDeclStmt(DeclStmt* S) { // // we should treat "x" as being initialized, because the variable // "x" really refers to the memory block. Clearly x[1] is - // uninitialized, but expressions like "(char *) x" really do refer to - // an initialized value. This simple dataflow analysis does not reason + // uninitialized, but expressions like "(char *) x" really do refer to + // an initialized value. This simple dataflow analysis does not reason // about the contents of arrays, although it could be potentially // extended to do so if the array were of constant size. if (VD->getType()->isArrayType()) V(VD,AD) = Initialized; - else + else V(VD,AD) = Uninitialized; } } } return Uninitialized; // Value is never consumed. } - + bool TransferFuncs::VisitCallExpr(CallExpr* C) { VisitChildren(C); return Initialized; @@ -172,14 +172,14 @@ bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { return V(VD,AD) = Initialized; break; } - + default: break; } return Visit(U->getSubExpr()); } - + bool TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { // This represents a use of the 'collection' @@ -203,12 +203,12 @@ TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { else return Visit(ElemExpr); } - + V(VD,AD) = Initialized; return Initialized; } - - + + bool TransferFuncs::VisitConditionalOperator(ConditionalOperator* C) { Visit(C->getCond()); @@ -228,21 +228,21 @@ bool TransferFuncs::VisitStmt(Stmt* S) { // or "Initialized" to variables referenced in the other subexpressions. for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I) if (*I && Visit(*I) == Uninitialized) x = Uninitialized; - + return x; } - + bool TransferFuncs::Visit(Stmt *S) { if (AD.isTracked(static_cast(S))) return V(static_cast(S),AD); else return static_cast*>(this)->Visit(S); } bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) { - bool x = static_cast*>(this)->Visit(E); + bool x = static_cast*>(this)->Visit(E); if (AD.isTracked(E)) V(E,AD) = x; return x; } - + } // end anonymous namespace //===----------------------------------------------------------------------===// @@ -255,7 +255,7 @@ bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) { // Merges take the same approach, preferring soundness. At a confluence point, // if any predecessor has a variable marked uninitialized, the value is // uninitialized at the confluence point. -//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// namespace { typedef StmtDeclBitVector_Types::Union Merge; @@ -264,28 +264,28 @@ namespace { //===----------------------------------------------------------------------===// // Uninitialized values checker. Scan an AST and flag variable uses -//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// UninitializedValues_ValueTypes::ObserverTy::~ObserverTy() {} namespace { class VISIBILITY_HIDDEN UninitializedValuesChecker : public UninitializedValues::ObserverTy { - + ASTContext &Ctx; Diagnostic &Diags; llvm::SmallPtrSet AlreadyWarned; - + public: UninitializedValuesChecker(ASTContext &ctx, Diagnostic &diags) : Ctx(ctx), Diags(diags) {} - + virtual void ObserveDeclRefExpr(UninitializedValues::ValTy& V, UninitializedValues::AnalysisDataTy& AD, DeclRefExpr* DR, VarDecl* VD) { assert ( AD.isTracked(VD) && "Unknown VarDecl."); - + if (V(VD,AD) == Uninitialized) if (AlreadyWarned.insert(VD)) Diags.Report(Ctx.getFullLoc(DR->getSourceRange().getBegin()), @@ -297,13 +297,13 @@ public: namespace clang { void CheckUninitializedValues(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags, bool FullUninitTaint) { - + // Compute the uninitialized values information. UninitializedValues U(cfg); U.getAnalysisData().FullUninitTaint = FullUninitTaint; Solver S(U); S.runOnCFG(cfg); - + // Scan for DeclRefExprs that use uninitialized values. UninitializedValuesChecker Observer(Ctx,Diags); U.getAnalysisData().Observer = &Observer; diff --git a/lib/Analysis/ValueManager.cpp b/lib/Analysis/ValueManager.cpp index 724a2e92d744..fe670e79b3b5 100644 --- a/lib/Analysis/ValueManager.cpp +++ b/lib/Analysis/ValueManager.cpp @@ -22,16 +22,16 @@ using namespace llvm; // Utility methods for constructing SVals. //===----------------------------------------------------------------------===// -SVal ValueManager::makeZeroVal(QualType T) { +DefinedOrUnknownSVal ValueManager::makeZeroVal(QualType T) { if (Loc::IsLocType(T)) return makeNull(); if (T->isIntegerType()) return makeIntVal(0, T); - + // FIXME: Handle floats. // FIXME: Handle structs. - return UnknownVal(); + return UnknownVal(); } //===----------------------------------------------------------------------===// @@ -55,71 +55,89 @@ NonLoc ValueManager::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, } -SVal ValueManager::getRegionValueSymbolVal(const MemRegion* R, QualType T) { - SymbolRef sym = SymMgr.getRegionValueSymbol(R, T); - - if (const TypedRegion* TR = dyn_cast(R)) { - if (T.isNull()) - T = TR->getValueType(SymMgr.getContext()); - - // If T is of function pointer type, create a CodeTextRegion wrapping a - // symbol. - if (T->isFunctionPointerType()) { - return loc::MemRegionVal(MemMgr.getCodeTextRegion(sym, T)); - } - - if (Loc::IsLocType(T)) - return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); - - // Only handle integers for now. - if (T->isIntegerType() && T->isScalarType()) - return nonloc::SymbolVal(sym); +SVal ValueManager::convertToArrayIndex(SVal V) { + if (V.isUnknownOrUndef()) + return V; + + // Common case: we have an appropriately sized integer. + if (nonloc::ConcreteInt* CI = dyn_cast(&V)) { + const llvm::APSInt& I = CI->getValue(); + if (I.getBitWidth() == ArrayIndexWidth && I.isSigned()) + return V; } - return UnknownVal(); + return SVator->EvalCastNL(cast(V), ArrayIndexTy); } -SVal ValueManager::getConjuredSymbolVal(const Expr* E, unsigned Count) { - QualType T = E->getType(); - SymbolRef sym = SymMgr.getConjuredSymbol(E, Count); +DefinedOrUnknownSVal ValueManager::getRegionValueSymbolVal(const MemRegion* R, + QualType T) { - // If T is of function pointer type, create a CodeTextRegion wrapping a - // symbol. - if (T->isFunctionPointerType()) { - return loc::MemRegionVal(MemMgr.getCodeTextRegion(sym, T)); + if (T.isNull()) { + const TypedRegion* TR = cast(R); + T = TR->getValueType(SymMgr.getContext()); } + if (!SymbolManager::canSymbolicate(T)) + return UnknownVal(); + + SymbolRef sym = SymMgr.getRegionValueSymbol(R, T); + if (Loc::IsLocType(T)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); - if (T->isIntegerType() && T->isScalarType()) - return nonloc::SymbolVal(sym); - - return UnknownVal(); + return nonloc::SymbolVal(sym); } -SVal ValueManager::getConjuredSymbolVal(const Expr* E, QualType T, - unsigned Count) { +DefinedOrUnknownSVal ValueManager::getConjuredSymbolVal(const void *SymbolTag, + const Expr *E, + unsigned Count) { + QualType T = E->getType(); + + if (!SymbolManager::canSymbolicate(T)) + return UnknownVal(); - SymbolRef sym = SymMgr.getConjuredSymbol(E, T, Count); + SymbolRef sym = SymMgr.getConjuredSymbol(E, Count, SymbolTag); - // If T is of function pointer type, create a CodeTextRegion wrapping a - // symbol. - if (T->isFunctionPointerType()) { - return loc::MemRegionVal(MemMgr.getCodeTextRegion(sym, T)); - } + if (Loc::IsLocType(T)) + return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); + + return nonloc::SymbolVal(sym); +} + +DefinedOrUnknownSVal ValueManager::getConjuredSymbolVal(const void *SymbolTag, + const Expr *E, + QualType T, + unsigned Count) { + + if (!SymbolManager::canSymbolicate(T)) + return UnknownVal(); + + SymbolRef sym = SymMgr.getConjuredSymbol(E, T, Count, SymbolTag); if (Loc::IsLocType(T)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); - if (T->isIntegerType() && T->isScalarType()) - return nonloc::SymbolVal(sym); + return nonloc::SymbolVal(sym); +} + - return UnknownVal(); +DefinedOrUnknownSVal +ValueManager::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol, + const TypedRegion *R) { + QualType T = R->getValueType(R->getContext()); + + if (!SymbolManager::canSymbolicate(T)) + return UnknownVal(); + + SymbolRef sym = SymMgr.getDerivedSymbol(parentSymbol, R); + + if (Loc::IsLocType(T)) + return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); + + return nonloc::SymbolVal(sym); } -SVal ValueManager::getFunctionPointer(const FunctionDecl* FD) { - CodeTextRegion* R - = MemMgr.getCodeTextRegion(FD, Context.getPointerType(FD->getType())); +DefinedSVal ValueManager::getFunctionPointer(const FunctionDecl* FD) { + CodeTextRegion *R = MemMgr.getCodeTextRegion(FD); return loc::MemRegionVal(R); } diff --git a/lib/Basic/Builtins.cpp b/lib/Basic/Builtins.cpp index 6cb5dab53df2..1a3293775ed6 100644 --- a/lib/Basic/Builtins.cpp +++ b/lib/Basic/Builtins.cpp @@ -34,7 +34,7 @@ Builtin::Context::Context(const TargetInfo &Target) { // Get the target specific builtins from the target. TSRecords = 0; NumTSRecords = 0; - Target.getTargetBuiltins(TSRecords, NumTSRecords); + Target.getTargetBuiltins(TSRecords, NumTSRecords); } /// InitializeBuiltins - Mark the identifiers for all the builtins with their @@ -51,13 +51,13 @@ void Builtin::Context::InitializeBuiltins(IdentifierTable &Table, // Step #2: Register target-specific builtins. for (unsigned i = 0, e = NumTSRecords; i != e; ++i) if (!TSRecords[i].Suppressed && - (!NoBuiltins || - (TSRecords[i].Attributes && + (!NoBuiltins || + (TSRecords[i].Attributes && !strchr(TSRecords[i].Attributes, 'f')))) Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin); } -void +void Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl &Names, bool NoBuiltins) { // Final all target-independent names @@ -65,18 +65,18 @@ Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl &Names, if (!BuiltinInfo[i].Suppressed && (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f'))) Names.push_back(BuiltinInfo[i].Name); - + // Find target-specific names. for (unsigned i = 0, e = NumTSRecords; i != e; ++i) if (!TSRecords[i].Suppressed && - (!NoBuiltins || - (TSRecords[i].Attributes && + (!NoBuiltins || + (TSRecords[i].Attributes && !strchr(TSRecords[i].Attributes, 'f')))) Names.push_back(TSRecords[i].Name); } -bool -Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx, +bool +Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg) { const char *Printf = strpbrk(GetRecord(ID).Attributes, "pP"); if (!Printf) diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt index e0e9a10e5195..527ebf965934 100644 --- a/lib/Basic/CMakeLists.txt +++ b/lib/Basic/CMakeLists.txt @@ -11,8 +11,19 @@ add_clang_library(clangBasic TargetInfo.cpp Targets.cpp TokenKinds.cpp + Version.cpp ) +# Determine Subversion revision. +# FIXME: This only gets updated when CMake is run, so this revision number +# may be out-of-date! +find_package(Subversion) +if (Subversion_FOUND) + Subversion_WC_INFO(${CLANG_SOURCE_DIR} CLANG) + set_source_files_properties(Version.cpp + PROPERTIES COMPILE_DEFINITIONS "SVN_REVISION=\"${CLANG_WC_REVISION}\"") +endif() + add_dependencies(clangBasic ClangDiagnosticAnalysis ClangDiagnosticAST diff --git a/lib/Basic/ConvertUTF.c b/lib/Basic/ConvertUTF.c index e5dd3e6bf570..124e386c5526 100644 --- a/lib/Basic/ConvertUTF.c +++ b/lib/Basic/ConvertUTF.c @@ -34,10 +34,10 @@ Author: Mark E. Davis, 1994. Rev History: Rick McGowan, fixes & updates May 2001. Sept 2001: fixed const & error conditions per - mods suggested by S. Parent & A. Lillich. + mods suggested by S. Parent & A. Lillich. June 2002: Tim Dodd added detection and handling of incomplete - source sequences, enhanced error detection, added casts - to eliminate compiler warnings. + source sequences, enhanced error detection, added casts + to eliminate compiler warnings. July 2003: slight mods to back out aggressive FFFE detection. Jan 2004: updated switches in from-UTF8 conversions. Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. @@ -61,8 +61,8 @@ static const UTF32 halfMask = 0x3FFUL; #define UNI_SUR_HIGH_END (UTF32)0xDBFF #define UNI_SUR_LOW_START (UTF32)0xDC00 #define UNI_SUR_LOW_END (UTF32)0xDFFF -#define false 0 -#define true 1 +#define false 0 +#define true 1 /* --------------------------------------------------------------------- */ @@ -90,7 +90,7 @@ static const char trailingBytesForUTF8[256] = { * in a UTF-8 sequence. */ static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, - 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; /* * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed @@ -116,46 +116,46 @@ static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF32toUTF16 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF32* source = *sourceStart; UTF16* target = *targetStart; while (source < sourceEnd) { - UTF32 ch; - if (target >= targetEnd) { - result = targetExhausted; break; - } - ch = *source++; - if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ - /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - if (flags == strictConversion) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - *target++ = (UTF16)ch; /* normal case */ - } - } else if (ch > UNI_MAX_LEGAL_UTF32) { - if (flags == strictConversion) { - result = sourceIllegal; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - /* target is a character in range 0xFFFF - 0x10FFFF. */ - if (target + 1 >= targetEnd) { - --source; /* Back up source pointer! */ - result = targetExhausted; break; - } - ch -= halfBase; - *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); - } + UTF32 ch; + if (target >= targetEnd) { + result = targetExhausted; break; + } + ch = *source++; + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_LEGAL_UTF32) { + if (flags == strictConversion) { + result = sourceIllegal; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + --source; /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } } *sourceStart = source; *targetStart = target; @@ -165,48 +165,48 @@ ConversionResult ConvertUTF32toUTF16 ( /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF16toUTF32 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF16* source = *sourceStart; UTF32* target = *targetStart; UTF32 ch, ch2; while (source < sourceEnd) { - const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ - ch = *source++; - /* If we have a surrogate pair, convert to UTF32 first. */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { - /* If the 16 bits following the high surrogate are in the source buffer... */ - if (source < sourceEnd) { - ch2 = *source; - /* If it's a low surrogate, convert to UTF32. */ - if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { - ch = ((ch - UNI_SUR_HIGH_START) << halfShift) - + (ch2 - UNI_SUR_LOW_START) + halfBase; - ++source; - } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } else { /* We don't have the 16 bits following the high surrogate. */ - --source; /* return to the high surrogate */ - result = sourceExhausted; - break; - } - } else if (flags == strictConversion) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - if (target >= targetEnd) { - source = oldSource; /* Back up source pointer! */ - result = targetExhausted; break; - } - *target++ = ch; + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + if (target >= targetEnd) { + source = oldSource; /* Back up source pointer! */ + result = targetExhausted; break; + } + *target++ = ch; } *sourceStart = source; *targetStart = target; @@ -219,67 +219,67 @@ if (result == sourceIllegal) { return result; } ConversionResult ConvertUTF16toUTF8 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF16* source = *sourceStart; UTF8* target = *targetStart; while (source < sourceEnd) { - UTF32 ch; - unsigned short bytesToWrite = 0; - const UTF32 byteMask = 0xBF; - const UTF32 byteMark = 0x80; - const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ - ch = *source++; - /* If we have a surrogate pair, convert to UTF32 first. */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { - /* If the 16 bits following the high surrogate are in the source buffer... */ - if (source < sourceEnd) { - UTF32 ch2 = *source; - /* If it's a low surrogate, convert to UTF32. */ - if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { - ch = ((ch - UNI_SUR_HIGH_START) << halfShift) - + (ch2 - UNI_SUR_LOW_START) + halfBase; - ++source; - } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } else { /* We don't have the 16 bits following the high surrogate. */ - --source; /* return to the high surrogate */ - result = sourceExhausted; - break; - } - } else if (flags == strictConversion) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - /* Figure out how many bytes the result will require */ - if (ch < (UTF32)0x80) { bytesToWrite = 1; - } else if (ch < (UTF32)0x800) { bytesToWrite = 2; - } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; - } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; - } else { bytesToWrite = 3; - ch = UNI_REPLACEMENT_CHAR; - } - - target += bytesToWrite; - if (target > targetEnd) { - source = oldSource; /* Back up source pointer! */ - target -= bytesToWrite; result = targetExhausted; break; - } - switch (bytesToWrite) { /* note: everything falls through. */ - case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); - } - target += bytesToWrite; + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + UTF32 ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + } + + target += bytesToWrite; + if (target > targetEnd) { + source = oldSource; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; } *sourceStart = source; *targetStart = target; @@ -289,50 +289,50 @@ ConversionResult ConvertUTF16toUTF8 ( /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF32toUTF8 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF32* source = *sourceStart; UTF8* target = *targetStart; while (source < sourceEnd) { - UTF32 ch; - unsigned short bytesToWrite = 0; - const UTF32 byteMask = 0xBF; - const UTF32 byteMark = 0x80; - ch = *source++; - if (flags == strictConversion ) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - /* - * Figure out how many bytes the result will require. Turn any - * illegally large UTF32 things (> Plane 17) into replacement chars. - */ - if (ch < (UTF32)0x80) { bytesToWrite = 1; - } else if (ch < (UTF32)0x800) { bytesToWrite = 2; - } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; - } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; - } else { bytesToWrite = 3; - ch = UNI_REPLACEMENT_CHAR; - result = sourceIllegal; - } - - target += bytesToWrite; - if (target > targetEnd) { - --source; /* Back up source pointer! */ - target -= bytesToWrite; result = targetExhausted; break; - } - switch (bytesToWrite) { /* note: everything falls through. */ - case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); - } - target += bytesToWrite; + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + ch = *source++; + if (flags == strictConversion ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* + * Figure out how many bytes the result will require. Turn any + * illegally large UTF32 things (> Plane 17) into replacement chars. + */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + result = sourceIllegal; + } + + target += bytesToWrite; + if (target > targetEnd) { + --source; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; } *sourceStart = source; *targetStart = target; @@ -342,59 +342,59 @@ ConversionResult ConvertUTF32toUTF8 ( /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF8toUTF32 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF8* source = *sourceStart; UTF32* target = *targetStart; while (source < sourceEnd) { - UTF32 ch = 0; - unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; - if (source + extraBytesToRead >= sourceEnd) { - result = sourceExhausted; break; - } - /* Do this check whether lenient or strict */ - if (!isLegalUTF8(source, extraBytesToRead+1)) { - result = sourceIllegal; - break; - } - /* - * The cases all fall through. See "Note A" below. - */ - switch (extraBytesToRead) { - case 5: ch += *source++; ch <<= 6; - case 4: ch += *source++; ch <<= 6; - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; - } - ch -= offsetsFromUTF8[extraBytesToRead]; - - if (target >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up the source pointer! */ - result = targetExhausted; break; - } - if (ch <= UNI_MAX_LEGAL_UTF32) { - /* - * UTF-16 surrogate values are illegal in UTF-32, and anything - * over Plane 17 (> 0x10FFFF) is illegal. - */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - if (flags == strictConversion) { - source -= (extraBytesToRead+1); /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - *target++ = ch; - } - } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ - result = sourceIllegal; - *target++ = UNI_REPLACEMENT_CHAR; - } + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (!isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; + case 4: ch += *source++; ch <<= 6; + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up the source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_LEGAL_UTF32) { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = ch; + } + } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ + result = sourceIllegal; + *target++ = UNI_REPLACEMENT_CHAR; + } } *sourceStart = source; *targetStart = target; @@ -420,19 +420,19 @@ static Boolean isLegalUTF8(const UTF8 *source, int length) { const UTF8 *srcptr = source+length; switch (length) { default: return false; - /* Everything else falls through when "true"... */ + /* Everything else falls through when "true"... */ case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; case 2: if ((a = (*--srcptr)) > 0xBF) return false; - switch (*source) { - /* no fall-through in this inner switch */ - case 0xE0: if (a < 0xA0) return false; break; - case 0xED: if (a > 0x9F) return false; break; - case 0xF0: if (a < 0x90) return false; break; - case 0xF4: if (a > 0x8F) return false; break; - default: if (a < 0x80) return false; - } + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return false; break; + case 0xED: if (a > 0x9F) return false; break; + case 0xF0: if (a < 0x90) return false; break; + case 0xF4: if (a > 0x8F) return false; break; + default: if (a < 0x80) return false; + } case 1: if (*source >= 0x80 && *source < 0xC2) return false; } @@ -449,7 +449,7 @@ static Boolean isLegalUTF8(const UTF8 *source, int length) { Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { int length = trailingBytesForUTF8[*source]+1; if (source+length > sourceEnd) { - return false; + return false; } return isLegalUTF8(source, length); } @@ -457,70 +457,70 @@ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF8toUTF16 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF8* source = *sourceStart; UTF16* target = *targetStart; while (source < sourceEnd) { - UTF32 ch = 0; - unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; - if (source + extraBytesToRead >= sourceEnd) { - result = sourceExhausted; break; - } - /* Do this check whether lenient or strict */ - if (!isLegalUTF8(source, extraBytesToRead+1)) { - result = sourceIllegal; - break; - } - /* - * The cases all fall through. See "Note A" below. - */ - switch (extraBytesToRead) { - case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ - case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; - } - ch -= offsetsFromUTF8[extraBytesToRead]; - - if (target >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up source pointer! */ - result = targetExhausted; break; - } - if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - if (flags == strictConversion) { - source -= (extraBytesToRead+1); /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - *target++ = (UTF16)ch; /* normal case */ - } - } else if (ch > UNI_MAX_UTF16) { - if (flags == strictConversion) { - result = sourceIllegal; - source -= (extraBytesToRead+1); /* return to the start */ - break; /* Bail out; shouldn't continue */ - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - /* target is a character in range 0xFFFF - 0x10FFFF. */ - if (target + 1 >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up source pointer! */ - result = targetExhausted; break; - } - ch -= halfBase; - *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); - } + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (!isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_UTF16) { + if (flags == strictConversion) { + result = sourceIllegal; + source -= (extraBytesToRead+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } } *sourceStart = source; *targetStart = target; @@ -533,14 +533,14 @@ ConversionResult ConvertUTF8toUTF16 ( The fall-through switches in UTF-8 reading code save a temp variable, some decrements & conditionals. The switches are equivalent to the following loop: - { - int tmpBytesToRead = extraBytesToRead+1; - do { - ch += *source++; - --tmpBytesToRead; - if (tmpBytesToRead) ch <<= 6; - } while (tmpBytesToRead > 0); - } + { + int tmpBytesToRead = extraBytesToRead+1; + do { + ch += *source++; + --tmpBytesToRead; + if (tmpBytesToRead) ch <<= 6; + } while (tmpBytesToRead > 0); + } In UTF-8 writing code, the switches on "bytesToWrite" are similarly unrolled loops. diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 78b8b0a85597..4a29997a2ccc 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -49,7 +49,7 @@ struct StaticDiagInfoRec { bool SFINAE : 1; const char *Description; const char *OptionGroup; - + bool operator<(const StaticDiagInfoRec &RHS) const { return DiagID < RHS.DiagID; } @@ -88,16 +88,16 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) { IsFirst = false; } #endif - + // Search the diagnostic table with a binary search. StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0 }; - + const StaticDiagInfoRec *Found = std::lower_bound(StaticDiagInfo, StaticDiagInfo + NumDiagEntries, Find); if (Found == StaticDiagInfo + NumDiagEntries || Found->DiagID != DiagID) return 0; - + return Found; } @@ -141,7 +141,7 @@ namespace clang { std::vector DiagInfo; std::map DiagIDs; public: - + /// getDescription - Return the description of the specified custom /// diagnostic. const char *getDescription(unsigned DiagID) const { @@ -149,14 +149,14 @@ namespace clang { "Invalid diagnosic ID"); return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second.c_str(); } - + /// getLevel - Return the level of the specified custom diagnostic. Diagnostic::Level getLevel(unsigned DiagID) const { assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() && "Invalid diagnosic ID"); return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first; } - + unsigned getOrCreateDiagID(Diagnostic::Level L, const char *Message, Diagnostic &Diags) { DiagDesc D(L, Message); @@ -164,7 +164,7 @@ namespace clang { std::map::iterator I = DiagIDs.lower_bound(D); if (I != DiagIDs.end() && I->first == D) return I->second; - + // If not, assign a new ID. unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT; DiagIDs.insert(std::make_pair(D, ID)); @@ -172,9 +172,9 @@ namespace clang { return ID; } }; - - } // end diag namespace -} // end clang namespace + + } // end diag namespace +} // end clang namespace //===----------------------------------------------------------------------===// @@ -196,32 +196,48 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) { IgnoreAllWarnings = false; WarningsAsErrors = false; SuppressSystemWarnings = false; + SuppressAllDiagnostics = false; ExtBehavior = Ext_Ignore; - + ErrorOccurred = false; FatalErrorOccurred = false; NumDiagnostics = 0; + NumErrors = 0; CustomDiagInfo = 0; CurDiagID = ~0U; LastDiagLevel = Ignored; - + ArgToStringFn = DummyArgToStringFn; ArgToStringCookie = 0; - + // Set all mappings to 'unset'. - memset(DiagMappings, 0, sizeof(DiagMappings)); + DiagMappings BlankDiags(diag::DIAG_UPPER_LIMIT/2, 0); + DiagMappingsStack.push_back(BlankDiags); } Diagnostic::~Diagnostic() { delete CustomDiagInfo; } + +void Diagnostic::pushMappings() { + DiagMappingsStack.push_back(DiagMappingsStack.back()); +} + +bool Diagnostic::popMappings() { + if (DiagMappingsStack.size() == 1) + return false; + + DiagMappingsStack.pop_back(); + return true; +} + /// getCustomDiagID - Return an ID for a diagnostic with the specified message /// and level. If this is the first request for this diagnosic, it is /// registered and created, otherwise the existing ID is returned. unsigned Diagnostic::getCustomDiagID(Level L, const char *Message) { - if (CustomDiagInfo == 0) + if (CustomDiagInfo == 0) CustomDiagInfo = new diag::CustomDiagInfo(); return CustomDiagInfo->getOrCreateDiagID(L, Message, *this); } @@ -267,7 +283,7 @@ Diagnostic::Level Diagnostic::getDiagnosticLevel(unsigned DiagID) const { // Handle custom diagnostics, which cannot be mapped. if (DiagID >= diag::DIAG_UPPER_LIMIT) return CustomDiagInfo->getLevel(DiagID); - + unsigned DiagClass = getBuiltinDiagClass(DiagID); assert(DiagClass != CLASS_NOTE && "Cannot get diagnostic level of a note!"); return getDiagnosticLevel(DiagID, DiagClass); @@ -281,14 +297,14 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const { // Specific non-error diagnostics may be mapped to various levels from ignored // to error. Errors can only be mapped to fatal. Diagnostic::Level Result = Diagnostic::Fatal; - + // Get the mapping information, if unset, compute it lazily. unsigned MappingInfo = getDiagnosticMappingInfo((diag::kind)DiagID); if (MappingInfo == 0) { MappingInfo = GetDefaultDiagMapping(DiagID); setDiagnosticMappingInternal(DiagID, MappingInfo, false); } - + switch (MappingInfo & 7) { default: assert(0 && "Unknown mapping!"); case diag::MAP_IGNORE: @@ -311,29 +327,29 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const { // If warnings are globally mapped to ignore or error, do it. if (IgnoreAllWarnings) return Diagnostic::Ignored; - + Result = Diagnostic::Warning; - + // If this is an extension diagnostic and we're in -pedantic-error mode, and // if the user didn't explicitly map it, upgrade to an error. if (ExtBehavior == Ext_Error && (MappingInfo & 8) == 0 && isBuiltinExtensionDiag(DiagID)) Result = Diagnostic::Error; - + if (WarningsAsErrors) Result = Diagnostic::Error; break; - + case diag::MAP_WARNING_NO_WERROR: // Diagnostics specified with -Wno-error=foo should be set to warnings, but // not be adjusted by -Werror or -pedantic-errors. Result = Diagnostic::Warning; - + // If warnings are globally mapped to ignore or error, do it. if (IgnoreAllWarnings) return Diagnostic::Ignored; - + break; } @@ -342,7 +358,7 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const { // block, silence it. if (AllExtensionsSilenced && isBuiltinExtensionDiag(DiagID)) return Diagnostic::Ignored; - + return Result; } @@ -377,7 +393,7 @@ static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping, for (; *Member != -1; ++Member) Diags.setDiagnosticMapping(*Member, Mapping); } - + // Enable/disable all subgroups along with this one. if (const char *SubGroups = Group->SubGroups) { for (; *SubGroups != (char)-1; ++SubGroups) @@ -390,7 +406,7 @@ static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping, /// ignores the request if "Group" was unknown, false otherwise. bool Diagnostic::setDiagnosticGroupMapping(const char *Group, diag::Mapping Map) { - + WarningOption Key = { Group, 0, 0 }; const WarningOption *Found = std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key, @@ -398,7 +414,7 @@ bool Diagnostic::setDiagnosticGroupMapping(const char *Group, if (Found == OptionTable + OptionTableSize || strcmp(Found->Name, Group) != 0) return true; // Option not found. - + MapGroupMembers(Found, Map, *this); return false; } @@ -408,19 +424,22 @@ bool Diagnostic::setDiagnosticGroupMapping(const char *Group, /// finally fully formed. bool Diagnostic::ProcessDiag() { DiagnosticInfo Info(this); - + + if (SuppressAllDiagnostics) + return false; + // Figure out the diagnostic level of this message. Diagnostic::Level DiagLevel; unsigned DiagID = Info.getID(); - + // ShouldEmitInSystemHeader - True if this diagnostic should be produced even // in a system header. bool ShouldEmitInSystemHeader; - + if (DiagID >= diag::DIAG_UPPER_LIMIT) { // Handle custom diagnostics, which cannot be mapped. DiagLevel = CustomDiagInfo->getLevel(DiagID); - + // Custom diagnostics always are emitted in system headers. ShouldEmitInSystemHeader = true; } else { @@ -432,12 +451,12 @@ bool Diagnostic::ProcessDiag() { DiagLevel = Diagnostic::Note; ShouldEmitInSystemHeader = false; // extra consideration is needed } else { - // If this is not an error and we are in a system header, we ignore it. + // If this is not an error and we are in a system header, we ignore it. // Check the original Diag ID here, because we also want to ignore // extensions and warnings in -Werror and -pedantic-errors modes, which // *map* warnings/extensions to errors. ShouldEmitInSystemHeader = DiagClass == CLASS_ERROR; - + DiagLevel = getDiagnosticLevel(DiagID, DiagClass); } } @@ -451,7 +470,7 @@ bool Diagnostic::ProcessDiag() { FatalErrorOccurred = true; LastDiagLevel = DiagLevel; - } + } // If a fatal error has already been emitted, silence all subsequent // diagnostics. @@ -478,7 +497,7 @@ bool Diagnostic::ProcessDiag() { ErrorOccurred = true; ++NumErrors; } - + // Finally, report it. Client->HandleDiagnostic(DiagLevel, Info); if (Client->IncludeInDiagnosticCounts()) ++NumDiagnostics; @@ -508,7 +527,7 @@ static void HandleSelectModifier(unsigned ValNo, const char *Argument, unsigned ArgumentLen, llvm::SmallVectorImpl &OutStr) { const char *ArgumentEnd = Argument+ArgumentLen; - + // Skip over 'ValNo' |'s. while (ValNo) { const char *NextVal = std::find(Argument, ArgumentEnd, '|'); @@ -517,7 +536,7 @@ static void HandleSelectModifier(unsigned ValNo, Argument = NextVal+1; // Skip this string. --ValNo; } - + // Get the end of the value. This is either the } or the |. const char *EndPtr = std::find(Argument, ArgumentEnd, '|'); // Add the value to the output string. @@ -590,7 +609,7 @@ static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) { // Scan for next or-expr part. Start = std::find(Start, End, ','); - if(Start == End) + if (Start == End) break; ++Start; } @@ -659,7 +678,7 @@ void DiagnosticInfo:: FormatDiagnostic(llvm::SmallVectorImpl &OutStr) const { const char *DiagStr = getDiags()->getDescription(getID()); const char *DiagEnd = DiagStr+strlen(DiagStr); - + while (DiagStr != DiagEnd) { if (DiagStr[0] != '%') { // Append non-%0 substrings to Str if we have one. @@ -672,10 +691,10 @@ FormatDiagnostic(llvm::SmallVectorImpl &OutStr) const { DiagStr += 2; continue; } - + // Skip the %. ++DiagStr; - + // This must be a placeholder for a diagnostic argument. The format for a // placeholder is one of "%0", "%modifier0", or "%modifier{arguments}0". // The digit is a number from 0-9 indicating which argument this comes from. @@ -683,7 +702,7 @@ FormatDiagnostic(llvm::SmallVectorImpl &OutStr) const { // brace enclosed string. const char *Modifier = 0, *Argument = 0; unsigned ModifierLen = 0, ArgumentLen = 0; - + // Check to see if we have a modifier. If so eat it. if (!isdigit(DiagStr[0])) { Modifier = DiagStr; @@ -696,14 +715,14 @@ FormatDiagnostic(llvm::SmallVectorImpl &OutStr) const { if (DiagStr[0] == '{') { ++DiagStr; // Skip {. Argument = DiagStr; - + for (; DiagStr[0] != '}'; ++DiagStr) assert(DiagStr[0] && "Mismatched {}'s in diagnostic string!"); ArgumentLen = DiagStr-Argument; ++DiagStr; // Skip }. } } - + assert(isdigit(*DiagStr) && "Invalid format for argument in diagnostic"); unsigned ArgNo = *DiagStr++ - '0'; @@ -722,14 +741,14 @@ FormatDiagnostic(llvm::SmallVectorImpl &OutStr) const { // Don't crash if get passed a null pointer by accident. if (!S) S = "(null)"; - + OutStr.append(S, S + strlen(S)); break; } // ---- INTEGERS ---- case Diagnostic::ak_sint: { int Val = getArgSInt(ArgNo); - + if (ModifierIs(Modifier, ModifierLen, "select")) { HandleSelectModifier((unsigned)Val, Argument, ArgumentLen, OutStr); } else if (ModifierIs(Modifier, ModifierLen, "s")) { @@ -746,7 +765,7 @@ FormatDiagnostic(llvm::SmallVectorImpl &OutStr) const { } case Diagnostic::ak_uint: { unsigned Val = getArgUInt(ArgNo); - + if (ModifierIs(Modifier, ModifierLen, "select")) { HandleSelectModifier(Val, Argument, ArgumentLen, OutStr); } else if (ModifierIs(Modifier, ModifierLen, "s")) { @@ -755,7 +774,7 @@ FormatDiagnostic(llvm::SmallVectorImpl &OutStr) const { HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr); } else { assert(ModifierLen == 0 && "Unknown integer modifier"); - + // FIXME: Optimize std::string S = llvm::utostr_32(Val); OutStr.append(S.begin(), S.end()); @@ -782,6 +801,8 @@ FormatDiagnostic(llvm::SmallVectorImpl &OutStr) const { case Diagnostic::ak_qualtype: case Diagnostic::ak_declarationname: case Diagnostic::ak_nameddecl: + case Diagnostic::ak_nestednamespec: + case Diagnostic::ak_declcontext: getDiags()->ConvertArgToString(getArgKind(ArgNo), getRawArg(ArgNo), Modifier, ModifierLen, Argument, ArgumentLen, OutStr); diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index cc25d3305158..df86f9d04702 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -19,9 +19,12 @@ #include "clang/Basic/FileManager.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" -#include "llvm/Support/Streams.h" #include "llvm/Config/config.h" +#include +#include +#include using namespace clang; // FIXME: Enhance libsystem to support inode and other fields. @@ -44,8 +47,7 @@ using namespace clang; #define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/' || (x) == '\\') namespace { - static std::string GetFullPath(const char *relPath) - { + static std::string GetFullPath(const char *relPath) { char *absPathStrPtr = _fullpath(NULL, relPath, 0); assert(absPathStrPtr && "_fullpath() returned NULL!"); @@ -59,7 +61,7 @@ namespace { class FileManager::UniqueDirContainer { /// UniqueDirs - Cache from full path to existing directories/files. /// - llvm::StringMap UniqueDirs; + llvm::StringMap UniqueDirs; public: DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) { @@ -69,7 +71,7 @@ public: FullPath.c_str() + FullPath.size() ).getValue(); } - + size_t size() { return UniqueDirs.size(); } }; @@ -101,7 +103,7 @@ public: class FileManager::UniqueDirContainer { /// UniqueDirs - Cache from ID's to existing directories/files. /// - std::map, DirectoryEntry> UniqueDirs; + std::map, DirectoryEntry> UniqueDirs; public: DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) { @@ -149,27 +151,27 @@ FileManager::~FileManager() { /// getDirectory - Lookup, cache, and verify the specified directory. This /// returns null if the directory doesn't exist. -/// +/// const DirectoryEntry *FileManager::getDirectory(const char *NameStart, const char *NameEnd) { ++NumDirLookups; llvm::StringMapEntry &NamedDirEnt = DirEntries.GetOrCreateValue(NameStart, NameEnd); - + // See if there is already an entry in the map. if (NamedDirEnt.getValue()) return NamedDirEnt.getValue() == NON_EXISTENT_DIR ? 0 : NamedDirEnt.getValue(); - + ++NumDirCacheMisses; - + // By default, initialize it to invalid. NamedDirEnt.setValue(NON_EXISTENT_DIR); - + // Get the null-terminated directory name as stored as the key of the // DirEntries map. const char *InterndDirName = NamedDirEnt.getKeyData(); - + // Check to see if the directory exists. struct stat StatBuf; if (stat_cached(InterndDirName, &StatBuf) || // Error stat'ing. @@ -177,13 +179,13 @@ const DirectoryEntry *FileManager::getDirectory(const char *NameStart, return 0; // It exists. See if we have already opened a directory with the same inode. - // This occurs when one dir is symlinked to another, for example. + // This occurs when one dir is symlinked to another, for example. DirectoryEntry &UDE = UniqueDirs.getDirectory(InterndDirName, StatBuf); - + NamedDirEnt.setValue(&UDE); if (UDE.getName()) // Already have an entry with this inode, return it. return &UDE; - + // Otherwise, we don't have this directory yet, add it. We use the string // key from the DirEntries map as the string. UDE.Name = InterndDirName; @@ -196,11 +198,11 @@ const DirectoryEntry *FileManager::getDirectory(const char *NameStart, /// getFile - Lookup, cache, and verify the specified file. This returns null /// if the file doesn't exist. -/// +/// const FileEntry *FileManager::getFile(const char *NameStart, const char *NameEnd) { ++NumFileLookups; - + // See if there is already an entry in the map. llvm::StringMapEntry &NamedFileEnt = FileEntries.GetOrCreateValue(NameStart, NameEnd); @@ -209,7 +211,7 @@ const FileEntry *FileManager::getFile(const char *NameStart, if (NamedFileEnt.getValue()) return NamedFileEnt.getValue() == NON_EXISTENT_FILE ? 0 : NamedFileEnt.getValue(); - + ++NumFileCacheMisses; // By default, initialize it to invalid. @@ -221,7 +223,10 @@ const FileEntry *FileManager::getFile(const char *NameStart, const char *SlashPos = NameEnd-1; while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0])) --SlashPos; - + // Ignore duplicate //'s. + while (SlashPos > NameStart && IS_DIR_SEPARATOR_CHAR(SlashPos[-1])) + --SlashPos; + const DirectoryEntry *DirInfo; if (SlashPos < NameStart) { // Use the current directory if file has no path component. @@ -231,32 +236,32 @@ const FileEntry *FileManager::getFile(const char *NameStart, return 0; // If filename ends with a /, it's a directory. else DirInfo = getDirectory(NameStart, SlashPos); - + if (DirInfo == 0) // Directory doesn't exist, file can't exist. return 0; - + // Get the null-terminated file name as stored as the key of the // FileEntries map. const char *InterndFileName = NamedFileEnt.getKeyData(); - + // FIXME: Use the directory info to prune this, before doing the stat syscall. // FIXME: This will reduce the # syscalls. - + // Nope, there isn't. Check to see if the file exists. struct stat StatBuf; - //llvm::cerr << "STATING: " << Filename; + //llvm::errs() << "STATING: " << Filename; if (stat_cached(InterndFileName, &StatBuf) || // Error stat'ing. S_ISDIR(StatBuf.st_mode)) { // A directory? // If this file doesn't exist, we leave a null in FileEntries for this path. - //llvm::cerr << ": Not existing\n"; + //llvm::errs() << ": Not existing\n"; return 0; } - //llvm::cerr << ": exists\n"; - + //llvm::errs() << ": exists\n"; + // It exists. See if we have already opened a file with the same inode. // This occurs when one dir is symlinked to another, for example. FileEntry &UFE = UniqueFiles.getFile(InterndFileName, StatBuf); - + NamedFileEnt.setValue(&UFE); if (UFE.getName()) // Already have an entry with this inode, return it. return &UFE; @@ -273,23 +278,24 @@ const FileEntry *FileManager::getFile(const char *NameStart, } void FileManager::PrintStats() const { - llvm::cerr << "\n*** File Manager Stats:\n"; - llvm::cerr << UniqueFiles.size() << " files found, " - << UniqueDirs.size() << " dirs found.\n"; - llvm::cerr << NumDirLookups << " dir lookups, " - << NumDirCacheMisses << " dir cache misses.\n"; - llvm::cerr << NumFileLookups << " file lookups, " - << NumFileCacheMisses << " file cache misses.\n"; - - //llvm::cerr << PagesMapped << BytesOfPagesMapped << FSLookups; + llvm::errs() << "\n*** File Manager Stats:\n"; + llvm::errs() << UniqueFiles.size() << " files found, " + << UniqueDirs.size() << " dirs found.\n"; + llvm::errs() << NumDirLookups << " dir lookups, " + << NumDirCacheMisses << " dir cache misses.\n"; + llvm::errs() << NumFileLookups << " file lookups, " + << NumFileCacheMisses << " file cache misses.\n"; + + //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups; } int MemorizeStatCalls::stat(const char *path, struct stat *buf) { int result = ::stat(path, buf); - - if (result != 0) { + + if (result != 0) { // Cache failed 'stat' results. struct stat empty; + memset(&empty, 0, sizeof(empty)); StatCalls[path] = StatResult(result, empty); } else if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute()) { @@ -297,6 +303,6 @@ int MemorizeStatCalls::stat(const char *path, struct stat *buf) { // paths. StatCalls[path] = StatResult(result, *buf); } - - return result; + + return result; } diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 3810c49f71f3..93c260fdbe17 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -109,9 +109,9 @@ static void AddCXXOperatorKeyword(const char *Keyword, unsigned KWLen, Info.setIsCPlusPlusOperatorKeyword(); } -/// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or +/// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or /// "property". -static void AddObjCKeyword(tok::ObjCKeywordKind ObjCID, +static void AddObjCKeyword(tok::ObjCKeywordKind ObjCID, const char *Name, unsigned NameLen, IdentifierTable &Table) { Table.get(Name, Name+NameLen).setObjCKeywordID(ObjCID); @@ -144,13 +144,13 @@ tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { // the first and third character. For preprocessor ID's there are no // collisions (if there were, the switch below would complain about duplicate // case values). Note that this depends on 'if' being null terminated. - + #define HASH(LEN, FIRST, THIRD) \ (LEN << 5) + (((FIRST-'a') + (THIRD-'a')) & 31) #define CASE(LEN, FIRST, THIRD, NAME) \ case HASH(LEN, FIRST, THIRD): \ return memcmp(Name, #NAME, LEN) ? tok::pp_not_keyword : tok::pp_ ## NAME - + unsigned Len = getLength(); if (Len < 2) return tok::pp_not_keyword; const char *Name = getName(); @@ -179,7 +179,7 @@ tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { CASE( 8, 'u', 'a', unassert); CASE(12, 'i', 'c', include_next); - + CASE(16, '_', 'i', __include_macros); #undef CASE #undef HASH @@ -198,7 +198,7 @@ void IdentifierTable::PrintStats() const { unsigned NumEmptyBuckets = NumBuckets-NumIdentifiers; unsigned AverageIdentifierSize = 0; unsigned MaxIdentifierLength = 0; - + // TODO: Figure out maximum times an identifier had to probe for -stats. for (llvm::StringMap::const_iterator I = HashTable.begin(), E = HashTable.end(); I != E; ++I) { @@ -207,7 +207,7 @@ void IdentifierTable::PrintStats() const { if (MaxIdentifierLength < IdLen) MaxIdentifierLength = IdLen; } - + fprintf(stderr, "\n*** Identifier Table Stats:\n"); fprintf(stderr, "# Identifiers: %d\n", NumIdentifiers); fprintf(stderr, "# Empty Buckets: %d\n", NumEmptyBuckets); @@ -216,7 +216,7 @@ void IdentifierTable::PrintStats() const { fprintf(stderr, "Ave identifier length: %f\n", (AverageIdentifierSize/(double)NumIdentifiers)); fprintf(stderr, "Max identifier length: %d\n", MaxIdentifierLength); - + // Compute statistics about the memory allocated for identifiers. HashTable.getAllocator().PrintStats(); } @@ -232,42 +232,42 @@ unsigned llvm::DenseMapInfo::getHashValue(clang::Selector S) { namespace clang { /// MultiKeywordSelector - One of these variable length records is kept for each /// selector containing more than one keyword. We use a folding set -/// to unique aggregate names (keyword selectors in ObjC parlance). Access to +/// to unique aggregate names (keyword selectors in ObjC parlance). Access to /// this class is provided strictly through Selector. -class MultiKeywordSelector +class MultiKeywordSelector : public DeclarationNameExtra, public llvm::FoldingSetNode { MultiKeywordSelector(unsigned nKeys) { ExtraKindOrNumArgs = NUM_EXTRA_KINDS + nKeys; } -public: +public: // Constructor for keyword selectors. MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) { assert((nKeys > 1) && "not a multi-keyword selector"); ExtraKindOrNumArgs = NUM_EXTRA_KINDS + nKeys; - + // Fill in the trailing keyword array. IdentifierInfo **KeyInfo = reinterpret_cast(this+1); for (unsigned i = 0; i != nKeys; ++i) KeyInfo[i] = IIV[i]; - } - + } + // getName - Derive the full selector name and return it. std::string getName() const; - + unsigned getNumArgs() const { return ExtraKindOrNumArgs - NUM_EXTRA_KINDS; } - + typedef IdentifierInfo *const *keyword_iterator; keyword_iterator keyword_begin() const { return reinterpret_cast(this+1); } - keyword_iterator keyword_end() const { - return keyword_begin()+getNumArgs(); + keyword_iterator keyword_end() const { + return keyword_begin()+getNumArgs(); } IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const { assert(i < getNumArgs() && "getIdentifierInfoForSlot(): illegal index"); return keyword_begin()[i]; } - static void Profile(llvm::FoldingSetNodeID &ID, + static void Profile(llvm::FoldingSetNodeID &ID, keyword_iterator ArgTys, unsigned NumArgs) { ID.AddInteger(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) @@ -287,7 +287,7 @@ unsigned Selector::getNumArgs() const { return 1; // We point to a MultiKeywordSelector (pointer doesn't contain any flags). MultiKeywordSelector *SI = reinterpret_cast(InfoPtr); - return SI->getNumArgs(); + return SI->getNumArgs(); } IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const { @@ -308,16 +308,16 @@ std::string MultiKeywordSelector::getName() const { Length += (*I)->getLength(); ++Length; // : } - + Result.reserve(Length); - + for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) { if (*I) Result.insert(Result.end(), (*I)->getName(), (*I)->getName()+(*I)->getLength()); Result.push_back(':'); } - + return Result; } @@ -327,7 +327,7 @@ std::string Selector::getAsString() const { if (InfoPtr & ArgFlags) { IdentifierInfo *II = getAsIdentifierInfo(); - + // If the number of arguments is 0 then II is guaranteed to not be null. if (getNumArgs() == 0) return II->getName(); @@ -336,7 +336,7 @@ std::string Selector::getAsString() const { Res += ":"; return Res; } - + // We have a multiple keyword selector (no embedded flags). return reinterpret_cast(InfoPtr)->getName(); } @@ -357,9 +357,9 @@ static SelectorTableImpl &getSelectorTableImpl(void *P) { Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) { if (nKeys < 2) return Selector(IIV[0], nKeys); - + SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl); - + // Unique selector, to guarantee there is one per name. llvm::FoldingSetNodeID ID; MultiKeywordSelector::Profile(ID, IIV, nKeys); @@ -368,12 +368,12 @@ Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) { if (MultiKeywordSelector *SI = SelTabImpl.Table.FindNodeOrInsertPos(ID, InsertPos)) return Selector(SI); - + // MultiKeywordSelector objects are not allocated with new because they have a // variable size array (for parameter types) at the end of them. unsigned Size = sizeof(MultiKeywordSelector) + nKeys*sizeof(IdentifierInfo *); MultiKeywordSelector *SI = - (MultiKeywordSelector*)SelTabImpl.Allocator.Allocate(Size, + (MultiKeywordSelector*)SelTabImpl.Allocator.Allocate(Size, llvm::alignof()); new (SI) MultiKeywordSelector(nKeys, IIV); SelTabImpl.Table.InsertNode(SI, InsertPos); diff --git a/lib/Basic/Makefile b/lib/Basic/Makefile index 3fd6c2c15384..5bd4314f45cd 100644 --- a/lib/Basic/Makefile +++ b/lib/Basic/Makefile @@ -20,3 +20,14 @@ CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include include $(LEVEL)/Makefile.common +SVN_REVISION := $(shell cd $(PROJ_SRC_DIR)/../.. && svnversion) + +CPP.Defines += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include \ + -DSVN_REVISION='"$(SVN_REVISION)"' + +$(ObjDir)/.ver-svn .ver: $(ObjDir)/.dir + @if [ '$(SVN_REVISION)' != '$(shell cat $(ObjDir)/.ver-svn 2>/dev/null)' ]; then\ + echo '$(SVN_REVISION)' > $(ObjDir)/.ver-svn; \ + fi +$(ObjDir)/.ver-svn: .ver +$(ObjDir)/Version.o: $(ObjDir)/.ver-svn diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp index f21ec8b1e9d7..578a4eb34bab 100644 --- a/lib/Basic/SourceLocation.cpp +++ b/lib/Basic/SourceLocation.cpp @@ -40,7 +40,7 @@ void SourceLocation::print(llvm::raw_ostream &OS, const SourceManager &SM)const{ OS << ""; return; } - + if (isFileID()) { PresumedLoc PLoc = SM.getPresumedLoc(*this); // The instantiation and spelling pos is identical for file locs. @@ -48,7 +48,7 @@ void SourceLocation::print(llvm::raw_ostream &OS, const SourceManager &SM)const{ << ':' << PLoc.getColumn(); return; } - + SM.getInstantiationLoc(*this).print(OS, SM); OS << " -#include using namespace clang; using namespace SrcMgr; using llvm::MemoryBuffer; @@ -42,29 +41,74 @@ unsigned ContentCache::getSizeBytesMapped() const { /// getSize - Returns the size of the content encapsulated by this ContentCache. /// This can be the size of the source file or the size of an arbitrary /// scratch buffer. If the ContentCache encapsulates a source file, that -/// file is not lazily brought in from disk to satisfy this query. +/// file is not lazily brought in from disk to satisfy this query unless it +/// needs to be truncated due to a truncateAt() call. unsigned ContentCache::getSize() const { - return Entry ? Entry->getSize() : Buffer->getBufferSize(); + return Buffer ? Buffer->getBufferSize() : Entry->getSize(); } -const llvm::MemoryBuffer *ContentCache::getBuffer() const { +const llvm::MemoryBuffer *ContentCache::getBuffer() const { // Lazily create the Buffer for ContentCaches that wrap files. if (!Buffer && Entry) { // FIXME: Should we support a way to not have to do this check over // and over if we cannot open the file? Buffer = MemoryBuffer::getFile(Entry->getName(), 0, Entry->getSize()); + if (isTruncated()) + const_cast(this)->truncateAt(TruncateAtLine, + TruncateAtColumn); } return Buffer; } +void ContentCache::truncateAt(unsigned Line, unsigned Column) { + TruncateAtLine = Line; + TruncateAtColumn = Column; + + if (!isTruncated() || !Buffer) + return; + + // Find the byte position of the truncation point. + const char *Position = Buffer->getBufferStart(); + for (unsigned Line = 1; Line < TruncateAtLine; ++Line) { + for (; *Position; ++Position) { + if (*Position != '\r' && *Position != '\n') + continue; + + // Eat \r\n or \n\r as a single line. + if ((Position[1] == '\r' || Position[1] == '\n') && + Position[0] != Position[1]) + ++Position; + ++Position; + break; + } + } + + for (unsigned Column = 1; Column < TruncateAtColumn; ++Column, ++Position) { + if (!*Position) + break; + + if (*Position == '\t') + Column += 7; + } + + // Truncate the buffer. + if (Position != Buffer->getBufferEnd()) { + MemoryBuffer *TruncatedBuffer + = MemoryBuffer::getMemBufferCopy(Buffer->getBufferStart(), Position, + Buffer->getBufferIdentifier()); + delete Buffer; + Buffer = TruncatedBuffer; + } +} + unsigned LineTableInfo::getLineTableFilenameID(const char *Ptr, unsigned Len) { // Look up the filename in the string table, returning the pre-existing value // if it exists. - llvm::StringMapEntry &Entry = + llvm::StringMapEntry &Entry = FilenameIDs.GetOrCreateValue(Ptr, Ptr+Len, ~0U); if (Entry.getValue() != ~0U) return Entry.getValue(); - + // Otherwise, assign this the next available ID. Entry.setValue(FilenamesByID.size()); FilenamesByID.push_back(&Entry); @@ -77,25 +121,25 @@ unsigned LineTableInfo::getLineTableFilenameID(const char *Ptr, unsigned Len) { void LineTableInfo::AddLineNote(unsigned FID, unsigned Offset, unsigned LineNo, int FilenameID) { std::vector &Entries = LineEntries[FID]; - + assert((Entries.empty() || Entries.back().FileOffset < Offset) && "Adding line entries out of order!"); - + SrcMgr::CharacteristicKind Kind = SrcMgr::C_User; unsigned IncludeOffset = 0; - + if (!Entries.empty()) { // If this is a '#line 4' after '#line 42 "foo.h"', make sure to remember // that we are still in "foo.h". if (FilenameID == -1) FilenameID = Entries.back().FilenameID; - + // If we are after a line marker that switched us to system header mode, or // that set #include information, preserve it. Kind = Entries.back().FileKind; IncludeOffset = Entries.back().IncludeOffset; } - + Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, Kind, IncludeOffset)); } @@ -110,9 +154,9 @@ void LineTableInfo::AddLineNote(unsigned FID, unsigned Offset, unsigned EntryExit, SrcMgr::CharacteristicKind FileKind) { assert(FilenameID != -1 && "Unspecified filename should use other accessor"); - + std::vector &Entries = LineEntries[FID]; - + assert((Entries.empty() || Entries.back().FileOffset < Offset) && "Adding line entries out of order!"); @@ -124,14 +168,14 @@ void LineTableInfo::AddLineNote(unsigned FID, unsigned Offset, } else if (EntryExit == 2) { assert(!Entries.empty() && Entries.back().IncludeOffset && "PPDirectives should have caught case when popping empty include stack"); - + // Get the include loc of the last entries' include loc as our include loc. IncludeOffset = 0; if (const LineEntry *PrevEntry = FindNearestLineEntry(FID, Entries.back().IncludeOffset)) IncludeOffset = PrevEntry->IncludeOffset; } - + Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, FileKind, IncludeOffset)); } @@ -139,7 +183,7 @@ void LineTableInfo::AddLineNote(unsigned FID, unsigned Offset, /// FindNearestLineEntry - Find the line entry nearest to FID that is before /// it. If there is no line entry before Offset in FID, return null. -const LineEntry *LineTableInfo::FindNearestLineEntry(unsigned FID, +const LineEntry *LineTableInfo::FindNearestLineEntry(unsigned FID, unsigned Offset) { const std::vector &Entries = LineEntries[FID]; assert(!Entries.empty() && "No #line entries for this FID after all!"); @@ -158,13 +202,13 @@ const LineEntry *LineTableInfo::FindNearestLineEntry(unsigned FID, /// \brief Add a new line entry that has already been encoded into /// the internal representation of the line table. -void LineTableInfo::AddEntry(unsigned FID, +void LineTableInfo::AddEntry(unsigned FID, const std::vector &Entries) { LineEntries[FID] = Entries; } /// getLineTableFilenameID - Return the uniqued ID for the specified filename. -/// +/// unsigned SourceManager::getLineTableFilenameID(const char *Ptr, unsigned Len) { if (LineTable == 0) LineTable = new LineTableInfo(); @@ -178,12 +222,12 @@ unsigned SourceManager::getLineTableFilenameID(const char *Ptr, unsigned Len) { void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID) { std::pair LocInfo = getDecomposedInstantiationLoc(Loc); - + const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile(); // Remember that this file has #line directives now if it doesn't already. const_cast(FileInfo).setHasLineDirectives(); - + if (LineTable == 0) LineTable = new LineTableInfo(); LineTable->AddLineNote(LocInfo.first.ID, LocInfo.second, LineNo, FilenameID); @@ -201,16 +245,16 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, "Can't set flags without setting the filename!"); return AddLineNote(Loc, LineNo, FilenameID); } - + std::pair LocInfo = getDecomposedInstantiationLoc(Loc); const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile(); - + // Remember that this file has #line directives now if it doesn't already. const_cast(FileInfo).setHasLineDirectives(); - + if (LineTable == 0) LineTable = new LineTableInfo(); - + SrcMgr::CharacteristicKind FileKind; if (IsExternCHeader) FileKind = SrcMgr::C_ExternCSystem; @@ -218,13 +262,13 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, FileKind = SrcMgr::C_System; else FileKind = SrcMgr::C_User; - + unsigned EntryExit = 0; if (IsFileEntry) EntryExit = 1; else if (IsFileExit) EntryExit = 2; - + LineTable->AddLineNote(LocInfo.first.ID, LocInfo.second, LineNo, FilenameID, EntryExit, FileKind); } @@ -241,7 +285,7 @@ LineTableInfo &SourceManager::getLineTable() { SourceManager::~SourceManager() { delete LineTable; - + // Delete FileEntry objects corresponding to content caches. Since the actual // content cache objects are bump pointer allocated, we just have to run the // dtors, but we call the deallocate method for completeness. @@ -262,10 +306,10 @@ void SourceManager::clearIDTables() { LastLineNoFileIDQuery = FileID(); LastLineNoContentCache = 0; LastFileIDLookup = FileID(); - + if (LineTable) LineTable->clear(); - + // Use up FileID #0 as an invalid instantiation. NextOffset = 0; createInstantiationLoc(SourceLocation(),SourceLocation(),SourceLocation(), 1); @@ -276,11 +320,11 @@ void SourceManager::clearIDTables() { const ContentCache * SourceManager::getOrCreateContentCache(const FileEntry *FileEnt) { assert(FileEnt && "Didn't specify a file entry to use?"); - + // Do we already have information about this file? ContentCache *&Entry = FileInfos[FileEnt]; if (Entry) return Entry; - + // Nope, create a new Cache entry. Make sure it is at least 8-byte aligned // so that FileInfo can use the low 3 bits of the pointer for its own // nefarious purposes. @@ -288,6 +332,16 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt) { EntryAlign = std::max(8U, EntryAlign); Entry = ContentCacheAlloc.Allocate(1, EntryAlign); new (Entry) ContentCache(FileEnt); + + if (FileEnt == TruncateFile) { + // If we had queued up a file truncation request, perform the truncation + // now. + Entry->truncateAt(TruncateAtLine, TruncateAtColumn); + TruncateFile = 0; + TruncateAtLine = 0; + TruncateAtColumn = 0; + } + return Entry; } @@ -350,12 +404,12 @@ FileID SourceManager::createFileID(const ContentCache *File, if (PreallocatedID) { // If we're filling in a preallocated ID, just load in the file // entry and return. - assert(PreallocatedID < SLocEntryLoaded.size() && + assert(PreallocatedID < SLocEntryLoaded.size() && "Preallocate ID out-of-range"); - assert(!SLocEntryLoaded[PreallocatedID] && + assert(!SLocEntryLoaded[PreallocatedID] && "Source location entry already loaded"); assert(Offset && "Preallocate source location cannot have zero offset"); - SLocEntryTable[PreallocatedID] + SLocEntryTable[PreallocatedID] = SLocEntry::get(Offset, FileInfo::get(IncludePos, File, FileCharacter)); SLocEntryLoaded[PreallocatedID] = true; FileID FID = FileID::get(PreallocatedID); @@ -364,13 +418,13 @@ FileID SourceManager::createFileID(const ContentCache *File, return LastFileIDLookup = FID; } - SLocEntryTable.push_back(SLocEntry::get(NextOffset, + SLocEntryTable.push_back(SLocEntry::get(NextOffset, FileInfo::get(IncludePos, File, FileCharacter))); unsigned FileSize = File->getSize(); assert(NextOffset+FileSize+1 > NextOffset && "Ran out of source locations!"); NextOffset += FileSize+1; - + // Set LastFileIDLookup to the newly created file. The next getFileID call is // almost guaranteed to be from that file. FileID FID = FileID::get(SLocEntryTable.size()-1); @@ -392,9 +446,9 @@ SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc, if (PreallocatedID) { // If we're filling in a preallocated ID, just load in the // instantiation entry and return. - assert(PreallocatedID < SLocEntryLoaded.size() && + assert(PreallocatedID < SLocEntryLoaded.size() && "Preallocate ID out-of-range"); - assert(!SLocEntryLoaded[PreallocatedID] && + assert(!SLocEntryLoaded[PreallocatedID] && "Source location entry already loaded"); assert(Offset && "Preallocate source location cannot have zero offset"); SLocEntryTable[PreallocatedID] = SLocEntry::get(Offset, II); @@ -427,7 +481,7 @@ SourceManager::getBufferData(FileID FID) const { /// FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { assert(SLocOffset && "Invalid FileID"); - + // After the first and second level caches, I see two common sorts of // behavior: 1) a lot of searched FileID's are "near" the cached file location // or are "near" the cached instantiation location. 2) others are just @@ -436,11 +490,11 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { // To handle this, we do a linear search for up to 8 steps to catch #1 quickly // then we fall back to a less cache efficient, but more scalable, binary // search to find the location. - + // See if this is near the file point - worst case we start scanning from the // most newly created FileID. std::vector::const_iterator I; - + if (SLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset) { // Neither loc prunes our search. I = SLocEntryTable.end(); @@ -475,7 +529,7 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { if (++NumProbes == 8) break; } - + // Convert "I" back into an index. We know that it is an entry whose index is // larger than the offset we are looking for. unsigned GreaterIndex = I-SLocEntryTable.begin(); @@ -487,16 +541,16 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { while (1) { unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex; unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex)).getOffset(); - + ++NumProbes; - + // If the offset of the midpoint is too large, chop the high side of the // range to the midpoint. if (MidOffset > SLocOffset) { GreaterIndex = MiddleIndex; continue; } - + // If the middle index contains the value, succeed and return. if (isOffsetInFileID(FileID::get(MiddleIndex), SLocOffset)) { #if 0 @@ -514,7 +568,7 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { NumBinaryProbes += NumProbes; return Res; } - + // Otherwise, move the low-side up to the middle index. LessIndex = MiddleIndex; } @@ -551,12 +605,12 @@ SourceManager::getDecomposedInstantiationLocSlowCase(const SrcMgr::SLocEntry *E, SourceLocation Loc; do { Loc = E->getInstantiation().getInstantiationLocStart(); - + FID = getFileID(Loc); E = &getSLocEntry(FID); Offset += Loc.getOffset()-E->getOffset(); } while (!Loc.isFileID()); - + return std::make_pair(FID, Offset); } @@ -569,12 +623,12 @@ SourceManager::getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E, SourceLocation Loc; do { Loc = E->getInstantiation().getSpellingLoc(); - + FID = getFileID(Loc); E = &getSLocEntry(FID); Offset += Loc.getOffset()-E->getOffset(); } while (!Loc.isFileID()); - + return std::make_pair(FID, Offset); } @@ -604,10 +658,10 @@ SourceManager::getImmediateInstantiationRange(SourceLocation Loc) const { std::pair SourceManager::getInstantiationRange(SourceLocation Loc) const { if (Loc.isFileID()) return std::make_pair(Loc, Loc); - + std::pair Res = getImmediateInstantiationRange(Loc); - + // Fully resolve the start and end locations to their ultimate instantiation // points. while (!Res.first.isFileID()) @@ -629,7 +683,7 @@ const char *SourceManager::getCharacterData(SourceLocation SL) const { // Note that this is a hot function in the getSpelling() path, which is // heavily used by -E mode. std::pair LocInfo = getDecomposedSpellingLoc(SL); - + // Note that calling 'getBuffer()' may lazily page in a source file. return getSLocEntry(LocInfo.first).getFile().getContentCache() ->getBuffer()->getBufferStart() + LocInfo.second; @@ -640,7 +694,7 @@ const char *SourceManager::getCharacterData(SourceLocation SL) const { /// this is significantly cheaper to compute than the line number. unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos) const { const char *Buf = getBuffer(FID)->getBufferStart(); - + unsigned LineStart = FilePos; while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r') --LineStart; @@ -663,17 +717,17 @@ unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc) const { static void ComputeLineNumbers(ContentCache* FI, llvm::BumpPtrAllocator &Alloc) DISABLE_INLINE; -static void ComputeLineNumbers(ContentCache* FI, llvm::BumpPtrAllocator &Alloc){ +static void ComputeLineNumbers(ContentCache* FI, llvm::BumpPtrAllocator &Alloc){ // Note that calling 'getBuffer()' may lazily page in the file. const MemoryBuffer *Buffer = FI->getBuffer(); - + // Find the file offsets of all of the *physical* source lines. This does // not look at trigraphs, escaped newlines, or anything else tricky. std::vector LineOffsets; - + // Line #1 starts at char 0. LineOffsets.push_back(0); - + const unsigned char *Buf = (const unsigned char *)Buffer->getBufferStart(); const unsigned char *End = (const unsigned char *)Buffer->getBufferEnd(); unsigned Offs = 0; @@ -686,7 +740,7 @@ static void ComputeLineNumbers(ContentCache* FI, llvm::BumpPtrAllocator &Alloc){ ++NextBuf; Offs += NextBuf-Buf; Buf = NextBuf; - + if (Buf[0] == '\n' || Buf[0] == '\r') { // If this is \n\r or \r\n, skip both characters. if ((Buf[1] == '\n' || Buf[1] == '\r') && Buf[0] != Buf[1]) @@ -700,7 +754,7 @@ static void ComputeLineNumbers(ContentCache* FI, llvm::BumpPtrAllocator &Alloc){ ++Offs, ++Buf; } } - + // Copy the offsets into the FileInfo structure. FI->NumLines = LineOffsets.size(); FI->SourceLineCache = Alloc.Allocate(LineOffsets.size()); @@ -718,7 +772,7 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const { else Content = const_cast(getSLocEntry(FID) .getFile().getContentCache()); - + // If this is the first use of line information for this buffer, compute the /// SourceLineCache for it on demand. if (Content->SourceLineCache == 0) @@ -729,11 +783,11 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const { unsigned *SourceLineCache = Content->SourceLineCache; unsigned *SourceLineCacheStart = SourceLineCache; unsigned *SourceLineCacheEnd = SourceLineCache + Content->NumLines; - + unsigned QueriedFilePos = FilePos+1; // FIXME: I would like to be convinced that this code is worth being as - // complicated as it is, binary search isn't that slow. + // complicated as it is, binary search isn't that slow. // // If it is worth being optimized, then in my opinion it could be more // performant, simpler, and more obviously correct by just "galloping" outward @@ -749,7 +803,7 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const { if (QueriedFilePos >= LastLineNoFilePos) { // FIXME: Potential overflow? SourceLineCache = SourceLineCache+LastLineNoResult-1; - + // The query is likely to be nearby the previous one. Here we check to // see if it is within 5, 10 or 20 lines. It can be far away in cases // where big comment blocks and vertical whitespace eat up lines but @@ -771,17 +825,17 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const { SourceLineCacheEnd = SourceLineCache+LastLineNoResult+1; } } - + // If the spread is large, do a "radix" test as our initial guess, based on // the assumption that lines average to approximately the same length. // NOTE: This is currently disabled, as it does not appear to be profitable in // initial measurements. if (0 && SourceLineCacheEnd-SourceLineCache > 20) { unsigned FileLen = Content->SourceLineCache[Content->NumLines-1]; - + // Take a stab at guessing where it is. unsigned ApproxPos = Content->NumLines*QueriedFilePos / FileLen; - + // Check for -10 and +10 lines. unsigned LowerBound = std::max(int(ApproxPos-10), 0); unsigned UpperBound = std::min(ApproxPos+10, FileLen); @@ -790,17 +844,17 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const { if (SourceLineCache < SourceLineCacheStart+LowerBound && SourceLineCacheStart[LowerBound] < QueriedFilePos) SourceLineCache = SourceLineCacheStart+LowerBound; - + // If the computed upper bound is greater than the query location, move it. if (SourceLineCacheEnd > SourceLineCacheStart+UpperBound && SourceLineCacheStart[UpperBound] >= QueriedFilePos) SourceLineCacheEnd = SourceLineCacheStart+UpperBound; } - + unsigned *Pos = std::lower_bound(SourceLineCache, SourceLineCacheEnd, QueriedFilePos); unsigned LineNo = Pos-SourceLineCacheStart; - + LastLineNoFileIDQuery = FID; LastLineNoContentCache = Content; LastLineNoFilePos = QueriedFilePos; @@ -820,14 +874,14 @@ unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc) const { } /// getFileCharacteristic - return the file characteristic of the specified -/// source location, indicating whether this is a normal file, a system +/// source location, indicating whether this is a normal file, a system /// header, or an "implicit extern C" system header. /// /// This state can be modified with flags on GNU linemarker directives like: /// # 4 "foo.h" 3 /// which changes all source locations in the current file after that to be /// considered to be from a system header. -SrcMgr::CharacteristicKind +SrcMgr::CharacteristicKind SourceManager::getFileCharacteristic(SourceLocation Loc) const { assert(!Loc.isInvalid() && "Can't get file characteristic of invalid loc!"); std::pair LocInfo = getDecomposedInstantiationLoc(Loc); @@ -837,12 +891,12 @@ SourceManager::getFileCharacteristic(SourceLocation Loc) const { // state. if (!FI.hasLineDirectives()) return FI.getFileCharacteristic(); - + assert(LineTable && "Can't have linetable entries without a LineTable!"); // See if there is a #line directive before the location. const LineEntry *Entry = LineTable->FindNearestLineEntry(LocInfo.first.ID, LocInfo.second); - + // If this is before the first line marker, use the file characteristic. if (!Entry) return FI.getFileCharacteristic(); @@ -855,7 +909,7 @@ SourceManager::getFileCharacteristic(SourceLocation Loc) const { /// for normal clients. const char *SourceManager::getBufferName(SourceLocation Loc) const { if (Loc.isInvalid()) return ""; - + return getBuffer(getFileID(Loc))->getBufferIdentifier(); } @@ -869,22 +923,22 @@ const char *SourceManager::getBufferName(SourceLocation Loc) const { /// of an instantiation location, not at the spelling location. PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const { if (Loc.isInvalid()) return PresumedLoc(); - + // Presumed locations are always for instantiation points. std::pair LocInfo = getDecomposedInstantiationLoc(Loc); - + const SrcMgr::FileInfo &FI = getSLocEntry(LocInfo.first).getFile(); const SrcMgr::ContentCache *C = FI.getContentCache(); - + // To get the source name, first consult the FileEntry (if one exists) // before the MemBuffer as this will avoid unnecessarily paging in the // MemBuffer. - const char *Filename = + const char *Filename = C->Entry ? C->Entry->getName() : C->getBuffer()->getBufferIdentifier(); unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second); unsigned ColNo = getColumnNumber(LocInfo.first, LocInfo.second); SourceLocation IncludeLoc = FI.getIncludeLoc(); - + // If we have #line directives in this file, update and overwrite the physical // location info if appropriate. if (FI.hasLineDirectives()) { @@ -902,9 +956,9 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const { // total. unsigned MarkerLineNo = getLineNumber(LocInfo.first, Entry->FileOffset); LineNo = Entry->LineNo + (LineNo-MarkerLineNo-1); - + // Note that column numbers are not molested by line markers. - + // Handle virtual #include manipulation. if (Entry->IncludeOffset) { IncludeLoc = getLocForStartOfFile(LocInfo.first); @@ -933,7 +987,7 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, if (FI == FileInfos.end()) return SourceLocation(); ContentCache *Content = FI->second; - + // If this is the first use of line information for this buffer, compute the /// SourceLineCache for it on demand. if (Content->SourceLineCache == 0) @@ -941,7 +995,7 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, if (Line > Content->NumLines) return SourceLocation(); - + unsigned FilePos = Content->SourceLineCache[Line - 1]; const char *Buf = Content->getBuffer()->getBufferStart() + FilePos; unsigned BufLength = Content->getBuffer()->getBufferEnd() - Buf; @@ -952,7 +1006,7 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, ++i; if (i < Col-1) return SourceLocation(); - + return getLocForStartOfFile(Content->FirstFID). getFileLocWithOffset(FilePos + Col - 1); } @@ -965,24 +1019,24 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, assert(LHS.isValid() && RHS.isValid() && "Passed invalid source location!"); if (LHS == RHS) return false; - + std::pair LOffs = getDecomposedLoc(LHS); std::pair ROffs = getDecomposedLoc(RHS); - + // If the source locations are in the same file, just compare offsets. if (LOffs.first == ROffs.first) return LOffs.second < ROffs.second; // If we are comparing a source location with multiple locations in the same // file, we get a big win by caching the result. - + if (LastLFIDForBeforeTUCheck == LOffs.first && LastRFIDForBeforeTUCheck == ROffs.first) return LastResForBeforeTUCheck; - + LastLFIDForBeforeTUCheck = LOffs.first; LastRFIDForBeforeTUCheck = ROffs.first; - + // "Traverse" the include/instantiation stacks of both locations and try to // find a common "ancestor". // @@ -1000,15 +1054,15 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, UpperLoc = Entry.getInstantiation().getInstantiationLocStart(); else UpperLoc = Entry.getFile().getIncludeLoc(); - + if (UpperLoc.isInvalid()) break; // We reached the top. - + ROffs = getDecomposedLoc(UpperLoc); - + if (LOffs.first == ROffs.first) return LastResForBeforeTUCheck = LOffs.second < ROffs.second; - + ROffsMap[ROffs.first] = ROffs.second; } @@ -1022,33 +1076,33 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, UpperLoc = Entry.getInstantiation().getInstantiationLocStart(); else UpperLoc = Entry.getFile().getIncludeLoc(); - + if (UpperLoc.isInvalid()) break; // We reached the top. - + LOffs = getDecomposedLoc(UpperLoc); - + std::map::iterator I = ROffsMap.find(LOffs.first); if (I != ROffsMap.end()) return LastResForBeforeTUCheck = LOffs.second < I->second; } - + // No common ancestor. // Now we are getting into murky waters. Most probably this is because one // location is in the predefines buffer. - + const FileEntry *LEntry = getSLocEntry(LOffs.first).getFile().getContentCache()->Entry; const FileEntry *REntry = getSLocEntry(ROffs.first).getFile().getContentCache()->Entry; - + // If the locations are in two memory buffers we give up, we can't answer // which one should be considered first. // FIXME: Should there be a way to "include" memory buffers in the translation // unit ? assert((LEntry != 0 || REntry != 0) && "Locations in memory buffers."); (void) REntry; - + // Consider the memory buffer as coming before the file in the translation // unit. if (LEntry == 0) @@ -1059,26 +1113,48 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, } } +void SourceManager::truncateFileAt(const FileEntry *Entry, unsigned Line, + unsigned Column) { + llvm::DenseMap::iterator FI + = FileInfos.find(Entry); + if (FI != FileInfos.end()) { + FI->second->truncateAt(Line, Column); + return; + } + + // We cannot perform the truncation until we actually see the file, so + // save the truncation information. + assert(TruncateFile == 0 && "Can't queue up multiple file truncations!"); + TruncateFile = Entry; + TruncateAtLine = Line; + TruncateAtColumn = Column; +} + +/// \brief Determine whether this file was truncated. +bool SourceManager::isTruncatedFile(FileID FID) const { + return getSLocEntry(FID).getFile().getContentCache()->isTruncated(); +} + /// PrintStats - Print statistics to stderr. /// void SourceManager::PrintStats() const { - llvm::cerr << "\n*** Source Manager Stats:\n"; - llvm::cerr << FileInfos.size() << " files mapped, " << MemBufferInfos.size() - << " mem buffers mapped.\n"; - llvm::cerr << SLocEntryTable.size() << " SLocEntry's allocated, " - << NextOffset << "B of Sloc address space used.\n"; - + llvm::errs() << "\n*** Source Manager Stats:\n"; + llvm::errs() << FileInfos.size() << " files mapped, " << MemBufferInfos.size() + << " mem buffers mapped.\n"; + llvm::errs() << SLocEntryTable.size() << " SLocEntry's allocated, " + << NextOffset << "B of Sloc address space used.\n"; + unsigned NumLineNumsComputed = 0; unsigned NumFileBytesMapped = 0; for (fileinfo_iterator I = fileinfo_begin(), E = fileinfo_end(); I != E; ++I){ NumLineNumsComputed += I->second->SourceLineCache != 0; NumFileBytesMapped += I->second->getSizeBytesMapped(); } - - llvm::cerr << NumFileBytesMapped << " bytes of files mapped, " - << NumLineNumsComputed << " files with line #'s computed.\n"; - llvm::cerr << "FileID scans: " << NumLinearScans << " linear, " - << NumBinaryProbes << " binary.\n"; + + llvm::errs() << NumFileBytesMapped << " bytes of files mapped, " + << NumLineNumsComputed << " files with line #'s computed.\n"; + llvm::errs() << "FileID scans: " << NumLinearScans << " linear, " + << NumBinaryProbes << " binary.\n"; } ExternalSLocEntrySource::~ExternalSLocEntrySource() { } diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index ba7f190408b2..9cd12493e7a4 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -25,6 +25,8 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { TLSSupported = true; PointerWidth = PointerAlign = 32; WCharWidth = WCharAlign = 32; + Char16Width = Char16Align = 16; + Char32Width = Char32Align = 32; IntWidth = IntAlign = 32; LongWidth = LongAlign = 32; LongLongWidth = LongLongAlign = 64; @@ -41,6 +43,8 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { UIntMaxType = UnsignedLongLong; IntPtrType = SignedLong; WCharType = SignedInt; + Char16Type = UnsignedShort; + Char32Type = UnsignedInt; Int64Type = SignedLongLong; FloatFormat = &llvm::APFloat::IEEEsingle; DoubleFormat = &llvm::APFloat::IEEEdouble; @@ -83,17 +87,17 @@ static void removeGCCRegisterPrefix(const char *&Name) { bool TargetInfo::isValidGCCRegisterName(const char *Name) const { const char * const *Names; unsigned NumNames; - + // Get rid of any register prefix. removeGCCRegisterPrefix(Name); - + if (strcmp(Name, "memory") == 0 || strcmp(Name, "cc") == 0) 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; @@ -107,11 +111,11 @@ bool TargetInfo::isValidGCCRegisterName(const char *Name) const { if (strcmp(Name, Names[i]) == 0) return true; } - + // Now check aliases. const GCCRegAlias *Aliases; unsigned NumAliases; - + getGCCRegAliases(Aliases, NumAliases); for (unsigned i = 0; i < NumAliases; i++) { for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) { @@ -121,15 +125,15 @@ bool TargetInfo::isValidGCCRegisterName(const char *Name) const { return true; } } - + return false; } const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const { assert(isValidGCCRegisterName(Name) && "Invalid register passed in"); - + removeGCCRegisterPrefix(Name); - + const char * const *Names; unsigned NumNames; @@ -140,16 +144,16 @@ const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const { char *End; int n = (int)strtol(Name, &End, 0); if (*End == 0) { - assert(n >= 0 && (unsigned)n < NumNames && + assert(n >= 0 && (unsigned)n < NumNames && "Out of bounds register number!"); return Names[n]; } } - + // Now check aliases. const GCCRegAlias *Aliases; unsigned NumAliases; - + getGCCRegAliases(Aliases, NumAliases); for (unsigned i = 0; i < NumAliases; i++) { for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) { @@ -159,7 +163,7 @@ const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const { return Aliases[i].Register; } } - + return Name; } @@ -184,6 +188,9 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const { } case '&': // early clobber. break; + case '%': // commutative. + // FIXME: Check that there is a another register after this one. + break; case 'r': // general register. Info.setAllowsRegister(); break; @@ -196,10 +203,10 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const { Info.setAllowsMemory(); break; } - + Name++; } - + return true; } @@ -212,14 +219,14 @@ bool TargetInfo::resolveSymbolicName(const char *&Name, const char *Start = Name; while (*Name && *Name != ']') Name++; - + if (!*Name) { // Missing ']' return false; } - + std::string SymbolicName(Start, Name - Start); - + for (Index = 0; Index != NumOutputs; ++Index) if (SymbolicName == OutputConstraints[Index].getName()) return true; @@ -238,12 +245,12 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, // Check if we have a matching constraint if (*Name >= '0' && *Name <= '9') { unsigned i = *Name - '0'; - + // Check if matching constraint is out of bounds. if (i >= NumOutputs) return false; - - // The constraint should have the same info as the respective + + // The constraint should have the same info as the respective // output constraint. Info.setTiedOperand(i, OutputConstraints[i]); } else if (!validateAsmConstraint(Name, Info)) { @@ -257,9 +264,9 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, unsigned Index = 0; if (!resolveSymbolicName(Name, OutputConstraints, NumOutputs, Index)) return false; - + break; - } + } case '%': // commutative // FIXME: Fail if % is used with the last operand. break; @@ -287,9 +294,9 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, Info.setAllowsMemory(); break; } - + Name++; } - + return true; } diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 3f7d9a31c61e..1d4d1235c963 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -16,22 +16,25 @@ #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/LangOptions.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" +#include "llvm/MC/MCSectionMachO.h" using namespace clang; //===----------------------------------------------------------------------===// // Common code shared among targets. //===----------------------------------------------------------------------===// -static void Define(std::vector &Buf, const char *Macro, - const char *Val = "1") { +static void Define(std::vector &Buf, const llvm::StringRef &Macro, + const llvm::StringRef &Val = "1") { const char *Def = "#define "; Buf.insert(Buf.end(), Def, Def+strlen(Def)); - Buf.insert(Buf.end(), Macro, Macro+strlen(Macro)); + Buf.insert(Buf.end(), Macro.begin(), Macro.end()); Buf.push_back(' '); - Buf.insert(Buf.end(), Val, Val+strlen(Val)); + Buf.insert(Buf.end(), Val.begin(), Val.end()); Buf.push_back('\n'); } @@ -51,91 +54,34 @@ static void DefineStd(std::vector &Buf, const char *MacroName, llvm::SmallString<20> TmpStr; TmpStr = "__"; TmpStr += MacroName; - Define(Buf, TmpStr.c_str()); + Define(Buf, TmpStr.str()); // Define __unix__. TmpStr += "__"; - Define(Buf, TmpStr.c_str()); + Define(Buf, TmpStr.str()); } //===----------------------------------------------------------------------===// // Defines specific to certain operating systems. //===----------------------------------------------------------------------===// + namespace { template class OSTargetInfo : public TgtInfo { protected: - virtual void getOSDefines(const LangOptions &Opts, const char *Triple, + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, std::vector &Defines) const=0; public: OSTargetInfo(const std::string& triple) : TgtInfo(triple) {} virtual void getTargetDefines(const LangOptions &Opts, std::vector &Defines) const { TgtInfo::getTargetDefines(Opts, Defines); - getOSDefines(Opts, TgtInfo::getTargetTriple(), Defines); + getOSDefines(Opts, TgtInfo::getTriple(), Defines); } }; -} - -namespace { -/// getDarwinNumber - Parse the 'darwin number' out of the specific targe -/// triple. For example, if we have darwin8.5 return 8,5,0. If any entry is -/// not defined, return 0's. Return true if we have -darwin in the string or -/// false otherwise. -static bool getDarwinNumber(const char *Triple, unsigned &Maj, unsigned &Min, unsigned &Revision) { - Maj = Min = Revision = 0; - const char *Darwin = strstr(Triple, "-darwin"); - if (Darwin == 0) return false; - - Darwin += strlen("-darwin"); - if (Darwin[0] < '0' || Darwin[0] > '9') - return true; - - Maj = Darwin[0]-'0'; - ++Darwin; - - // Handle "darwin11". - if (Maj == 1 && Darwin[0] >= '0' && Darwin[0] <= '9') { - Maj = Maj*10 + (Darwin[0] - '0'); - ++Darwin; - } - - // Handle minor version: 10.4.9 -> darwin8.9 -> "1049" - if (Darwin[0] != '.') - return true; - - ++Darwin; - if (Darwin[0] < '0' || Darwin[0] > '9') - return true; - - Min = Darwin[0]-'0'; - ++Darwin; - - // Handle 10.4.11 -> darwin8.11 - if (Min == 1 && Darwin[0] >= '0' && Darwin[0] <= '9') { - Min = Min*10 + (Darwin[0] - '0'); - ++Darwin; - } - - // Handle revision darwin8.9.1 - if (Darwin[0] != '.') - return true; - - ++Darwin; - if (Darwin[0] < '0' || Darwin[0] > '9') - return true; - - Revision = Darwin[0]-'0'; - ++Darwin; - - if (Revision == 1 && Darwin[0] >= '0' && Darwin[0] <= '9') { - Revision = Revision*10 + (Darwin[0] - '0'); - ++Darwin; - } +} // end anonymous namespace - return true; -} static void getDarwinDefines(std::vector &Defs, const LangOptions &Opts) { Define(Defs, "__APPLE_CC__", "5621"); @@ -156,81 +102,94 @@ static void getDarwinDefines(std::vector &Defs, const LangOptions &Opts) { Define(Defs, "__STATIC__"); else Define(Defs, "__DYNAMIC__"); + + if (Opts.POSIXThreads) + Define(Defs, "_REENTRANT", "1"); } -static void getDarwinOSXDefines(std::vector &Defs, const char *Triple) { +static void getDarwinOSXDefines(std::vector &Defs, + 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; - if (getDarwinNumber(Triple, 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; - } + Triple.getDarwinNumber(Maj, Min, Rev); - // Handle minor version: 10.4.9 -> darwin8.9 -> "1049" - // Cap 10.4.11 -> darwin8.11 -> "1049" - MacOSXStr[3] = std::min(Min, 9U)+'0'; - Define(Defs, "__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", MacOSXStr); + 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'; + Define(Defs, "__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", MacOSXStr); } static void getDarwinIPhoneOSDefines(std::vector &Defs, - const char *Triple) { + 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; - if (getDarwinNumber(Triple, 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; - } + Triple.getDarwinNumber(Maj, Min, Rev); - // Handle minor version: 2.2 -> darwin9.2.2 -> 20200 - iPhoneOSStr[2] = std::min(Rev, 9U)+'0'; - Define(Defs, "__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", - iPhoneOSStr); + // 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; } + + // Handle minor version: 2.2 -> darwin9.2.2 -> 20200 + iPhoneOSStr[2] = std::min(Rev, 9U)+'0'; + Define(Defs, "__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", + iPhoneOSStr); } /// GetDarwinLanguageOptions - Set the default language options for darwin. static void GetDarwinLanguageOptions(LangOptions &Opts, - const char *Triple) { + const llvm::Triple &Triple) { Opts.NeXTRuntime = true; - unsigned Maj, Min, Rev; - if (!getDarwinNumber(Triple, Maj, Min, Rev)) + if (Triple.getOS() != llvm::Triple::Darwin) return; + unsigned MajorVersion = Triple.getDarwinMajorNumber(); + // Blocks and stack protectors default to on for 10.6 (darwin10) and beyond. - if (Maj > 9) { + if (MajorVersion > 9) { Opts.Blocks = 1; Opts.setStackProtectorMode(LangOptions::SSPOn); } // Non-fragile ABI (in 64-bit mode) default to on for 10.5 (darwin9) and // beyond. - if (Maj >= 9 && Opts.ObjC1 && !strncmp(Triple, "x86_64", 6)) + if (MajorVersion >= 9 && Opts.ObjC1 && + Triple.getArch() == llvm::Triple::x86_64) Opts.ObjCNonFragileABI = 1; } +namespace { template class DarwinTargetInfo : public OSTargetInfo { protected: - virtual void getOSDefines(const LangOptions &Opts, const char *Triple, + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, std::vector &Defines) const { getDarwinDefines(Defines, Opts); getDarwinOSXDefines(Defines, Triple); } - + /// getDefaultLangOptions - Allow the target to specify default settings for /// various language options. These may be overridden by command line /// options. virtual void getDefaultLangOptions(LangOptions &Opts) { TargetInfo::getDefaultLangOptions(Opts); - GetDarwinLanguageOptions(Opts, TargetInfo::getTargetTriple()); + GetDarwinLanguageOptions(Opts, TargetInfo::getTriple()); } public: DarwinTargetInfo(const std::string& triple) : @@ -238,28 +197,25 @@ public: this->TLSSupported = false; } - virtual const char *getCFStringSymbolPrefix() const { - return "\01L_unnamed_cfstring_"; - } - - virtual const char *getStringSymbolPrefix(bool IsConstant) const { - return IsConstant ? "\01LC" : "\01lC"; - } - - virtual const char *getUnicodeStringSymbolPrefix() const { - return "__utf16_string_"; - } - virtual const char *getUnicodeStringSection() const { return "__TEXT,__ustring"; } + + virtual std::string isValidSectionSpecifier(const llvm::StringRef &SR) const { + // Let MCSectionMachO validate this. + llvm::StringRef Segment, Section; + unsigned TAA, StubSize; + return llvm::MCSectionMachO::ParseSectionSpecifier(SR, Segment, Section, + TAA, StubSize); + } }; + // DragonFlyBSD Target template class DragonFlyBSDTargetInfo : public OSTargetInfo { protected: - virtual void getOSDefines(const LangOptions &Opts, const char *Triple, + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, std::vector &Defs) const { // DragonFly defines; list based off of gcc output Define(Defs, "__DragonFly__"); @@ -270,7 +226,7 @@ protected: DefineStd(Defs, "unix", Opts); } public: - DragonFlyBSDTargetInfo(const std::string &triple) + DragonFlyBSDTargetInfo(const std::string &triple) : OSTargetInfo(triple) {} }; @@ -278,11 +234,13 @@ public: template class FreeBSDTargetInfo : public OSTargetInfo { protected: - virtual void getOSDefines(const LangOptions &Opts, const char *Triple, + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, std::vector &Defs) const { // FreeBSD defines; list based off of gcc output - const char *FreeBSD = strstr(Triple, "-freebsd"); + // 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]; @@ -296,43 +254,69 @@ protected: Define(Defs, "__ELF__", "1"); } public: - FreeBSDTargetInfo(const std::string &triple) - : OSTargetInfo(triple) {} + FreeBSDTargetInfo(const std::string &triple) + : OSTargetInfo(triple) { + this->UserLabelPrefix = ""; + } }; // Linux target template class LinuxTargetInfo : public OSTargetInfo { protected: - virtual void getOSDefines(const LangOptions &Opts, const char *Triple, + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, std::vector &Defs) const { // Linux defines; list based off of gcc output DefineStd(Defs, "unix", Opts); DefineStd(Defs, "linux", Opts); Define(Defs, "__gnu_linux__"); Define(Defs, "__ELF__", "1"); + if (Opts.POSIXThreads) + Define(Defs, "_REENTRANT", "1"); } public: - LinuxTargetInfo(const std::string& triple) + LinuxTargetInfo(const std::string& triple) : OSTargetInfo(triple) { this->UserLabelPrefix = ""; } }; +// NetBSD Target +template +class NetBSDTargetInfo : public OSTargetInfo { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + std::vector &Defs) const { + // NetBSD defines; list based off of gcc output + Define(Defs, "__NetBSD__", "1"); + Define(Defs, "__unix__", "1"); + Define(Defs, "__ELF__", "1"); + if (Opts.POSIXThreads) + Define(Defs, "_POSIX_THREADS", "1"); + } +public: + NetBSDTargetInfo(const std::string &triple) + : OSTargetInfo(triple) { + this->UserLabelPrefix = ""; + } +}; + // OpenBSD Target template class OpenBSDTargetInfo : public OSTargetInfo { protected: - virtual void getOSDefines(const LangOptions &Opts, const char *Triple, + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, std::vector &Defs) const { // OpenBSD defines; list based off of gcc output Define(Defs, "__OpenBSD__", "1"); DefineStd(Defs, "unix", Opts); Define(Defs, "__ELF__", "1"); + if (Opts.POSIXThreads) + Define(Defs, "_POSIX_THREADS", "1"); } public: - OpenBSDTargetInfo(const std::string &triple) + OpenBSDTargetInfo(const std::string &triple) : OSTargetInfo(triple) {} }; @@ -340,7 +324,7 @@ public: template class SolarisTargetInfo : public OSTargetInfo { protected: - virtual void getOSDefines(const LangOptions &Opts, const char *Triple, + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, std::vector &Defs) const { DefineStd(Defs, "sun", Opts); DefineStd(Defs, "unix", Opts); @@ -349,20 +333,14 @@ protected: Define(Defs, "__SVR4"); } public: - SolarisTargetInfo(const std::string& triple) + SolarisTargetInfo(const std::string& triple) : OSTargetInfo(triple) { this->UserLabelPrefix = ""; this->WCharType = this->SignedLong; // FIXME: WIntType should be SignedLong } }; -} // end anonymous namespace. - -/// GetWindowsLanguageOptions - Set the default language options for Windows. -static void GetWindowsLanguageOptions(LangOptions &Opts, - const char *Triple) { - Opts.Microsoft = true; -} +} // end anonymous namespace. //===----------------------------------------------------------------------===// // Specific target implementations. @@ -398,9 +376,6 @@ public: " void* reg_save_area;" "} __builtin_va_list[1];";*/ } - virtual const char *getTargetPrefix() const { - return "ppc"; - } virtual void getGCCRegNames(const char * const *&Names, unsigned &NumNames) const; virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, @@ -464,21 +439,21 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, const char * const PPCTargetInfo::GCCRegNames[] = { - "0", "1", "2", "3", "4", "5", "6", "7", - "8", "9", "10", "11", "12", "13", "14", "15", - "16", "17", "18", "19", "20", "21", "22", "23", - "24", "25", "26", "27", "28", "29", "30", "31", - "0", "1", "2", "3", "4", "5", "6", "7", - "8", "9", "10", "11", "12", "13", "14", "15", - "16", "17", "18", "19", "20", "21", "22", "23", - "24", "25", "26", "27", "28", "29", "30", "31", + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", "mq", "lr", "ctr", "ap", - "0", "1", "2", "3", "4", "5", "6", "7", + "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", "xer", - "0", "1", "2", "3", "4", "5", "6", "7", - "8", "9", "10", "11", "12", "13", "14", "15", - "16", "17", "18", "19", "20", "21", "22", "23", - "24", "25", "26", "27", "28", "29", "30", "31", + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", + "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", "vrsave", "vscr", "spe_acc", "spefscr", "sfp" @@ -493,38 +468,71 @@ void PPCTargetInfo::getGCCRegNames(const char * const *&Names, const TargetInfo::GCCRegAlias PPCTargetInfo::GCCRegAliases[] = { // While some of these aliases do map to different registers // they still share the same register name. - { { "cc", "cr0", "fr0", "r0", "v0"}, "0" }, - { { "cr1", "fr1", "r1", "sp", "v1"}, "1" }, - { { "cr2", "fr2", "r2", "toc", "v2"}, "2" }, - { { "cr3", "fr3", "r3", "v3"}, "3" }, - { { "cr4", "fr4", "r4", "v4"}, "4" }, - { { "cr5", "fr5", "r5", "v5"}, "5" }, - { { "cr6", "fr6", "r6", "v6"}, "6" }, - { { "cr7", "fr7", "r7", "v7"}, "7" }, - { { "fr8", "r8", "v8"}, "8" }, - { { "fr9", "r9", "v9"}, "9" }, - { { "fr10", "r10", "v10"}, "10" }, - { { "fr11", "r11", "v11"}, "11" }, - { { "fr12", "r12", "v12"}, "12" }, - { { "fr13", "r13", "v13"}, "13" }, - { { "fr14", "r14", "v14"}, "14" }, - { { "fr15", "r15", "v15"}, "15" }, - { { "fr16", "r16", "v16"}, "16" }, - { { "fr17", "r17", "v17"}, "17" }, - { { "fr18", "r18", "v18"}, "18" }, - { { "fr19", "r19", "v19"}, "19" }, - { { "fr20", "r20", "v20"}, "20" }, - { { "fr21", "r21", "v21"}, "21" }, - { { "fr22", "r22", "v22"}, "22" }, - { { "fr23", "r23", "v23"}, "23" }, - { { "fr24", "r24", "v24"}, "24" }, - { { "fr25", "r25", "v25"}, "25" }, - { { "fr26", "r26", "v26"}, "26" }, - { { "fr27", "r27", "v27"}, "27" }, - { { "fr28", "r28", "v28"}, "28" }, - { { "fr29", "r29", "v29"}, "29" }, - { { "fr30", "r30", "v30"}, "30" }, - { { "fr31", "r31", "v31"}, "31" }, + { { "0" }, "r0" }, + { { "1"}, "r1" }, + { { "2" }, "r2" }, + { { "3" }, "r3" }, + { { "4" }, "r4" }, + { { "5" }, "r5" }, + { { "6" }, "r6" }, + { { "7" }, "r7" }, + { { "8" }, "r8" }, + { { "9" }, "r9" }, + { { "10" }, "r10" }, + { { "11" }, "r11" }, + { { "12" }, "r12" }, + { { "13" }, "r13" }, + { { "14" }, "r14" }, + { { "15" }, "r15" }, + { { "16" }, "r16" }, + { { "17" }, "r17" }, + { { "18" }, "r18" }, + { { "19" }, "r19" }, + { { "20" }, "r20" }, + { { "21" }, "r21" }, + { { "22" }, "r22" }, + { { "23" }, "r23" }, + { { "24" }, "r24" }, + { { "25" }, "r25" }, + { { "26" }, "r26" }, + { { "27" }, "r27" }, + { { "28" }, "r28" }, + { { "29" }, "r29" }, + { { "30" }, "r30" }, + { { "31" }, "r31" }, + { { "fr0" }, "f0" }, + { { "fr1" }, "f1" }, + { { "fr2" }, "f2" }, + { { "fr3" }, "f3" }, + { { "fr4" }, "f4" }, + { { "fr5" }, "f5" }, + { { "fr6" }, "f6" }, + { { "fr7" }, "f7" }, + { { "fr8" }, "f8" }, + { { "fr9" }, "f9" }, + { { "fr10" }, "f10" }, + { { "fr11" }, "f11" }, + { { "fr12" }, "f12" }, + { { "fr13" }, "f13" }, + { { "fr14" }, "f14" }, + { { "fr15" }, "f15" }, + { { "fr16" }, "f16" }, + { { "fr17" }, "f17" }, + { { "fr18" }, "f18" }, + { { "fr19" }, "f19" }, + { { "fr20" }, "f20" }, + { { "fr21" }, "f21" }, + { { "fr22" }, "f22" }, + { { "fr23" }, "f23" }, + { { "fr24" }, "f24" }, + { { "fr25" }, "f25" }, + { { "fr26" }, "f26" }, + { { "fr27" }, "f27" }, + { { "fr28" }, "f28" }, + { { "fr29" }, "f29" }, + { { "fr30" }, "f30" }, + { { "fr31" }, "f31" }, + { { "cc" }, "cr0" }, }; void PPCTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, @@ -603,9 +611,6 @@ public: Records = BuiltinInfo; NumRecords = clang::X86::LastTSBuiltin-Builtin::FirstTSBuiltin; } - virtual const char *getTargetPrefix() const { - return "x86"; - } virtual void getGCCRegNames(const char * const *&Names, unsigned &NumNames) const { Names = GCCRegNames; @@ -627,12 +632,12 @@ public: virtual bool setFeatureEnabled(llvm::StringMap &Features, const std::string &Name, bool Enabled) const; - virtual void getDefaultFeatures(const std::string &CPU, + virtual void getDefaultFeatures(const std::string &CPU, llvm::StringMap &Features) const; virtual void HandleTargetFeatures(const llvm::StringMap &Features); }; -void X86TargetInfo::getDefaultFeatures(const std::string &CPU, +void X86TargetInfo::getDefaultFeatures(const std::string &CPU, llvm::StringMap &Features) const { // FIXME: This should not be here. Features["3dnow"] = false; @@ -676,7 +681,7 @@ void X86TargetInfo::getDefaultFeatures(const std::string &CPU, setFeatureEnabled(Features, "sse4", true); else if (CPU == "k6" || CPU == "winchip-c6") setFeatureEnabled(Features, "mmx", true); - else if (CPU == "k6-2" || CPU == "k6-3" || CPU == "athlon" || + else if (CPU == "k6-2" || CPU == "k6-3" || CPU == "athlon" || CPU == "athlon-tbird" || CPU == "winchip2" || CPU == "c3") { setFeatureEnabled(Features, "mmx", true); setFeatureEnabled(Features, "3dnow", true); @@ -685,14 +690,14 @@ void X86TargetInfo::getDefaultFeatures(const std::string &CPU, setFeatureEnabled(Features, "3dnowa", true); } else if (CPU == "k8" || CPU == "opteron" || CPU == "athlon64" || CPU == "athlon-fx") { - setFeatureEnabled(Features, "sse2", true); + setFeatureEnabled(Features, "sse2", true); setFeatureEnabled(Features, "3dnowa", true); } else if (CPU == "c3-2") setFeatureEnabled(Features, "sse", true); } bool X86TargetInfo::setFeatureEnabled(llvm::StringMap &Features, - const std::string &Name, + const std::string &Name, bool Enabled) const { // FIXME: This *really* should not be here. if (!Features.count(Name) && Name != "sse4") @@ -706,13 +711,13 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap &Features, else if (Name == "sse2") Features["mmx"] = Features["sse"] = Features["sse2"] = true; else if (Name == "sse3") - Features["mmx"] = Features["sse"] = Features["sse2"] = + Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] = true; else if (Name == "ssse3") - Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] = + Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] = Features["ssse3"] = true; else if (Name == "sse4") - Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] = + Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] = Features["ssse3"] = Features["sse41"] = Features["sse42"] = true; else if (Name == "3dnow") Features["3dnowa"] = true; @@ -720,16 +725,16 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap &Features, Features["3dnow"] = Features["3dnowa"] = true; } else { if (Name == "mmx") - Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] = + Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] = Features["ssse3"] = Features["sse41"] = Features["sse42"] = false; else if (Name == "sse") - Features["sse"] = Features["sse2"] = Features["sse3"] = + Features["sse"] = Features["sse2"] = Features["sse3"] = Features["ssse3"] = Features["sse41"] = Features["sse42"] = false; else if (Name == "sse2") - Features["sse2"] = Features["sse3"] = Features["ssse3"] = + Features["sse2"] = Features["sse3"] = Features["ssse3"] = Features["sse41"] = Features["sse42"] = false; else if (Name == "sse3") - Features["sse3"] = Features["ssse3"] = Features["sse41"] = + Features["sse3"] = Features["ssse3"] = Features["sse41"] = Features["sse42"] = false; else if (Name == "ssse3") Features["ssse3"] = Features["sse41"] = Features["sse42"] = false; @@ -885,6 +890,24 @@ public: virtual const char *getVAListDeclaration() const { return "typedef char* __builtin_va_list;"; } + + int getEHDataRegisterNumber(unsigned RegNo) const { + if (RegNo == 0) return 0; + if (RegNo == 1) return 2; + return -1; + } +}; +} // end anonymous namespace + +namespace { +class OpenBSDI386TargetInfo : public OpenBSDTargetInfo { +public: + OpenBSDI386TargetInfo(const std::string& triple) : + OpenBSDTargetInfo(triple) { + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + } }; } // end anonymous namespace @@ -927,12 +950,75 @@ public: DefineStd(Defines, "WIN32", Opts); DefineStd(Defines, "WINNT", Opts); Define(Defines, "_X86_"); - Define(Defines, "__MSVCRT__"); } +}; +} // end anonymous namespace +namespace { + +/// GetWindowsVisualStudioLanguageOptions - Set the default language options for Windows. +static void GetWindowsVisualStudioLanguageOptions(LangOptions &Opts) { + Opts.Microsoft = true; +} + +// x86-32 Windows Visual Studio target +class VisualStudioWindowsX86_32TargetInfo : public WindowsX86_32TargetInfo { +public: + VisualStudioWindowsX86_32TargetInfo(const std::string& triple) + : WindowsX86_32TargetInfo(triple) { + } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector &Defines) const { + WindowsX86_32TargetInfo::getTargetDefines(Opts, Defines); + // The value of the following reflects processor type. + // 300=386, 400=486, 500=Pentium, 600=Blend (default) + // We lost the original triple, so we use the default. + Define(Defines, "_M_IX86", "600"); + } virtual void getDefaultLangOptions(LangOptions &Opts) { - X86_32TargetInfo::getDefaultLangOptions(Opts); - GetWindowsLanguageOptions(Opts, getTargetTriple()); + WindowsX86_32TargetInfo::getDefaultLangOptions(Opts); + GetWindowsVisualStudioLanguageOptions(Opts); + } +}; +} // end anonymous namespace + +namespace { +// x86-32 MinGW target +class MinGWX86_32TargetInfo : public WindowsX86_32TargetInfo { +public: + MinGWX86_32TargetInfo(const std::string& triple) + : WindowsX86_32TargetInfo(triple) { + } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector &Defines) const { + WindowsX86_32TargetInfo::getTargetDefines(Opts, Defines); + Define(Defines, "__MSVCRT__"); + Define(Defines, "__MINGW32__"); + Define(Defines, "__declspec", "__declspec"); + } +}; +} // end anonymous namespace + +namespace { +// x86-32 Cygwin target +class CygwinX86_32TargetInfo : public X86_32TargetInfo { +public: + CygwinX86_32TargetInfo(const std::string& triple) + : X86_32TargetInfo(triple) { + TLSSupported = false; + WCharType = UnsignedShort; + WCharWidth = WCharAlign = 16; + DoubleAlign = LongLongAlign = 64; + DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" + "a0:0:64-f80:32:32"; + } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector &Defines) const { + X86_32TargetInfo::getTargetDefines(Opts, Defines); + Define(Defines, "__CYGWIN__"); + Define(Defines, "__CYGWIN32__"); + DefineStd(Defines, "unix", Opts); } }; } // end anonymous namespace @@ -963,47 +1049,183 @@ public: "} __va_list_tag;" "typedef __va_list_tag __builtin_va_list[1];"; } + + int getEHDataRegisterNumber(unsigned RegNo) const { + if (RegNo == 0) return 0; + if (RegNo == 1) return 1; + return -1; + } +}; +} // end anonymous namespace + +namespace { +// x86-64 Windows target +class WindowsX86_64TargetInfo : public X86_64TargetInfo { +public: + WindowsX86_64TargetInfo(const std::string& triple) + : X86_64TargetInfo(triple) { + TLSSupported = false; + WCharType = UnsignedShort; + WCharWidth = WCharAlign = 16; + LongWidth = LongAlign = 32; + DoubleAlign = LongLongAlign = 64; + } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector &Defines) const { + X86_64TargetInfo::getTargetDefines(Opts, Defines); + Define(Defines, "_WIN64"); + DefineStd(Defines, "WIN64", Opts); + } +}; +} // end anonymous namespace + +namespace { +// x86-64 Windows Visual Studio target +class VisualStudioWindowsX86_64TargetInfo : public WindowsX86_64TargetInfo { +public: + VisualStudioWindowsX86_64TargetInfo(const std::string& triple) + : WindowsX86_64TargetInfo(triple) { + } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector &Defines) const { + WindowsX86_64TargetInfo::getTargetDefines(Opts, Defines); + Define(Defines, "_M_X64"); + } + virtual const char *getVAListDeclaration() const { + return "typedef char* va_list;"; + } +}; +} // end anonymous namespace + +namespace { +// x86-64 MinGW target +class MinGWX86_64TargetInfo : public WindowsX86_64TargetInfo { +public: + MinGWX86_64TargetInfo(const std::string& triple) + : WindowsX86_64TargetInfo(triple) { + } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector &Defines) const { + WindowsX86_64TargetInfo::getTargetDefines(Opts, Defines); + Define(Defines, "__MSVCRT__"); + Define(Defines, "__MINGW64__"); + Define(Defines, "__declspec"); + } }; } // end anonymous namespace namespace { class DarwinX86_64TargetInfo : public DarwinTargetInfo { public: - DarwinX86_64TargetInfo(const std::string& triple) + DarwinX86_64TargetInfo(const std::string& triple) : DarwinTargetInfo(triple) { Int64Type = SignedLongLong; } }; } // end anonymous namespace +namespace { +class OpenBSDX86_64TargetInfo : public OpenBSDTargetInfo { +public: + OpenBSDX86_64TargetInfo(const std::string& triple) + : OpenBSDTargetInfo(triple) { + IntMaxType = SignedLongLong; + UIntMaxType = UnsignedLongLong; + Int64Type = SignedLongLong; + } +}; +} // end anonymous namespace + namespace { class ARMTargetInfo : public TargetInfo { enum { Armv4t, Armv5, Armv6, + Armv7a, XScale } ArmArch; + + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char * const GCCRegNames[]; + + std::string ABI; + bool IsThumb; + public: - ARMTargetInfo(const std::string& triple) : TargetInfo(triple) { - // FIXME: Are the defaults correct for ARM? - DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" - "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:64:64"; - if (triple.find("arm-") == 0 || triple.find("armv6-") == 0) + ARMTargetInfo(const std::string &TripleStr) + : TargetInfo(TripleStr), ABI("aapcs-linux"), IsThumb(false) + { + llvm::Triple Triple(TripleStr); + + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + + // FIXME: This shouldn't be done this way, we should use features to + // indicate the arch. See lib/Driver/Tools.cpp. + llvm::StringRef Version(""), Arch = Triple.getArchName(); + if (Arch.startswith("arm")) + Version = Arch.substr(3); + else if (Arch.startswith("thumb")) + Version = Arch.substr(5); + if (Version == "v7") + ArmArch = Armv7a; + else if (Version.empty() || Version == "v6" || Version == "v6t2") ArmArch = Armv6; - else if (triple.find("armv5-") == 0) + else if (Version == "v5") ArmArch = Armv5; - else if (triple.find("armv4t-") == 0) + else if (Version == "v4t") ArmArch = Armv4t; - else if (triple.find("xscale-") == 0) + else if (Arch == "xscale" || Arch == "thumbv5e") ArmArch = XScale; - else if (triple.find("armv") == 0) { - // FIXME: fuzzy match for other random weird arm triples. This is useful - // for the static analyzer and other clients, but probably should be - // re-evaluated when codegen is brought up. + else ArmArch = Armv6; + + if (Arch.startswith("thumb")) + IsThumb = true; + + if (IsThumb) { + DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-" + "v64:64:64-v128:128:128-a0:0:32"); + } else { + DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-" + "v64:64:64-v128:128:128-a0:0:64"); } } + virtual const char *getABI() const { return ABI.c_str(); } + virtual bool setABI(const std::string &Name) { + ABI = Name; + + // The defaults (above) are for AAPCS, check if we need to change them. + // + // FIXME: We need support for -meabi... we could just mangle it into the + // name. + if (Name == "apcs-gnu") { + DoubleAlign = LongLongAlign = 32; + SizeType = UnsignedLong; + + if (IsThumb) { + DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-" + "i64:32:32-f32:32:32-f64:32:32-" + "v64:64:64-v128:128:128-a0:0:32"); + } else { + DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:32:32-f32:32:32-f64:32:32-" + "v64:64:64-v128:128:128-a0:0:64"); + } + + // FIXME: Override "preferred align" for double and long long. + } else if (Name == "aapcs") { + // FIXME: Enumerated types are variable width in straight AAPCS. + } else if (Name == "aapcs-linux") { + ; + } else + return false; + + return true; + } virtual void getTargetDefines(const LangOptions &Opts, std::vector &Defs) const { // Target identification. @@ -1014,7 +1236,13 @@ public: Define(Defs, "__LITTLE_ENDIAN__"); // Subtarget options. - if (ArmArch == Armv6) { + // + // FIXME: Neither THUMB_INTERWORK nor SOFTFP is not being set correctly + // here. + if (ArmArch == Armv7a) { + Define(Defs, "__ARM_ARCH_7A__"); + Define(Defs, "__THUMB_INTERWORK__"); + } else if (ArmArch == Armv6) { Define(Defs, "__ARM_ARCH_6K__"); Define(Defs, "__THUMB_INTERWORK__"); } else if (ArmArch == Armv5) { @@ -1029,9 +1257,22 @@ public: Define(Defs, "__XSCALE__"); Define(Defs, "__SOFTFP__"); } + Define(Defs, "__ARMEL__"); + + if (IsThumb) { + Define(Defs, "__THUMBEL__"); + Define(Defs, "__thumb__"); + if (ArmArch == Armv7a) + Define(Defs, "__thumb2__"); + } + + // Note, this is always on in gcc, even though it doesn't make sense. Define(Defs, "__APCS_32__"); + // FIXME: This should be conditional on VFP instruction support. Define(Defs, "__VFP_FP__"); + + Define(Defs, "__USING_SJLJ_EXCEPTIONS__"); } virtual void getTargetBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) const { @@ -1042,21 +1283,10 @@ public: virtual const char *getVAListDeclaration() const { return "typedef char* __builtin_va_list;"; } - virtual const char *getTargetPrefix() const { - return "arm"; - } virtual void getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const { - // FIXME: Implement. - Names = 0; - NumNames = 0; - } + unsigned &NumNames) const; virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const { - // FIXME: Implement. - Aliases = 0; - NumAliases = 0; - } + unsigned &NumAliases) const; virtual bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const { // FIXME: Check if this is complete @@ -1076,21 +1306,58 @@ public: return ""; } }; + +const char * const ARMTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" +}; + +void ARMTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); +} + +const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = { + + { { "a1" }, "r0" }, + { { "a2" }, "r1" }, + { { "a3" }, "r2" }, + { { "a4" }, "r3" }, + { { "v1" }, "r4" }, + { { "v2" }, "r5" }, + { { "v3" }, "r6" }, + { { "v4" }, "r7" }, + { { "v5" }, "r8" }, + { { "v6", "rfp" }, "r9" }, + { { "sl" }, "r10" }, + { { "fp" }, "r11" }, + { { "ip" }, "r12" }, + { { "sp" }, "r13" }, + { { "lr" }, "r14" }, + { { "pc" }, "r15" }, +}; + +void ARMTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); +} } // end anonymous namespace. namespace { -class DarwinARMTargetInfo : +class DarwinARMTargetInfo : public DarwinTargetInfo { protected: - virtual void getOSDefines(const LangOptions &Opts, const char *Triple, + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, std::vector &Defines) const { getDarwinDefines(Defines, Opts); getDarwinIPhoneOSDefines(Defines, Triple); } public: - DarwinARMTargetInfo(const std::string& triple) + DarwinARMTargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {} }; } // end anonymous namespace. @@ -1118,9 +1385,6 @@ public: virtual const char *getVAListDeclaration() const { return "typedef void* __builtin_va_list;"; } - virtual const char *getTargetPrefix() const { - return "sparc"; - } virtual void getGCCRegNames(const char * const *&Names, unsigned &NumNames) const; virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, @@ -1236,12 +1500,25 @@ namespace { virtual void getTargetDefines(const LangOptions &Opts, std::vector &Defines) const { Define(Defines, "__pic16"); + Define(Defines, "rom", "__attribute__((address_space(1)))"); + Define(Defines, "ram", "__attribute__((address_space(0)))"); + Define(Defines, "_section(SectName)", + "__attribute__((section(SectName)))"); + Define(Defines, "_address(Addr)", + "__attribute__((section(\"Address=\"#Addr)))"); + Define(Defines, "_CONFIG(conf)", "asm(\"CONFIG \"#conf)"); + Define(Defines, "_interrupt", + "__attribute__((section(\"interrupt=0x4\"))) \ + __attribute__((used))"); } virtual void getTargetBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) const {} - virtual const char *getVAListDeclaration() const { return "";} - virtual const char *getClobbers() const {return "";} - virtual const char *getTargetPrefix() const {return "pic16";} + virtual const char *getVAListDeclaration() const { + return ""; + } + virtual const char *getClobbers() const { + return ""; + } virtual void getGCCRegNames(const char * const *&Names, unsigned &NumNames) const {} virtual bool validateAsmConstraint(const char *&Name, @@ -1286,9 +1563,6 @@ namespace { Records = 0; NumRecords = 0; } - virtual const char *getTargetPrefix() const { - return "msp430"; - } virtual void getGCCRegNames(const char * const *&Names, unsigned &NumNames) const; virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, @@ -1325,93 +1599,309 @@ namespace { } +namespace { + class SystemZTargetInfo : public TargetInfo { + static const char * const GCCRegNames[]; + public: + SystemZTargetInfo(const std::string& triple) : TargetInfo(triple) { + TLSSupported = false; + IntWidth = IntAlign = 32; + LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64; + PointerWidth = PointerAlign = 64; + DescriptionString = "E-p:64:64:64-i8:8:16-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:128:128-a0:16:16"; + } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector &Defines) const { + Define(Defines, "__s390__"); + Define(Defines, "__s390x__"); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + // FIXME: Implement. + Records = 0; + NumRecords = 0; + } + + virtual void getDefaultLangOptions(LangOptions &Opts) { + TargetInfo::getDefaultLangOptions(Opts); + Opts.CharIsSigned = false; + } + + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const; + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + // No aliases. + Aliases = 0; + NumAliases = 0; + } + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const { + // FIXME: implement + return true; + } + virtual const char *getClobbers() const { + // FIXME: Is this really right? + return ""; + } + virtual const char *getVAListDeclaration() const { + // FIXME: implement + return "typedef char* __builtin_va_list;"; + } + }; + + const char * const SystemZTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" + }; + + void SystemZTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } +} + +namespace { + class BlackfinTargetInfo : public TargetInfo { + static const char * const GCCRegNames[]; + public: + BlackfinTargetInfo(const std::string& triple) : TargetInfo(triple) { + TLSSupported = false; + DoubleAlign = 32; + LongLongAlign = 32; + LongDoubleAlign = 32; + DescriptionString = "e-p:32:32-i64:32-f64:32"; + } + + virtual void getTargetDefines(const LangOptions &Opts, + std::vector &Defines) const { + DefineStd(Defines, "bfin", Opts); + DefineStd(Defines, "BFIN", Opts); + Define(Defines, "__ADSPBLACKFIN__"); + // FIXME: This one is really dependent on -mcpu + Define(Defines, "__ADSPLPBLACKFIN__"); + // FIXME: Add cpu-dependent defines and __SILICON_REVISION__ + } + + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + // FIXME: Implement. + Records = 0; + NumRecords = 0; + } + + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const; + + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + // No aliases. + Aliases = 0; + NumAliases = 0; + } + + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const { + if (strchr("adzDWeABbvfcCtukxywZY", Name[0])) { + Info.setAllowsRegister(); + return true; + } + return false; + } + + virtual const char *getClobbers() const { + return ""; + } + + virtual const char *getVAListDeclaration() const { + return "typedef char* __builtin_va_list;"; + } + }; + + const char * const BlackfinTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "p0", "p1", "p2", "p3", "p4", "p5", "sp", "fp", + "i0", "i1", "i2", "i3", "b0", "b1", "b2", "b3", + "l0", "l1", "l2", "l3", "m0", "m1", "m2", "m3", + "a0", "a1", "cc", + "rets", "reti", "retx", "retn", "rete", "astat", "seqstat", "usp", + "argp", "lt0", "lt1", "lc0", "lc1", "lb0", "lb1" + }; + + void BlackfinTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } +} + +namespace { + + // LLVM and Clang cannot be used directly to output native binaries for + // target, but is used to compile C code to llvm bitcode with correct + // type and alignment information. + // + // TCE uses the llvm bitcode as input and uses it for generating customized + // target processor and program binary. TCE co-design environment is + // publicly available in http://tce.cs.tut.fi + + class TCETargetInfo : public TargetInfo{ + public: + TCETargetInfo(const std::string& triple) : TargetInfo(triple) { + TLSSupported = false; + IntWidth = 32; + LongWidth = LongLongWidth = 32; + IntMaxTWidth = 32; + PointerWidth = 32; + IntAlign = 32; + LongAlign = LongLongAlign = 32; + PointerAlign = 32; + SizeType = UnsignedInt; + IntMaxType = SignedLong; + UIntMaxType = UnsignedLong; + IntPtrType = SignedInt; + PtrDiffType = SignedInt; + FloatWidth = 32; + FloatAlign = 32; + DoubleWidth = 32; + DoubleAlign = 32; + LongDoubleWidth = 32; + LongDoubleAlign = 32; + FloatFormat = &llvm::APFloat::IEEEsingle; + DoubleFormat = &llvm::APFloat::IEEEsingle; + LongDoubleFormat = &llvm::APFloat::IEEEsingle; + DescriptionString = "E-p:32:32:32-a0:32:32" + "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64" + "-f32:32:32-f64:32:64"; + } + + virtual void getTargetDefines(const LangOptions &Opts, + std::vector &Defines) const { + DefineStd(Defines, "tce", Opts); + Define(Defines, "__TCE__"); + Define(Defines, "__TCE_V1__"); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const {} + virtual const char *getClobbers() const { + return ""; + } + virtual const char *getVAListDeclaration() const { + return "typedef void* __builtin_va_list;"; + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const {} + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const { + return true; + } + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const {} + }; +} + //===----------------------------------------------------------------------===// // Driver code //===----------------------------------------------------------------------===// -static inline bool IsX86(const std::string& TT) { - return (TT.size() >= 5 && TT[0] == 'i' && TT[2] == '8' && TT[3] == '6' && - TT[4] == '-' && TT[1] - '3' < 6); -} - /// CreateTargetInfo - Return the target info object for the specified target /// triple. TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) { - // OS detection; this isn't really anywhere near complete. - // Additions and corrections are welcome. - bool isDarwin = T.find("-darwin") != std::string::npos; - bool isDragonFly = T.find("-dragonfly") != std::string::npos; - bool isOpenBSD = T.find("-openbsd") != std::string::npos; - bool isFreeBSD = T.find("-freebsd") != std::string::npos; - bool isSolaris = T.find("-solaris") != std::string::npos; - bool isLinux = T.find("-linux") != std::string::npos; - bool isWindows = T.find("-windows") != std::string::npos || - T.find("-win32") != std::string::npos || - T.find("-mingw") != std::string::npos; - - if (T.find("ppc-") == 0 || T.find("powerpc-") == 0) { - if (isDarwin) + llvm::Triple Triple(T); + llvm::Triple::OSType os = Triple.getOS(); + + switch (Triple.getArch()) { + default: + return NULL; + + case llvm::Triple::arm: + case llvm::Triple::thumb: + switch (os) { + case llvm::Triple::Darwin: + return new DarwinARMTargetInfo(T); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo(T); + default: + return new ARMTargetInfo(T); + } + + case llvm::Triple::bfin: + return new BlackfinTargetInfo(T); + + case llvm::Triple::msp430: + return new MSP430TargetInfo(T); + + case llvm::Triple::pic16: + return new PIC16TargetInfo(T); + + case llvm::Triple::ppc: + if (os == llvm::Triple::Darwin) return new DarwinTargetInfo(T); return new PPC32TargetInfo(T); - } - if (T.find("ppc64-") == 0 || T.find("powerpc64-") == 0) { - if (isDarwin) + case llvm::Triple::ppc64: + if (os == llvm::Triple::Darwin) return new DarwinTargetInfo(T); return new PPC64TargetInfo(T); - } - - if (T.find("armv") == 0 || T.find("arm-") == 0 || T.find("xscale") == 0) { - if (isDarwin) - return new DarwinARMTargetInfo(T); - if (isFreeBSD) - return new FreeBSDTargetInfo(T); - return new ARMTargetInfo(T); - } - if (T.find("sparc-") == 0) { - if (isSolaris) + case llvm::Triple::sparc: + if (os == llvm::Triple::Solaris) return new SolarisSparcV8TargetInfo(T); return new SparcV8TargetInfo(T); - } - - if (T.find("x86_64-") == 0 || T.find("amd64-") == 0) { - if (isDarwin) - return new DarwinX86_64TargetInfo(T); - if (isLinux) - return new LinuxTargetInfo(T); - if (isOpenBSD) - return new OpenBSDTargetInfo(T); - if (isFreeBSD) - return new FreeBSDTargetInfo(T); - if (isSolaris) - return new SolarisTargetInfo(T); - return new X86_64TargetInfo(T); - } - if (T.find("pic16-") == 0) - return new PIC16TargetInfo(T); + case llvm::Triple::systemz: + return new SystemZTargetInfo(T); - if (T.find("msp430-") == 0) - return new MSP430TargetInfo(T); + case llvm::Triple::tce: + return new TCETargetInfo(T); - if (IsX86(T)) { - if (isDarwin) + case llvm::Triple::x86: + switch (os) { + case llvm::Triple::Darwin: return new DarwinI386TargetInfo(T); - if (isLinux) + case llvm::Triple::Linux: return new LinuxTargetInfo(T); - if (isDragonFly) + case llvm::Triple::DragonFly: return new DragonFlyBSDTargetInfo(T); - if (isOpenBSD) - return new OpenBSDTargetInfo(T); - if (isFreeBSD) + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo(T); + case llvm::Triple::OpenBSD: + return new OpenBSDI386TargetInfo(T); + case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(T); - if (isSolaris) + case llvm::Triple::Solaris: return new SolarisTargetInfo(T); - if (isWindows) - return new WindowsX86_32TargetInfo(T); - return new X86_32TargetInfo(T); - } + case llvm::Triple::Cygwin: + return new CygwinX86_32TargetInfo(T); + case llvm::Triple::MinGW32: + return new MinGWX86_32TargetInfo(T); + case llvm::Triple::Win32: + return new VisualStudioWindowsX86_32TargetInfo(T); + default: + return new X86_32TargetInfo(T); + } - return NULL; + case llvm::Triple::x86_64: + switch (os) { + case llvm::Triple::Darwin: + return new DarwinX86_64TargetInfo(T); + case llvm::Triple::Linux: + return new LinuxTargetInfo(T); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo(T); + case llvm::Triple::OpenBSD: + return new OpenBSDX86_64TargetInfo(T); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo(T); + case llvm::Triple::Solaris: + return new SolarisTargetInfo(T); + case llvm::Triple::MinGW64: + return new MinGWX86_64TargetInfo(T); + case llvm::Triple::Win32: // This is what Triple.h supports now. + return new VisualStudioWindowsX86_64TargetInfo(T); + default: + return new X86_64TargetInfo(T); + } + } } diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp new file mode 100644 index 000000000000..30383f6251f6 --- /dev/null +++ b/lib/Basic/Version.cpp @@ -0,0 +1,49 @@ +//===- Version.cpp - Clang Version Number -----------------------*- 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 several version-related utility functions for Clang. +// +//===----------------------------------------------------------------------===// +#include +#include +using namespace std; + +namespace clang { + +const char *getClangSubversionPath() { + 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"); + if (End) + *End = 0; + + char *Begin = strstr(URL, "cfe/"); + if (Begin) { + Path = Begin + 4; + return Path; + } + + Path = URL; + return Path; +} + + +unsigned getClangSubversionRevision() { +#ifndef SVN_REVISION + // Subversion was not available at build time? + return 0; +#else + return strtol(SVN_REVISION, 0, 10); +#endif +} + +} // end namespace clang diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index e3da531011ee..2bfaa445e568 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -9,3 +9,4 @@ add_subdirectory(Analysis) add_subdirectory(Rewrite) add_subdirectory(Driver) add_subdirectory(Frontend) +add_subdirectory(Index) diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h index 58e5a778cf33..1ab2f55295fa 100644 --- a/lib/CodeGen/ABIInfo.h +++ b/lib/CodeGen/ABIInfo.h @@ -17,6 +17,7 @@ namespace llvm { class Type; class Value; + class LLVMContext; } namespace clang { @@ -71,11 +72,12 @@ namespace clang { Kind TheKind; const llvm::Type *TypeData; unsigned UIntData; + bool BoolData; ABIArgInfo(Kind K, const llvm::Type *TD=0, - unsigned UI=0) : TheKind(K), - TypeData(TD), - UIntData(UI) {} + unsigned UI=0, bool B = false) + : TheKind(K), TypeData(TD), UIntData(UI), BoolData(B) {} + public: ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {} @@ -91,8 +93,8 @@ namespace clang { static ABIArgInfo getCoerce(const llvm::Type *T) { return ABIArgInfo(Coerce, T); } - static ABIArgInfo getIndirect(unsigned Alignment) { - return ABIArgInfo(Indirect, 0, Alignment); + static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true) { + return ABIArgInfo(Indirect, 0, Alignment, ByVal); } static ABIArgInfo getExpand() { return ABIArgInfo(Expand); @@ -112,12 +114,17 @@ namespace clang { return TypeData; } - // ByVal accessors + // Indirect accessors unsigned getIndirectAlign() const { assert(TheKind == Indirect && "Invalid kind!"); return UIntData; } + bool getIndirectByVal() const { + assert(TheKind == Indirect && "Invalid kind!"); + return BoolData; + } + void dump() const; }; @@ -128,7 +135,8 @@ namespace clang { virtual ~ABIInfo(); virtual void computeInfo(CodeGen::CGFunctionInfo &FI, - ASTContext &Ctx) const = 0; + ASTContext &Ctx, + llvm::LLVMContext &VMContext) const = 0; /// EmitVAArg - Emit the target dependent code to load a value of /// \arg Ty from the va_list pointed to by \arg VAListAddr. diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index d5f803ba98bf..736425e01276 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -11,12 +11,15 @@ // //===----------------------------------------------------------------------===// +#include "CGDebugInfo.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "clang/AST/DeclObjC.h" #include "llvm/Module.h" #include "llvm/Target/TargetData.h" #include +#include + using namespace clang; using namespace CodeGen; @@ -48,24 +51,24 @@ BuildDescriptorBlockDecl(bool BlockHasCopyDispose, uint64_t Size, Elts.push_back(BuildDestroyHelper(Ty, NoteForHelper)); } - C = llvm::ConstantStruct::get(Elts); + C = llvm::ConstantStruct::get(VMContext, Elts, false); - C = new llvm::GlobalVariable(C->getType(), true, + C = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, llvm::GlobalValue::InternalLinkage, - C, "__block_descriptor_tmp", &CGM.getModule()); + C, "__block_descriptor_tmp"); return C; } llvm::Constant *BlockModule::getNSConcreteGlobalBlock() { if (NSConcreteGlobalBlock == 0) - NSConcreteGlobalBlock = CGM.CreateRuntimeVariable(PtrToInt8Ty, + NSConcreteGlobalBlock = CGM.CreateRuntimeVariable(PtrToInt8Ty, "_NSConcreteGlobalBlock"); return NSConcreteGlobalBlock; } llvm::Constant *BlockModule::getNSConcreteStackBlock() { if (NSConcreteStackBlock == 0) - NSConcreteStackBlock = CGM.CreateRuntimeVariable(PtrToInt8Ty, + NSConcreteStackBlock = CGM.CreateRuntimeVariable(PtrToInt8Ty, "_NSConcreteStackBlock"); return NSConcreteStackBlock; } @@ -125,7 +128,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { llvm::SmallVector subBlockDeclRefDecls; bool subBlockHasCopyDispose = false; llvm::Function *Fn - = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, CurFuncDecl, LocalDeclMap, + = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, CurFuncDecl, + LocalDeclMap, subBlockSize, subBlockAlign, subBlockDeclRefDecls, @@ -161,13 +165,13 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { Elts[0] = CGM.getNSConcreteGlobalBlock(); Elts[1] = llvm::ConstantInt::get(IntTy, flags|BLOCK_IS_GLOBAL); - C = llvm::ConstantStruct::get(Elts); + C = llvm::ConstantStruct::get(VMContext, Elts, false); char Name[32]; sprintf(Name, "__block_holder_tmp_%d", CGM.getGlobalUniqueCount()); - C = new llvm::GlobalVariable(C->getType(), true, + C = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, llvm::GlobalValue::InternalLinkage, - C, Name, &CGM.getModule()); + C, Name); QualType BPT = BE->getType(); C = llvm::ConstantExpr::getBitCast(C, ConvertType(BPT)); return C; @@ -183,13 +187,12 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { const BlockDeclRefExpr *BDRE = dyn_cast(E); QualType Ty = E->getType(); if (BDRE && BDRE->isByRef()) { - uint64_t Align = getContext().getDeclAlignInBytes(BDRE->getDecl()); - Types[i+5] = llvm::PointerType::get(BuildByRefType(Ty, Align), 0); + Types[i+5] = llvm::PointerType::get(BuildByRefType(BDRE->getDecl()), 0); } else Types[i+5] = ConvertType(Ty); } - llvm::StructType *Ty = llvm::StructType::get(Types, true); + llvm::StructType *Ty = llvm::StructType::get(VMContext, Types, true); llvm::AllocaInst *A = CreateTempAlloca(Ty); A->setAlignment(subBlockAlign); @@ -217,20 +220,21 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { llvm::Value* Addr = Builder.CreateStructGEP(V, i+5, "tmp"); NoteForHelper[helpersize].index = i+5; - NoteForHelper[helpersize].RequiresCopying = BlockRequiresCopying(VD->getType()); + NoteForHelper[helpersize].RequiresCopying + = BlockRequiresCopying(VD->getType()); NoteForHelper[helpersize].flag - = VD->getType()->isBlockPointerType() ? BLOCK_FIELD_IS_BLOCK : BLOCK_FIELD_IS_OBJECT; + = (VD->getType()->isBlockPointerType() + ? BLOCK_FIELD_IS_BLOCK + : BLOCK_FIELD_IS_OBJECT); if (LocalDeclMap[VD]) { if (BDRE->isByRef()) { NoteForHelper[helpersize].flag = BLOCK_FIELD_IS_BYREF | // FIXME: Someone double check this. (VD->getType().isObjCGCWeak() ? BLOCK_FIELD_IS_WEAK : 0); - const llvm::Type *Ty = Types[i+5]; llvm::Value *Loc = LocalDeclMap[VD]; Loc = Builder.CreateStructGEP(Loc, 1, "forwarding"); Loc = Builder.CreateLoad(Loc, false); - Loc = Builder.CreateBitCast(Loc, Ty); Builder.CreateStore(Loc, Addr); ++helpersize; continue; @@ -265,7 +269,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { llvm::Value *BlockLiteral = LoadBlockStruct(); Loc = Builder.CreateGEP(BlockLiteral, - llvm::ConstantInt::get(llvm::Type::Int64Ty, + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), offset), "block.literal"); Ty = llvm::PointerType::get(Ty, 0); @@ -310,7 +314,8 @@ const llvm::Type *BlockModule::getBlockDescriptorType() { // unsigned long reserved; // unsigned long block_size; // }; - BlockDescriptorType = llvm::StructType::get(UnsignedLongTy, + BlockDescriptorType = llvm::StructType::get(UnsignedLongTy->getContext(), + UnsignedLongTy, UnsignedLongTy, NULL); @@ -337,7 +342,8 @@ const llvm::Type *BlockModule::getGenericBlockLiteralType() { // void (*__invoke)(void *); // struct __block_descriptor *__descriptor; // }; - GenericBlockLiteralType = llvm::StructType::get(PtrToInt8Ty, + GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(), + PtrToInt8Ty, IntTy, IntTy, PtrToInt8Ty, @@ -369,7 +375,8 @@ const llvm::Type *BlockModule::getGenericExtendedBlockLiteralType() { // void *__copy_func_helper_decl; // void *__destroy_func_decl; // }; - GenericExtendedBlockLiteralType = llvm::StructType::get(PtrToInt8Ty, + GenericExtendedBlockLiteralType = llvm::StructType::get(IntTy->getContext(), + PtrToInt8Ty, IntTy, IntTy, PtrToInt8Ty, @@ -384,9 +391,13 @@ const llvm::Type *BlockModule::getGenericExtendedBlockLiteralType() { return GenericExtendedBlockLiteralType; } +bool BlockFunction::BlockRequiresCopying(QualType Ty) { + return CGM.BlockRequiresCopying(Ty); +} + RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) { const BlockPointerType *BPT = - E->getCallee()->getType()->getAsBlockPointerType(); + E->getCallee()->getType()->getAs(); llvm::Value *Callee = EmitScalarExpr(E->getCallee()); @@ -403,7 +414,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) { BlockLiteral = Builder.CreateBitCast(BlockLiteral, - llvm::PointerType::getUnqual(llvm::Type::Int8Ty), + llvm::Type::getInt8PtrTy(VMContext), "tmp"); // Add the block literal. @@ -414,33 +425,33 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) { QualType FnType = BPT->getPointeeType(); // And the rest of the arguments. - EmitCallArgs(Args, FnType->getAsFunctionProtoType(), + EmitCallArgs(Args, FnType->getAs(), E->arg_begin(), E->arg_end()); // Load the function. llvm::Value *Func = Builder.CreateLoad(FuncPtr, false, "tmp"); - QualType ResultType = FnType->getAsFunctionType()->getResultType(); + QualType ResultType = FnType->getAs()->getResultType(); - const CGFunctionInfo &FnInfo = + const CGFunctionInfo &FnInfo = CGM.getTypes().getFunctionInfo(ResultType, Args); - + // Cast the function pointer to the right type. - const llvm::Type *BlockFTy = + const llvm::Type *BlockFTy = CGM.getTypes().GetFunctionType(FnInfo, false); - + const llvm::Type *BlockFTyPtr = llvm::PointerType::getUnqual(BlockFTy); Func = Builder.CreateBitCast(Func, BlockFTyPtr); - + // And call the block. return EmitCall(FnInfo, Func, Args); } llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { - uint64_t &offset = BlockDecls[E->getDecl()]; + const ValueDecl *VD = E->getDecl(); + + uint64_t &offset = BlockDecls[VD]; - const llvm::Type *Ty; - Ty = CGM.getTypes().ConvertType(E->getDecl()->getType()); // See if we have already allocated an offset for this variable. if (offset == 0) { @@ -453,25 +464,27 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { llvm::Value *BlockLiteral = LoadBlockStruct(); llvm::Value *V = Builder.CreateGEP(BlockLiteral, - llvm::ConstantInt::get(llvm::Type::Int64Ty, - offset), + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), + offset), "block.literal"); if (E->isByRef()) { - bool needsCopyDispose = BlockRequiresCopying(E->getType()); - uint64_t Align = getContext().getDeclAlignInBytes(E->getDecl()); const llvm::Type *PtrStructTy - = llvm::PointerType::get(BuildByRefType(E->getType(), Align), 0); + = llvm::PointerType::get(BuildByRefType(VD), 0); // The block literal will need a copy/destroy helper. BlockHasCopyDispose = true; - Ty = PtrStructTy; + + const llvm::Type *Ty = PtrStructTy; Ty = llvm::PointerType::get(Ty, 0); V = Builder.CreateBitCast(V, Ty); V = Builder.CreateLoad(V, false); V = Builder.CreateStructGEP(V, 1, "forwarding"); V = Builder.CreateLoad(V, false); V = Builder.CreateBitCast(V, PtrStructTy); - V = Builder.CreateStructGEP(V, needsCopyDispose*2 + 4, "x"); + V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD), + VD->getNameAsString()); } else { + const llvm::Type *Ty = CGM.getTypes().ConvertType(VD->getType()); + Ty = llvm::PointerType::get(Ty, 0); V = Builder.CreateBitCast(V, Ty); } @@ -507,16 +520,16 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { // block literal struct. uint64_t BlockLiteralSize = TheTargetData.getTypeStoreSizeInBits(getGenericBlockLiteralType()) / 8; - DescriptorFields[1] = llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize); + DescriptorFields[1] = + llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize); llvm::Constant *DescriptorStruct = - llvm::ConstantStruct::get(&DescriptorFields[0], 2); + llvm::ConstantStruct::get(VMContext, &DescriptorFields[0], 2, false); llvm::GlobalVariable *Descriptor = - new llvm::GlobalVariable(DescriptorStruct->getType(), true, + new llvm::GlobalVariable(getModule(), DescriptorStruct->getType(), true, llvm::GlobalVariable::InternalLinkage, - DescriptorStruct, "__block_descriptor_global", - &getModule()); + DescriptorStruct, "__block_descriptor_global"); // Generate the constants for the block literal. llvm::Constant *LiteralFields[5]; @@ -552,13 +565,12 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { LiteralFields[4] = Descriptor; llvm::Constant *BlockLiteralStruct = - llvm::ConstantStruct::get(&LiteralFields[0], 5); + llvm::ConstantStruct::get(VMContext, &LiteralFields[0], 5, false); llvm::GlobalVariable *BlockLiteral = - new llvm::GlobalVariable(BlockLiteralStruct->getType(), true, + new llvm::GlobalVariable(getModule(), BlockLiteralStruct->getType(), true, llvm::GlobalVariable::InternalLinkage, - BlockLiteralStruct, "__block_literal_global", - &getModule()); + BlockLiteralStruct, "__block_literal_global"); return BlockLiteral; } @@ -580,7 +592,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, // Check if we should generate debug info for this block. if (CGM.getDebugInfo()) DebugInfo = CGM.getDebugInfo(); - + // Arrange for local static and local extern declarations to appear // to be local to this function as well, as they are directly referenced // in a block. @@ -588,7 +600,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, i != ldm.end(); ++i) { const VarDecl *VD = dyn_cast(i->first); - + if (VD->getStorageClass() == VarDecl::Static || VD->hasExternalStorage()) LocalDeclMap[VD] = i->second; } @@ -606,12 +618,11 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, const FunctionType *BlockFunctionType = BExpr->getFunctionType(); QualType ResultType; bool IsVariadic; - if (const FunctionProtoType *FTy = + if (const FunctionProtoType *FTy = dyn_cast(BlockFunctionType)) { ResultType = FTy->getResultType(); IsVariadic = FTy->isVariadic(); - } - else { + } else { // K&R style block. ResultType = BlockFunctionType->getResultType(); IsVariadic = false; @@ -650,9 +661,44 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, StartFunction(BD, ResultType, Fn, Args, BExpr->getBody()->getLocEnd()); + CurFuncDecl = OuterFuncDecl; CurCodeDecl = BD; + + // Save a spot to insert the debug information for all the BlockDeclRefDecls. + llvm::BasicBlock *entry = Builder.GetInsertBlock(); + llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint(); + --entry_ptr; + EmitStmt(BExpr->getBody()); + + // Remember where we were... + llvm::BasicBlock *resume = Builder.GetInsertBlock(); + + // Go back to the entry. + ++entry_ptr; + Builder.SetInsertPoint(entry, entry_ptr); + + 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(E); + if (BDRE) { + const ValueDecl *D = BDRE->getDecl(); + DI->setLocation(D->getLocation()); + DI->EmitDeclareOfBlockDeclRefVariable(BDRE, + LocalDeclMap[getBlockStructDecl()], + Builder, this); + } + } + } + // And resume where we left off. + if (resume == 0) + Builder.ClearInsertionPoint(); + else + Builder.SetInsertPoint(resume); + FinishFunction(cast(BExpr->getBody())->getRBracLoc()); // The runtime needs a minimum alignment of a void *. @@ -687,13 +733,12 @@ uint64_t BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) { uint64_t Pad = BlockOffset - OldOffset; if (Pad) { - llvm::ArrayType::get(llvm::Type::Int8Ty, Pad); + llvm::ArrayType::get(llvm::Type::getInt8Ty(VMContext), Pad); QualType PadTy = getContext().getConstantArrayType(getContext().CharTy, llvm::APInt(32, Pad), ArrayType::Normal, 0); ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(), - 0, QualType(PadTy), VarDecl::None, - SourceLocation()); + 0, QualType(PadTy), 0, VarDecl::None); Expr *E; E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(), SourceLocation(), false, false); @@ -720,7 +765,7 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T, ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, getContext().getPointerType(getContext().VoidTy)); Args.push_back(std::make_pair(Src, Src->getType())); - + const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args); @@ -740,7 +785,7 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T, FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), - SourceLocation(), II, R, + SourceLocation(), II, R, 0, FunctionDecl::Static, false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); @@ -776,7 +821,8 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T, llvm::Value *Dstv = Builder.CreateStructGEP(DstObj, index); Dstv = Builder.CreateBitCast(Dstv, PtrToInt8Ty); - llvm::Value *N = llvm::ConstantInt::get(llvm::Type::Int32Ty, flag); + llvm::Value *N = llvm::ConstantInt::get( + llvm::Type::getInt32Ty(T->getContext()), flag); llvm::Value *F = getBlockObjectAssign(); Builder.CreateCall3(F, Dstv, Srcv, N); } @@ -801,7 +847,7 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose, getContext().getPointerType(getContext().VoidTy)); Args.push_back(std::make_pair(Src, Src->getType())); - + const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args); @@ -821,7 +867,7 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose, FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), - SourceLocation(), II, R, + SourceLocation(), II, R, 0, FunctionDecl::Static, false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); @@ -885,7 +931,7 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) { ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, getContext().getPointerType(getContext().VoidTy)); Args.push_back(std::make_pair(Src, Src->getType())); - + const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args); @@ -905,7 +951,7 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) { FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), - SourceLocation(), II, R, + SourceLocation(), II, R, 0, FunctionDecl::Static, false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); @@ -924,10 +970,11 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) { V = Builder.CreateStructGEP(V, 6, "x"); V = Builder.CreateBitCast(V, llvm::PointerType::get(PtrToInt8Ty, 0)); llvm::Value *SrcObj = Builder.CreateLoad(V); - + flag |= BLOCK_BYREF_CALLER; - llvm::Value *N = llvm::ConstantInt::get(llvm::Type::Int32Ty, flag); + llvm::Value *N = llvm::ConstantInt::get( + llvm::Type::getInt32Ty(T->getContext()), flag); llvm::Value *F = getBlockObjectAssign(); Builder.CreateCall3(F, DstObj, SrcObj, N); @@ -948,7 +995,7 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, getContext().getPointerType(getContext().VoidTy)); Args.push_back(std::make_pair(Src, Src->getType())); - + const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args); @@ -968,7 +1015,7 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), - SourceLocation(), II, R, + SourceLocation(), II, R, 0, FunctionDecl::Static, false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); @@ -1024,9 +1071,9 @@ llvm::Value *BlockFunction::getBlockObjectDispose() { if (CGM.BlockObjectDispose == 0) { const llvm::FunctionType *FTy; std::vector ArgTys; - const llvm::Type *ResultType = llvm::Type::VoidTy; + const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext); ArgTys.push_back(PtrToInt8Ty); - ArgTys.push_back(llvm::Type::Int32Ty); + ArgTys.push_back(llvm::Type::getInt32Ty(VMContext)); FTy = llvm::FunctionType::get(ResultType, ArgTys, false); CGM.BlockObjectDispose = CGM.CreateRuntimeFunction(FTy, "_Block_object_dispose"); @@ -1038,10 +1085,10 @@ llvm::Value *BlockFunction::getBlockObjectAssign() { if (CGM.BlockObjectAssign == 0) { const llvm::FunctionType *FTy; std::vector ArgTys; - const llvm::Type *ResultType = llvm::Type::VoidTy; + const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext); ArgTys.push_back(PtrToInt8Ty); ArgTys.push_back(PtrToInt8Ty); - ArgTys.push_back(llvm::Type::Int32Ty); + ArgTys.push_back(llvm::Type::getInt32Ty(VMContext)); FTy = llvm::FunctionType::get(ResultType, ArgTys, false); CGM.BlockObjectAssign = CGM.CreateRuntimeFunction(FTy, "_Block_object_assign"); @@ -1053,7 +1100,7 @@ void BlockFunction::BuildBlockRelease(llvm::Value *V, int flag) { llvm::Value *F = getBlockObjectDispose(); llvm::Value *N; V = Builder.CreateBitCast(V, PtrToInt8Ty); - N = llvm::ConstantInt::get(llvm::Type::Int32Ty, flag); + N = llvm::ConstantInt::get(llvm::Type::getInt32Ty(V->getContext()), flag); Builder.CreateCall2(F, V, N); } @@ -1061,8 +1108,9 @@ ASTContext &BlockFunction::getContext() const { return CGM.getContext(); } BlockFunction::BlockFunction(CodeGenModule &cgm, CodeGenFunction &cgf, CGBuilderTy &B) - : CGM(cgm), CGF(cgf), Builder(B) { - PtrToInt8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + : CGM(cgm), CGF(cgf), VMContext(cgm.getLLVMContext()), Builder(B) { + PtrToInt8Ty = llvm::PointerType::getUnqual( + llvm::Type::getInt8Ty(VMContext)); BlockHasCopyDispose = false; } diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index 5d46ac78f693..3a860c0d3c36 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -16,6 +16,7 @@ #include "CodeGenTypes.h" #include "clang/AST/Type.h" +#include "llvm/Module.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "clang/Basic/TargetInfo.h" @@ -38,6 +39,7 @@ namespace llvm { class TargetData; class FunctionType; class Value; + class LLVMContext; } namespace clang { @@ -63,7 +65,8 @@ class BlockModule : public BlockBase { const llvm::TargetData &TheTargetData; CodeGenTypes &Types; CodeGenModule &CGM; - + llvm::LLVMContext &VMContext; + ASTContext &getContext() const { return Context; } llvm::Module &getModule() const { return TheModule; } CodeGenTypes &getTypes() { return Types; } @@ -86,7 +89,7 @@ public: /// NSConcreteStackBlock - Cached reference to the class poinnter for stack /// blocks. llvm::Constant *NSConcreteStackBlock; - + const llvm::Type *BlockDescriptorType; const llvm::Type *GenericBlockLiteralType; const llvm::Type *GenericExtendedBlockLiteralType; @@ -104,12 +107,22 @@ public: BlockModule(ASTContext &C, llvm::Module &M, const llvm::TargetData &TD, CodeGenTypes &T, CodeGenModule &CodeGen) : Context(C), TheModule(M), TheTargetData(TD), Types(T), - CGM(CodeGen), + CGM(CodeGen), VMContext(M.getContext()), NSConcreteGlobalBlock(0), NSConcreteStackBlock(0), BlockDescriptorType(0), GenericBlockLiteralType(0), GenericExtendedBlockLiteralType(0), BlockObjectAssign(0), BlockObjectDispose(0) { Block.GlobalUniqueCount = 0; - PtrToInt8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + PtrToInt8Ty = llvm::Type::getInt8PtrTy(M.getContext()); + } + + bool BlockRequiresCopying(QualType Ty) { + if (Ty->isBlockPointerType()) + return true; + if (getContext().isObjCNSObjectType(Ty)) + return true; + if (Ty->isObjCObjectPointerType()) + return true; + return false; } }; @@ -118,6 +131,9 @@ class BlockFunction : public BlockBase { CodeGenFunction &CGF; ASTContext &getContext() const; +protected: + llvm::LLVMContext &VMContext; + public: const llvm::Type *PtrToInt8Ty; struct HelperInfo { @@ -150,11 +166,11 @@ public: /// ByCopyDeclRefs - Variables from parent scopes that have been imported /// into this block. llvm::SmallVector ByCopyDeclRefs; - - // ByRefDeclRefs - __block variables from parent scopes that have been + + // ByRefDeclRefs - __block variables from parent scopes that have been // imported into this block. llvm::SmallVector ByRefDeclRefs; - + BlockInfo(const llvm::Type *blt, const char *n) : BlockLiteralTy(blt), Name(n) { // Skip asm prefix, if any. @@ -212,15 +228,7 @@ public: llvm::Value *getBlockObjectDispose(); void BuildBlockRelease(llvm::Value *DeclPtr, int flag = BLOCK_FIELD_IS_BYREF); - bool BlockRequiresCopying(QualType Ty) { - if (Ty->isBlockPointerType()) - return true; - if (getContext().isObjCNSObjectType(Ty)) - return true; - if (getContext().isObjCObjectPointerType(Ty)) - return true; - return false; - } + bool BlockRequiresCopying(QualType Ty); }; } // end namespace CodeGen diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index a919dfa2e32c..987cd24e2c8b 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -25,21 +25,21 @@ using namespace llvm; /// Utility to insert an atomic instruction based on Instrinsic::ID /// and the expression node. -static RValue EmitBinaryAtomic(CodeGenFunction& CGF, +static RValue EmitBinaryAtomic(CodeGenFunction& CGF, Intrinsic::ID Id, const CallExpr *E) { const llvm::Type *ResType[2]; ResType[0] = CGF.ConvertType(E->getType()); ResType[1] = CGF.ConvertType(E->getArg(0)->getType()); Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2); - return RValue::get(CGF.Builder.CreateCall2(AtomF, - CGF.EmitScalarExpr(E->getArg(0)), + return RValue::get(CGF.Builder.CreateCall2(AtomF, + CGF.EmitScalarExpr(E->getArg(0)), CGF.EmitScalarExpr(E->getArg(1)))); } /// Utility to insert an atomic instruction based Instrinsic::ID and // the expression node, where the return value is the result of the // operation. -static RValue EmitBinaryAtomicPost(CodeGenFunction& CGF, +static RValue EmitBinaryAtomicPost(CodeGenFunction& CGF, Intrinsic::ID Id, const CallExpr *E, Instruction::BinaryOps Op) { const llvm::Type *ResType[2]; @@ -49,25 +49,26 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction& CGF, Value *Ptr = CGF.EmitScalarExpr(E->getArg(0)); Value *Operand = CGF.EmitScalarExpr(E->getArg(1)); Value *Result = CGF.Builder.CreateCall2(AtomF, Ptr, Operand); - + if (Id == Intrinsic::atomic_load_nand) Result = CGF.Builder.CreateNot(Result); - - + + return RValue::get(CGF.Builder.CreateBinOp(Op, Result, Operand)); } -RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, +RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, unsigned BuiltinID, const CallExpr *E) { // See if we can constant fold this builtin. If so, don't emit it at all. Expr::EvalResult Result; if (E->Evaluate(Result, CGM.getContext())) { if (Result.Val.isInt()) - return RValue::get(llvm::ConstantInt::get(Result.Val.getInt())); + return RValue::get(llvm::ConstantInt::get(VMContext, + Result.Val.getInt())); else if (Result.Val.isFloat()) - return RValue::get(llvm::ConstantFP::get(Result.Val.getFloat())); + return RValue::get(ConstantFP::get(VMContext, Result.Val.getFloat())); } - + switch (BuiltinID) { default: break; // Handle intrinsics and libm functions below. case Builtin::BI__builtin___CFStringMakeConstantString: @@ -76,13 +77,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__builtin_va_start: case Builtin::BI__builtin_va_end: { Value *ArgValue = EmitVAListRef(E->getArg(0)); - const llvm::Type *DestType = - llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *DestType = llvm::Type::getInt8PtrTy(VMContext); if (ArgValue->getType() != DestType) - ArgValue = Builder.CreateBitCast(ArgValue, DestType, - ArgValue->getNameStart()); + ArgValue = Builder.CreateBitCast(ArgValue, DestType, + ArgValue->getName().data()); - Intrinsic::ID inst = (BuiltinID == Builtin::BI__builtin_va_end) ? + Intrinsic::ID inst = (BuiltinID == Builtin::BI__builtin_va_end) ? Intrinsic::vaend : Intrinsic::vastart; return RValue::get(Builder.CreateCall(CGM.getIntrinsic(inst), ArgValue)); } @@ -90,35 +90,35 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *DstPtr = EmitVAListRef(E->getArg(0)); Value *SrcPtr = EmitVAListRef(E->getArg(1)); - const llvm::Type *Type = - llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *Type = llvm::Type::getInt8PtrTy(VMContext); DstPtr = Builder.CreateBitCast(DstPtr, Type); SrcPtr = Builder.CreateBitCast(SrcPtr, Type); - return RValue::get(Builder.CreateCall2(CGM.getIntrinsic(Intrinsic::vacopy), + return RValue::get(Builder.CreateCall2(CGM.getIntrinsic(Intrinsic::vacopy), DstPtr, SrcPtr)); } case Builtin::BI__builtin_abs: { - Value *ArgValue = EmitScalarExpr(E->getArg(0)); - + Value *ArgValue = EmitScalarExpr(E->getArg(0)); + Value *NegOp = Builder.CreateNeg(ArgValue, "neg"); - Value *CmpResult = - Builder.CreateICmpSGE(ArgValue, Constant::getNullValue(ArgValue->getType()), + Value *CmpResult = + Builder.CreateICmpSGE(ArgValue, + llvm::Constant::getNullValue(ArgValue->getType()), "abscond"); - Value *Result = + Value *Result = Builder.CreateSelect(CmpResult, ArgValue, NegOp, "abs"); - + return RValue::get(Result); } case Builtin::BI__builtin_ctz: case Builtin::BI__builtin_ctzl: case Builtin::BI__builtin_ctzll: { Value *ArgValue = EmitScalarExpr(E->getArg(0)); - + const llvm::Type *ArgType = ArgValue->getType(); Value *F = CGM.getIntrinsic(Intrinsic::cttz, &ArgType, 1); - const llvm::Type *ResultType = ConvertType(E->getType()); + const llvm::Type *ResultType = ConvertType(E->getType()); Value *Result = Builder.CreateCall(F, ArgValue, "tmp"); if (Result->getType() != ResultType) Result = Builder.CreateIntCast(Result, ResultType, "cast"); @@ -128,11 +128,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__builtin_clzl: case Builtin::BI__builtin_clzll: { Value *ArgValue = EmitScalarExpr(E->getArg(0)); - + const llvm::Type *ArgType = ArgValue->getType(); Value *F = CGM.getIntrinsic(Intrinsic::ctlz, &ArgType, 1); - const llvm::Type *ResultType = ConvertType(E->getType()); + const llvm::Type *ResultType = ConvertType(E->getType()); Value *Result = Builder.CreateCall(F, ArgValue, "tmp"); if (Result->getType() != ResultType) Result = Builder.CreateIntCast(Result, ResultType, "cast"); @@ -143,13 +143,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__builtin_ffsll: { // ffs(x) -> x ? cttz(x) + 1 : 0 Value *ArgValue = EmitScalarExpr(E->getArg(0)); - + const llvm::Type *ArgType = ArgValue->getType(); Value *F = CGM.getIntrinsic(Intrinsic::cttz, &ArgType, 1); - + const llvm::Type *ResultType = ConvertType(E->getType()); - Value *Tmp = Builder.CreateAdd(Builder.CreateCall(F, ArgValue, "tmp"), - ConstantInt::get(ArgType, 1), "tmp"); + Value *Tmp = Builder.CreateAdd(Builder.CreateCall(F, ArgValue, "tmp"), + llvm::ConstantInt::get(ArgType, 1), "tmp"); Value *Zero = llvm::Constant::getNullValue(ArgType); Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero, "iszero"); Value *Result = Builder.CreateSelect(IsZero, Zero, Tmp, "ffs"); @@ -162,13 +162,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__builtin_parityll: { // parity(x) -> ctpop(x) & 1 Value *ArgValue = EmitScalarExpr(E->getArg(0)); - + const llvm::Type *ArgType = ArgValue->getType(); Value *F = CGM.getIntrinsic(Intrinsic::ctpop, &ArgType, 1); - + const llvm::Type *ResultType = ConvertType(E->getType()); Value *Tmp = Builder.CreateCall(F, ArgValue, "tmp"); - Value *Result = Builder.CreateAnd(Tmp, ConstantInt::get(ArgType, 1), + Value *Result = Builder.CreateAnd(Tmp, llvm::ConstantInt::get(ArgType, 1), "tmp"); if (Result->getType() != ResultType) Result = Builder.CreateIntCast(Result, ResultType, "cast"); @@ -178,10 +178,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__builtin_popcountl: case Builtin::BI__builtin_popcountll: { Value *ArgValue = EmitScalarExpr(E->getArg(0)); - + const llvm::Type *ArgType = ArgValue->getType(); Value *F = CGM.getIntrinsic(Intrinsic::ctpop, &ArgType, 1); - + const llvm::Type *ResultType = ConvertType(E->getType()); Value *Result = Builder.CreateCall(F, ArgValue, "tmp"); if (Result->getType() != ResultType) @@ -197,7 +197,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, const llvm::Type *ArgType = ArgValue->getType(); Value *F = CGM.getIntrinsic(Intrinsic::bswap, &ArgType, 1); return RValue::get(Builder.CreateCall(F, ArgValue, "tmp")); - } + } case Builtin::BI__builtin_object_size: { // FIXME: Implement. For now we just always fail and pretend we // don't know the object size. @@ -205,15 +205,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, const llvm::Type *ResType = ConvertType(E->getType()); // bool UseSubObject = TypeArg.getZExtValue() & 1; bool UseMinimum = TypeArg.getZExtValue() & 2; - return RValue::get(ConstantInt::get(ResType, UseMinimum ? 0 : -1LL)); + return RValue::get( + llvm::ConstantInt::get(ResType, UseMinimum ? 0 : -1LL)); } case Builtin::BI__builtin_prefetch: { Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0)); // FIXME: Technically these constants should of type 'int', yes? - RW = (E->getNumArgs() > 1) ? EmitScalarExpr(E->getArg(1)) : - ConstantInt::get(llvm::Type::Int32Ty, 0); - Locality = (E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) : - ConstantInt::get(llvm::Type::Int32Ty, 3); + RW = (E->getNumArgs() > 1) ? EmitScalarExpr(E->getArg(1)) : + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0); + Locality = (E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) : + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 3); Value *F = CGM.getIntrinsic(Intrinsic::prefetch, 0, 0); return RValue::get(Builder.CreateCall3(F, Address, RW, Locality)); } @@ -221,7 +222,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *F = CGM.getIntrinsic(Intrinsic::trap, 0, 0); return RValue::get(Builder.CreateCall(F)); } - + case Builtin::BI__builtin_unreachable: { + Value *V = Builder.CreateUnreachable(); + Builder.ClearInsertionPoint(); + return RValue::get(V); + } + case Builtin::BI__builtin_powi: case Builtin::BI__builtin_powif: case Builtin::BI__builtin_powil: { @@ -240,9 +246,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__builtin_isunordered: { // Ordered comparisons: we know the arguments to these are matching scalar // floating point values. - Value *LHS = EmitScalarExpr(E->getArg(0)); + Value *LHS = EmitScalarExpr(E->getArg(0)); Value *RHS = EmitScalarExpr(E->getArg(1)); - + switch (BuiltinID) { default: assert(0 && "Unknown ordered comparison"); case Builtin::BI__builtin_isgreater: @@ -260,7 +266,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__builtin_islessgreater: LHS = Builder.CreateFCmpONE(LHS, RHS, "cmp"); break; - case Builtin::BI__builtin_isunordered: + case Builtin::BI__builtin_isunordered: LHS = Builder.CreateFCmpUNO(LHS, RHS, "cmp"); break; } @@ -268,19 +274,24 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Builder.CreateZExt(LHS, ConvertType(E->getType()), "tmp")); } + case Builtin::BI__builtin_isnan: { + Value *V = EmitScalarExpr(E->getArg(0)); + V = Builder.CreateFCmpUNO(V, V, "cmp"); + return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()), "tmp")); + } case Builtin::BIalloca: case Builtin::BI__builtin_alloca: { // FIXME: LLVM IR Should allow alloca with an i64 size! Value *Size = EmitScalarExpr(E->getArg(0)); - Size = Builder.CreateIntCast(Size, llvm::Type::Int32Ty, false, "tmp"); - return RValue::get(Builder.CreateAlloca(llvm::Type::Int8Ty, Size, "tmp")); + Size = Builder.CreateIntCast(Size, llvm::Type::getInt32Ty(VMContext), false, "tmp"); + return RValue::get(Builder.CreateAlloca(llvm::Type::getInt8Ty(VMContext), Size, "tmp")); } case Builtin::BI__builtin_bzero: { Value *Address = EmitScalarExpr(E->getArg(0)); Builder.CreateCall4(CGM.getMemSetFn(), Address, - llvm::ConstantInt::get(llvm::Type::Int8Ty, 0), + llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 0), EmitScalarExpr(E->getArg(1)), - llvm::ConstantInt::get(llvm::Type::Int32Ty, 1)); + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1)); return RValue::get(Address); } case Builtin::BI__builtin_memcpy: { @@ -288,7 +299,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Builder.CreateCall4(CGM.getMemCpyFn(), Address, EmitScalarExpr(E->getArg(1)), EmitScalarExpr(E->getArg(2)), - llvm::ConstantInt::get(llvm::Type::Int32Ty, 1)); + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1)); return RValue::get(Address); } case Builtin::BI__builtin_memmove: { @@ -296,16 +307,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Builder.CreateCall4(CGM.getMemMoveFn(), Address, EmitScalarExpr(E->getArg(1)), EmitScalarExpr(E->getArg(2)), - llvm::ConstantInt::get(llvm::Type::Int32Ty, 1)); + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1)); return RValue::get(Address); } case Builtin::BI__builtin_memset: { Value *Address = EmitScalarExpr(E->getArg(0)); Builder.CreateCall4(CGM.getMemSetFn(), Address, Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)), - llvm::Type::Int8Ty), + llvm::Type::getInt8Ty(VMContext)), EmitScalarExpr(E->getArg(2)), - llvm::ConstantInt::get(llvm::Type::Int32Ty, 1)); + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1)); return RValue::get(Address); } case Builtin::BI__builtin_return_address: { @@ -332,20 +343,18 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *FrameAddrF = CGM.getIntrinsic(Intrinsic::frameaddress, 0, 0); Value *FrameAddr = Builder.CreateCall(FrameAddrF, - Constant::getNullValue(llvm::Type::Int32Ty)); + Constant::getNullValue(llvm::Type::getInt32Ty(VMContext))); Builder.CreateStore(FrameAddr, Buf); // Call the setjmp intrinsic Value *F = CGM.getIntrinsic(Intrinsic::eh_sjlj_setjmp, 0, 0); - const llvm::Type *DestType = - llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *DestType = llvm::Type::getInt8PtrTy(VMContext); Buf = Builder.CreateBitCast(Buf, DestType); return RValue::get(Builder.CreateCall(F, Buf)); } case Builtin::BI__builtin_longjmp: { Value *F = CGM.getIntrinsic(Intrinsic::eh_sjlj_longjmp, 0, 0); Value *Buf = EmitScalarExpr(E->getArg(0)); - const llvm::Type *DestType = - llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *DestType = llvm::Type::getInt8PtrTy(VMContext); Buf = Builder.CreateBitCast(Buf, DestType); return RValue::get(Builder.CreateCall(F, Buf)); } @@ -401,7 +410,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_fetch_and_nand_8: case Builtin::BI__sync_fetch_and_nand_16: return EmitBinaryAtomic(*this, Intrinsic::atomic_load_nand, E); - + // Clang extensions: not overloaded yet. case Builtin::BI__sync_fetch_and_min: return EmitBinaryAtomic(*this, Intrinsic::atomic_load_min, E); @@ -417,7 +426,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_add_and_fetch_4: case Builtin::BI__sync_add_and_fetch_8: case Builtin::BI__sync_add_and_fetch_16: - return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_add, E, + return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_add, E, llvm::Instruction::Add); case Builtin::BI__sync_sub_and_fetch_1: case Builtin::BI__sync_sub_and_fetch_2: @@ -454,7 +463,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_nand_and_fetch_16: return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_nand, E, llvm::Instruction::And); - + case Builtin::BI__sync_val_compare_and_swap_1: case Builtin::BI__sync_val_compare_and_swap_2: case Builtin::BI__sync_val_compare_and_swap_4: @@ -465,7 +474,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, ResType[0]= ConvertType(E->getType()); ResType[1] = ConvertType(E->getArg(0)->getType()); Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2); - return RValue::get(Builder.CreateCall3(AtomF, + return RValue::get(Builder.CreateCall3(AtomF, EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1)), EmitScalarExpr(E->getArg(2)))); @@ -482,7 +491,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, ResType[1] = llvm::PointerType::getUnqual(ResType[0]); Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2); Value *OldVal = EmitScalarExpr(E->getArg(1)); - Value *PrevVal = Builder.CreateCall3(AtomF, + Value *PrevVal = Builder.CreateCall3(AtomF, EmitScalarExpr(E->getArg(0)), OldVal, EmitScalarExpr(E->getArg(2))); @@ -511,12 +520,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_synchronize: { Value *C[5]; - C[0] = C[1] = C[2] = C[3] = llvm::ConstantInt::get(llvm::Type::Int1Ty, 1); - C[4] = ConstantInt::get(llvm::Type::Int1Ty, 0); + C[0] = C[1] = C[2] = C[3] = llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 1); + C[4] = llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 0); Builder.CreateCall(CGM.getIntrinsic(Intrinsic::memory_barrier), C, C + 5); return RValue::get(0); } - + // Library functions with special handling. case Builtin::BIsqrt: case Builtin::BIsqrtf: @@ -543,29 +552,31 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Builder.CreateCall2(F, Base, Exponent, "tmp")); } } - + // If this is an alias for a libm function (e.g. __builtin_sin) turn it into // that function. if (getContext().BuiltinInfo.isLibFunction(BuiltinID) || getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID)) - return EmitCall(CGM.getBuiltinLibFunction(BuiltinID), + return EmitCall(CGM.getBuiltinLibFunction(FD, BuiltinID), E->getCallee()->getType(), E->arg_begin(), E->arg_end()); - + // See if we have a target specific intrinsic. const char *Name = getContext().BuiltinInfo.GetName(BuiltinID); - Intrinsic::ID IntrinsicID = - Intrinsic::getIntrinsicForGCCBuiltin(Target.getTargetPrefix(), Name); - + Intrinsic::ID IntrinsicID = Intrinsic::not_intrinsic; + if (const char *Prefix = + llvm::Triple::getArchTypePrefix(Target.getTriple().getArch())) + IntrinsicID = Intrinsic::getIntrinsicForGCCBuiltin(Prefix, Name); + if (IntrinsicID != Intrinsic::not_intrinsic) { SmallVector Args; - + Function *F = CGM.getIntrinsic(IntrinsicID); const llvm::FunctionType *FTy = F->getFunctionType(); - + for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) { Value *ArgValue = EmitScalarExpr(E->getArg(i)); - + // If the intrinsic arg type is different from the builtin arg type // we need to do a bit cast. const llvm::Type *PTy = FTy->getParamType(i); @@ -574,50 +585,54 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, "Must be able to losslessly bit cast to param"); ArgValue = Builder.CreateBitCast(ArgValue, PTy); } - + Args.push_back(ArgValue); } - + Value *V = Builder.CreateCall(F, Args.data(), Args.data() + Args.size()); QualType BuiltinRetType = E->getType(); - - const llvm::Type *RetTy = llvm::Type::VoidTy; + + const llvm::Type *RetTy = llvm::Type::getVoidTy(VMContext); if (!BuiltinRetType->isVoidType()) RetTy = ConvertType(BuiltinRetType); - + if (RetTy != V->getType()) { assert(V->getType()->canLosslesslyBitCastTo(RetTy) && "Must be able to losslessly bit cast result type"); V = Builder.CreateBitCast(V, RetTy); } - + return RValue::get(V); } - + // See if we have a target specific builtin that needs to be lowered. if (Value *V = EmitTargetBuiltinExpr(BuiltinID, E)) return RValue::get(V); - + ErrorUnsupported(E, "builtin function"); - + // Unknown builtin, for now just dump it out and return undef. if (hasAggregateLLVMType(E->getType())) return RValue::getAggregate(CreateTempAlloca(ConvertType(E->getType()))); - return RValue::get(UndefValue::get(ConvertType(E->getType()))); -} + return RValue::get(llvm::UndefValue::get(ConvertType(E->getType()))); +} Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { - const char *TargetPrefix = Target.getTargetPrefix(); - if (strcmp(TargetPrefix, "x86") == 0) + switch (Target.getTriple().getArch()) { + case llvm::Triple::x86: + case llvm::Triple::x86_64: return EmitX86BuiltinExpr(BuiltinID, E); - else if (strcmp(TargetPrefix, "ppc") == 0) + case llvm::Triple::ppc: + case llvm::Triple::ppc64: return EmitPPCBuiltinExpr(BuiltinID, E); - return 0; + default: + return 0; + } } -Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, +Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E) { - + llvm::SmallVector Ops; for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) @@ -625,23 +640,23 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, switch (BuiltinID) { default: return 0; - case X86::BI__builtin_ia32_pslldi128: + case X86::BI__builtin_ia32_pslldi128: case X86::BI__builtin_ia32_psllqi128: - case X86::BI__builtin_ia32_psllwi128: + case X86::BI__builtin_ia32_psllwi128: case X86::BI__builtin_ia32_psradi128: case X86::BI__builtin_ia32_psrawi128: case X86::BI__builtin_ia32_psrldi128: case X86::BI__builtin_ia32_psrlqi128: case X86::BI__builtin_ia32_psrlwi128: { - Ops[1] = Builder.CreateZExt(Ops[1], llvm::Type::Int64Ty, "zext"); - const llvm::Type *Ty = llvm::VectorType::get(llvm::Type::Int64Ty, 2); - llvm::Value *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); + Ops[1] = Builder.CreateZExt(Ops[1], llvm::Type::getInt64Ty(VMContext), "zext"); + const llvm::Type *Ty = llvm::VectorType::get(llvm::Type::getInt64Ty(VMContext), 2); + llvm::Value *Zero = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0); Ops[1] = Builder.CreateInsertElement(llvm::UndefValue::get(Ty), Ops[1], Zero, "insert"); Ops[1] = Builder.CreateBitCast(Ops[1], Ops[0]->getType(), "bitcast"); const char *name = 0; Intrinsic::ID ID = Intrinsic::not_intrinsic; - + switch (BuiltinID) { default: assert(0 && "Unsupported shift intrinsic!"); case X86::BI__builtin_ia32_pslldi128: @@ -678,22 +693,22 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, break; } llvm::Function *F = CGM.getIntrinsic(ID); - return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name); + return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name); } - case X86::BI__builtin_ia32_pslldi: + case X86::BI__builtin_ia32_pslldi: case X86::BI__builtin_ia32_psllqi: - case X86::BI__builtin_ia32_psllwi: + case X86::BI__builtin_ia32_psllwi: case X86::BI__builtin_ia32_psradi: case X86::BI__builtin_ia32_psrawi: case X86::BI__builtin_ia32_psrldi: case X86::BI__builtin_ia32_psrlqi: case X86::BI__builtin_ia32_psrlwi: { - Ops[1] = Builder.CreateZExt(Ops[1], llvm::Type::Int64Ty, "zext"); - const llvm::Type *Ty = llvm::VectorType::get(llvm::Type::Int64Ty, 1); + Ops[1] = Builder.CreateZExt(Ops[1], llvm::Type::getInt64Ty(VMContext), "zext"); + const llvm::Type *Ty = llvm::VectorType::get(llvm::Type::getInt64Ty(VMContext), 1); Ops[1] = Builder.CreateBitCast(Ops[1], Ty, "bitcast"); const char *name = 0; Intrinsic::ID ID = Intrinsic::not_intrinsic; - + switch (BuiltinID) { default: assert(0 && "Unsupported shift intrinsic!"); case X86::BI__builtin_ia32_pslldi: @@ -730,7 +745,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, break; } llvm::Function *F = CGM.getIntrinsic(ID); - return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name); + return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name); } case X86::BI__builtin_ia32_cmpps: { llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ps); @@ -741,17 +756,17 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "cmpss"); } case X86::BI__builtin_ia32_ldmxcsr: { - llvm::Type *PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); - Value *One = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1); - Value *Tmp = Builder.CreateAlloca(llvm::Type::Int32Ty, One, "tmp"); + const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext); + Value *One = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1); + Value *Tmp = Builder.CreateAlloca(llvm::Type::getInt32Ty(VMContext), One, "tmp"); Builder.CreateStore(Ops[0], Tmp); return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_ldmxcsr), Builder.CreateBitCast(Tmp, PtrTy)); } case X86::BI__builtin_ia32_stmxcsr: { - llvm::Type *PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); - Value *One = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1); - Value *Tmp = Builder.CreateAlloca(llvm::Type::Int32Ty, One, "tmp"); + const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext); + Value *One = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1); + Value *Tmp = Builder.CreateAlloca(llvm::Type::getInt32Ty(VMContext), One, "tmp"); One = Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_stmxcsr), Builder.CreateBitCast(Tmp, PtrTy)); return Builder.CreateLoad(Tmp, "stmxcsr"); @@ -766,16 +781,16 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, } case X86::BI__builtin_ia32_storehps: case X86::BI__builtin_ia32_storelps: { - const llvm::Type *EltTy = llvm::Type::Int64Ty; + const llvm::Type *EltTy = llvm::Type::getInt64Ty(VMContext); llvm::Type *PtrTy = llvm::PointerType::getUnqual(EltTy); llvm::Type *VecTy = llvm::VectorType::get(EltTy, 2); - + // cast val v2i64 Ops[1] = Builder.CreateBitCast(Ops[1], VecTy, "cast"); - + // extract (0, 1) unsigned Index = BuiltinID == X86::BI__builtin_ia32_storelps ? 0 : 1; - llvm::Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, Index); + llvm::Value *Idx = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Index); Ops[1] = Builder.CreateExtractElement(Ops[1], Idx, "extract"); // cast pointer to i64 & store @@ -785,9 +800,9 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, } } -Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, +Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { switch (BuiltinID) { default: return 0; } -} +} diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 5f3acea767d5..3960cf51868f 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -11,22 +11,123 @@ // //===----------------------------------------------------------------------===// -// We might split this into multiple files if it gets too unwieldy +// We might split this into multiple files if it gets too unwieldy #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "Mangle.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/StmtCXX.h" #include "llvm/ADT/StringExtras.h" using namespace clang; using namespace CodeGen; -void -CodeGenFunction::GenerateStaticCXXBlockVarDeclInit(const VarDecl &D, - llvm::GlobalVariable *GV) { +void +CodeGenFunction::EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor, + llvm::Constant *DeclPtr) { + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8Ty(VMContext)->getPointerTo(); + + std::vector Params; + Params.push_back(Int8PtrTy); + + // Get the destructor function type + const llvm::Type *DtorFnTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false); + DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy); + + Params.clear(); + Params.push_back(DtorFnTy); + Params.push_back(Int8PtrTy); + Params.push_back(Int8PtrTy); + + // Get the __cxa_atexit function type + // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d ); + const llvm::FunctionType *AtExitFnTy = + llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false); + + llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy, + "__cxa_atexit"); + + llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy, + "__dso_handle"); + + llvm::Constant *DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete); + + llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy), + llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy), + llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) }; + Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args)); +} + +void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, + llvm::Constant *DeclPtr) { + assert(D.hasGlobalStorage() && + "VarDecl must have global storage!"); + + const Expr *Init = D.getInit(); + QualType T = D.getType(); + + if (T->isReferenceType()) { + ErrorUnsupported(Init, "global variable that binds to a reference"); + } else if (!hasAggregateLLVMType(T)) { + llvm::Value *V = EmitScalarExpr(Init); + EmitStoreOfScalar(V, DeclPtr, T.isVolatileQualified(), T); + } else if (T->isAnyComplexType()) { + EmitComplexExprIntoAddr(Init, DeclPtr, T.isVolatileQualified()); + } else { + EmitAggExpr(Init, DeclPtr, T.isVolatileQualified()); + + if (const RecordType *RT = T->getAs()) { + CXXRecordDecl *RD = cast(RT->getDecl()); + if (!RD->hasTrivialDestructor()) + EmitCXXGlobalDtorRegistration(RD->getDestructor(getContext()), DeclPtr); + } + } +} + +void +CodeGenModule::EmitCXXGlobalInitFunc() { + if (CXXGlobalInits.empty()) + return; + + const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + false); + + // Create our global initialization function. + // FIXME: Should this be tweakable by targets? + llvm::Function *Fn = + llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, + "__cxx_global_initialization", &TheModule); + + CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, + &CXXGlobalInits[0], + CXXGlobalInits.size()); + AddGlobalCtor(Fn); +} + +void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, + const VarDecl **Decls, + unsigned NumDecls) { + StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), + SourceLocation()); + + for (unsigned i = 0; i != NumDecls; ++i) { + const VarDecl *D = Decls[i]; + + llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D); + EmitCXXGlobalVarDeclInit(*D, DeclPtr); + } + FinishFunction(); +} + +void +CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, + llvm::GlobalVariable *GV) { // FIXME: This should use __cxa_guard_{acquire,release}? assert(!getContext().getLangOptions().ThreadsafeStatics && @@ -34,46 +135,37 @@ CodeGenFunction::GenerateStaticCXXBlockVarDeclInit(const VarDecl &D, llvm::SmallString<256> GuardVName; llvm::raw_svector_ostream GuardVOut(GuardVName); - mangleGuardVariable(&D, getContext(), GuardVOut); - + mangleGuardVariable(CGM.getMangleContext(), &D, GuardVOut); + // Create the guard variable. - llvm::GlobalValue *GuardV = - new llvm::GlobalVariable(llvm::Type::Int64Ty, false, + llvm::GlobalValue *GuardV = + new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext), false, GV->getLinkage(), - llvm::Constant::getNullValue(llvm::Type::Int64Ty), - GuardVName.c_str(), - &CGM.getModule()); - + llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)), + GuardVName.str()); + // Load the first byte of the guard variable. - const llvm::Type *PtrTy = llvm::PointerType::get(llvm::Type::Int8Ty, 0); - llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy), + 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::Int8Ty); + llvm::Value *nullValue = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)); llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool"); - + llvm::BasicBlock *InitBlock = createBasicBlock("init"); llvm::BasicBlock *EndBlock = createBasicBlock("init.end"); // If the guard variable is 0, jump to the initializer code. Builder.CreateCondBr(ICmp, InitBlock, EndBlock); - + EmitBlock(InitBlock); - const Expr *Init = D.getInit(); - if (!hasAggregateLLVMType(Init->getType())) { - llvm::Value *V = EmitScalarExpr(Init); - Builder.CreateStore(V, GV, D.getType().isVolatileQualified()); - } else if (Init->getType()->isAnyComplexType()) { - EmitComplexExprIntoAddr(Init, GV, D.getType().isVolatileQualified()); - } else { - EmitAggExpr(Init, GV, D.getType().isVolatileQualified()); - } - - Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::Int8Ty, 1), + EmitCXXGlobalVarDeclInit(D, GV); + + Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 1), Builder.CreateBitCast(GuardV, PtrTy)); - + EmitBlock(EndBlock); } @@ -82,336 +174,1399 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd) { - assert(MD->isInstance() && + assert(MD->isInstance() && "Trying to emit a member call expr on a static method!"); - const FunctionProtoType *FPT = MD->getType()->getAsFunctionProtoType(); - + // A call to a trivial destructor requires no code generation. + if (const CXXDestructorDecl *Destructor = dyn_cast(MD)) + if (Destructor->isTrivial()) + return RValue::get(0); + + const FunctionProtoType *FPT = MD->getType()->getAs(); + CallArgList Args; - + // Push the this ptr. Args.push_back(std::make_pair(RValue::get(This), MD->getThisType(getContext()))); - + // And the rest of the call args EmitCallArgs(Args, FPT, ArgBeg, ArgEnd); - - QualType ResultType = MD->getType()->getAsFunctionType()->getResultType(); + + QualType ResultType = MD->getType()->getAs()->getResultType(); return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, Args, MD); } +/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given +/// expr can be devirtualized. +static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) { + if (const DeclRefExpr *DRE = dyn_cast(Base)) { + if (const VarDecl *VD = dyn_cast(DRE->getDecl())) { + // This is a record decl. We know the type and can devirtualize it. + return VD->getType()->isRecordType(); + } + + return false; + } + + // We can always devirtualize calls on temporary object expressions. + if (isa(Base)) + return true; + + // And calls on bound temporaries. + if (isa(Base)) + return true; + + // Check if this is a call expr that returns a record type. + if (const CallExpr *CE = dyn_cast(Base)) + return CE->getCallReturnType()->isRecordType(); + + // We can't devirtualize the call. + return false; +} + RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { + if (isa(CE->getCallee())) + return EmitCXXMemberPointerCallExpr(CE); + const MemberExpr *ME = cast(CE->getCallee()); const CXXMethodDecl *MD = cast(ME->getMemberDecl()); - const FunctionProtoType *FPT = MD->getType()->getAsFunctionProtoType(); - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Constant *Callee = CGM.GetAddrOfFunction(GlobalDecl(MD), Ty); + if (MD->isStatic()) { + // The method is static, emit it as we would a regular call. + llvm::Value *Callee = CGM.GetAddrOfFunction(MD); + return EmitCall(Callee, getContext().getPointerType(MD->getType()), + CE->arg_begin(), CE->arg_end(), 0); + + } + const FunctionProtoType *FPT = MD->getType()->getAs(); + + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); llvm::Value *This; - + if (ME->isArrow()) This = EmitScalarExpr(ME->getBase()); else { LValue BaseLV = EmitLValue(ME->getBase()); This = BaseLV.getAddress(); } - - return EmitCXXMemberCall(MD, Callee, This, + + // C++ [class.virtual]p12: + // Explicit qualification with the scope operator (5.1) suppresses the + // virtual call mechanism. + // + // We also don't emit a virtual call if the base expression has a record type + // because then we know what the type is. + llvm::Value *Callee; + if (MD->isVirtual() && !ME->hasQualifier() && + !canDevirtualizeMemberFunctionCalls(ME->getBase())) + Callee = BuildVirtualCall(MD, This, Ty); + else if (const CXXDestructorDecl *Destructor + = dyn_cast(MD)) + Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty); + else + Callee = CGM.GetAddrOfFunction(MD, Ty); + + return EmitCXXMemberCall(MD, Callee, This, CE->arg_begin(), CE->arg_end()); } -RValue -CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, - const CXXMethodDecl *MD) { - assert(MD->isInstance() && - "Trying to emit a member call expr on a static method!"); +RValue +CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E) { + const BinaryOperator *BO = cast(E->getCallee()); + const Expr *BaseExpr = BO->getLHS(); + const Expr *MemFnExpr = BO->getRHS(); + const MemberPointerType *MPT = + MemFnExpr->getType()->getAs(); + const FunctionProtoType *FPT = + MPT->getPointeeType()->getAs(); + const CXXRecordDecl *RD = + cast(cast(MPT->getClass())->getDecl()); + + const llvm::FunctionType *FTy = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT), + FPT->isVariadic()); + + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8Ty(VMContext)->getPointerTo(); + + // Get the member function pointer. + llvm::Value *MemFnPtr = + CreateTempAlloca(ConvertType(MemFnExpr->getType()), "mem.fn"); + EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false); + + // Emit the 'this' pointer. + llvm::Value *This; - const FunctionProtoType *FPT = MD->getType()->getAsFunctionProtoType(); - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Constant *Callee = CGM.GetAddrOfFunction(GlobalDecl(MD), Ty); + if (BO->getOpcode() == BinaryOperator::PtrMemI) + This = EmitScalarExpr(BaseExpr); + else + This = EmitLValue(BaseExpr).getAddress(); - llvm::Value *This = EmitLValue(E->getArg(0)).getAddress(); + // Adjust it. + llvm::Value *Adj = Builder.CreateStructGEP(MemFnPtr, 1); + Adj = Builder.CreateLoad(Adj, "mem.fn.adj"); + + llvm::Value *Ptr = Builder.CreateBitCast(This, Int8PtrTy, "ptr"); + Ptr = Builder.CreateGEP(Ptr, Adj, "adj"); + + This = Builder.CreateBitCast(Ptr, This->getType(), "this"); + + llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0, "mem.fn.ptr"); + const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); + + llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "fn"); + + // If the LSB in the function pointer is 1, the function pointer points to + // a virtual function. + llvm::Value *IsVirtual + = Builder.CreateAnd(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1), + "and"); + + IsVirtual = Builder.CreateTrunc(IsVirtual, + llvm::Type::getInt1Ty(VMContext)); + + llvm::BasicBlock *FnVirtual = createBasicBlock("fn.virtual"); + llvm::BasicBlock *FnNonVirtual = createBasicBlock("fn.nonvirtual"); + llvm::BasicBlock *FnEnd = createBasicBlock("fn.end"); + + Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual); + EmitBlock(FnVirtual); + + const llvm::Type *VTableTy = + FTy->getPointerTo()->getPointerTo()->getPointerTo(); + + llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy); + VTable = Builder.CreateLoad(VTable); + + VTable = Builder.CreateGEP(VTable, FnAsInt, "fn"); + + // 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); + + llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn"); + + EmitBranch(FnEnd); + EmitBlock(FnNonVirtual); + + // If the function is not virtual, just load the pointer. + llvm::Value *NonVirtualFn = Builder.CreateLoad(FnPtr, "fn"); + NonVirtualFn = Builder.CreateIntToPtr(NonVirtualFn, FTy->getPointerTo()); + + EmitBlock(FnEnd); + + llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo()); + Callee->reserveOperandSpace(2); + Callee->addIncoming(VirtualFn, FnVirtual); + Callee->addIncoming(NonVirtualFn, FnNonVirtual); + + CallArgList Args; + + QualType ThisType = + getContext().getPointerType(getContext().getTagDeclType(RD)); + + // Push the this ptr. + Args.push_back(std::make_pair(RValue::get(This), ThisType)); + + // And the rest of the call args + EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end()); + QualType ResultType = BO->getType()->getAs()->getResultType(); + return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), + Callee, Args, 0); +} + +RValue +CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, + const CXXMethodDecl *MD) { + assert(MD->isInstance() && + "Trying to emit a member call expr on a static method!"); + + if (MD->isCopyAssignment()) { + const CXXRecordDecl *ClassDecl = cast(MD->getDeclContext()); + if (ClassDecl->hasTrivialCopyAssignment()) { + assert(!ClassDecl->hasUserDeclaredCopyAssignment() && + "EmitCXXOperatorMemberCallExpr - user declared copy assignment"); + llvm::Value *This = EmitLValue(E->getArg(0)).getAddress(); + llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress(); + QualType Ty = E->getType(); + EmitAggregateCopy(This, Src, Ty); + return RValue::get(This); + } + } + + const FunctionProtoType *FPT = MD->getType()->getAs(); + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, Ty); + + llvm::Value *This = EmitLValue(E->getArg(0)).getAddress(); + return EmitCXXMemberCall(MD, Callee, This, E->arg_begin() + 1, E->arg_end()); } llvm::Value *CodeGenFunction::LoadCXXThis() { - assert(isa(CurFuncDecl) && + assert(isa(CurFuncDecl) && "Must be in a C++ member function decl to load 'this'"); assert(cast(CurFuncDecl)->isInstance() && "Must be in a C++ member function decl to load 'this'"); - + // FIXME: What if we're inside a block? // ans: See how CodeGenFunction::LoadObjCSelf() uses // CodeGenFunction::BlockForwardSelf() for how to do this. return Builder.CreateLoad(LocalDeclMap[CXXThisDecl], "this"); } +/// EmitCXXAggrConstructorCall - This routine essentially creates a (nested) +/// for-loop to call the default constructor on individual members of the +/// array. +/// 'D' is the default constructor for elements of the array, 'ArrayTy' is the +/// array type and 'ArrayPtr' points to the beginning fo the array. +/// It is assumed that all relevant checks have been made by the caller. +void +CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, + const ConstantArrayType *ArrayTy, + llvm::Value *ArrayPtr) { + const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); + llvm::Value * NumElements = + llvm::ConstantInt::get(SizeTy, + getContext().getConstantArrayElementCount(ArrayTy)); + + EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr); +} + +void +CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, + llvm::Value *NumElements, + llvm::Value *ArrayPtr) { + const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); + + // Create a temporary for the loop index and initialize it with 0. + llvm::Value *IndexPtr = CreateTempAlloca(SizeTy, "loop.index"); + llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy); + Builder.CreateStore(Zero, IndexPtr, false); + + // Start the loop with a block that tests the condition. + llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); + llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); + + EmitBlock(CondBlock); + + llvm::BasicBlock *ForBody = createBasicBlock("for.body"); + + // Generate: if (loop-index < number-of-elements fall to the loop body, + // otherwise, go to the block after the for-loop. + llvm::Value *Counter = Builder.CreateLoad(IndexPtr); + llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElements, "isless"); + // If the condition is true, execute the body. + Builder.CreateCondBr(IsLess, ForBody, AfterFor); + + EmitBlock(ForBody); + + llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); + // Inside the loop body, emit the constructor call on the array element. + Counter = Builder.CreateLoad(IndexPtr); + llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter, + "arrayidx"); + EmitCXXConstructorCall(D, Ctor_Complete, Address, 0, 0); + + EmitBlock(ContinueBlock); + + // Emit the increment of the loop counter. + llvm::Value *NextVal = llvm::ConstantInt::get(SizeTy, 1); + Counter = Builder.CreateLoad(IndexPtr); + NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); + Builder.CreateStore(NextVal, IndexPtr, false); + + // Finally, branch back up to the condition for the next iteration. + EmitBranch(CondBlock); + + // Emit the fall-through block. + EmitBlock(AfterFor, true); +} + +/// EmitCXXAggrDestructorCall - calls the default destructor on array +/// elements in reverse order of construction. +void +CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, + const ArrayType *Array, + llvm::Value *This) { + const ConstantArrayType *CA = dyn_cast(Array); + assert(CA && "Do we support VLA for destruction ?"); + llvm::Value *One = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), + 1); + uint64_t ElementCount = getContext().getConstantArrayElementCount(CA); + // Create a temporary for the loop index and initialize it with count of + // array elements. + llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), + "loop.index"); + // Index = ElementCount; + llvm::Value* UpperCount = + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), ElementCount); + Builder.CreateStore(UpperCount, IndexPtr, false); + + // Start the loop with a block that tests the condition. + llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); + llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); + + EmitBlock(CondBlock); + + llvm::BasicBlock *ForBody = createBasicBlock("for.body"); + + // Generate: if (loop-index != 0 fall to the loop body, + // otherwise, go to the block after the for-loop. + llvm::Value* zeroConstant = + llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); + llvm::Value *Counter = Builder.CreateLoad(IndexPtr); + llvm::Value *IsNE = Builder.CreateICmpNE(Counter, zeroConstant, + "isne"); + // If the condition is true, execute the body. + Builder.CreateCondBr(IsNE, ForBody, AfterFor); + + EmitBlock(ForBody); + + llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); + // Inside the loop body, emit the constructor call on the array element. + Counter = Builder.CreateLoad(IndexPtr); + Counter = Builder.CreateSub(Counter, One); + llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx"); + EmitCXXDestructorCall(D, Dtor_Complete, Address); + + EmitBlock(ContinueBlock); + + // Emit the decrement of the loop counter. + Counter = Builder.CreateLoad(IndexPtr); + Counter = Builder.CreateSub(Counter, One, "dec"); + Builder.CreateStore(Counter, IndexPtr, false); + + // Finally, branch back up to the condition for the next iteration. + EmitBranch(CondBlock); + + // Emit the fall-through block. + EmitBlock(AfterFor, true); +} + void -CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, - CXXCtorType Type, +CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, + CXXCtorType Type, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd) { + if (D->isCopyConstructor(getContext())) { + const CXXRecordDecl *ClassDecl = cast(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); + return; + } + } + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type); EmitCXXMemberCall(D, Callee, This, ArgBeg, ArgEnd); } -void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *D, +void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type, llvm::Value *This) { llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(D, Type); - + EmitCXXMemberCall(D, Callee, This, 0, 0); } -void -CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, +void +CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E) { assert(Dest && "Must have a destination!"); - - const CXXRecordDecl *RD = - cast(E->getType()->getAsRecordType()->getDecl()); + + const CXXRecordDecl *RD = + cast(E->getType()->getAs()->getDecl()); if (RD->hasTrivialConstructor()) return; - - // Call the constructor. - EmitCXXConstructorCall(E->getConstructor(), Ctor_Complete, Dest, - E->arg_begin(), E->arg_end()); -} - -llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { - if (E->isArray()) { - ErrorUnsupported(E, "new[] expression"); - return llvm::UndefValue::get(ConvertType(E->getType())); - } - - QualType AllocType = E->getAllocatedType(); - FunctionDecl *NewFD = E->getOperatorNew(); - const FunctionProtoType *NewFTy = NewFD->getType()->getAsFunctionProtoType(); - - CallArgList NewArgs; - - // The allocation size is the first argument. - QualType SizeTy = getContext().getSizeType(); - llvm::Value *AllocSize = - llvm::ConstantInt::get(ConvertType(SizeTy), - getContext().getTypeSize(AllocType) / 8); - - NewArgs.push_back(std::make_pair(RValue::get(AllocSize), SizeTy)); - - // Emit the rest of the arguments. - // FIXME: Ideally, this should just use EmitCallArgs. - CXXNewExpr::const_arg_iterator NewArg = E->placement_arg_begin(); - - // First, use the types from the function type. - // We start at 1 here because the first argument (the allocation size) - // has already been emitted. - for (unsigned i = 1, e = NewFTy->getNumArgs(); i != e; ++i, ++NewArg) { - QualType ArgType = NewFTy->getArgType(i); - - assert(getContext().getCanonicalType(ArgType.getNonReferenceType()). - getTypePtr() == - getContext().getCanonicalType(NewArg->getType()).getTypePtr() && - "type mismatch in call argument!"); - - NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType), - ArgType)); - - } - - // Either we've emitted all the call args, or we have a call to a - // variadic function. - assert((NewArg == E->placement_arg_end() || NewFTy->isVariadic()) && - "Extra arguments in non-variadic function!"); - - // If we still have any arguments, emit them using the type of the argument. - for (CXXNewExpr::const_arg_iterator NewArgEnd = E->placement_arg_end(); - NewArg != NewArgEnd; ++NewArg) { - QualType ArgType = NewArg->getType(); - NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType), - ArgType)); - } - - // Emit the call to new. - RValue RV = - EmitCall(CGM.getTypes().getFunctionInfo(NewFTy->getResultType(), NewArgs), - CGM.GetAddrOfFunction(GlobalDecl(NewFD)), - NewArgs, NewFD); - - // If an allocation function is declared with an empty exception specification - // it returns null to indicate failure to allocate storage. [expr.new]p13. - // (We don't need to check for null when there's no new initializer and - // we're allocating a POD type). - bool NullCheckResult = NewFTy->hasEmptyExceptionSpec() && - !(AllocType->isPODType() && !E->hasInitializer()); - - llvm::BasicBlock *NewNull = 0; - llvm::BasicBlock *NewNotNull = 0; - llvm::BasicBlock *NewEnd = 0; - - llvm::Value *NewPtr = RV.getScalarVal(); - - if (NullCheckResult) { - NewNull = createBasicBlock("new.null"); - NewNotNull = createBasicBlock("new.notnull"); - NewEnd = createBasicBlock("new.end"); - - llvm::Value *IsNull = - Builder.CreateICmpEQ(NewPtr, - llvm::Constant::getNullValue(NewPtr->getType()), - "isnull"); - - Builder.CreateCondBr(IsNull, NewNull, NewNotNull); - EmitBlock(NewNotNull); - } - - NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType())); - - if (AllocType->isPODType()) { - if (E->getNumConstructorArgs() > 0) { - assert(E->getNumConstructorArgs() == 1 && - "Can only have one argument to initializer of POD type."); - - const Expr *Init = E->getConstructorArg(0); - - if (!hasAggregateLLVMType(AllocType)) - Builder.CreateStore(EmitScalarExpr(Init), NewPtr); - else if (AllocType->isAnyComplexType()) - EmitComplexExprIntoAddr(Init, NewPtr, AllocType.isVolatileQualified()); - else - EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified()); - } - } else { - // Call the constructor. - CXXConstructorDecl *Ctor = E->getConstructor(); - - EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr, - E->constructor_arg_begin(), - E->constructor_arg_end()); - } - - if (NullCheckResult) { - Builder.CreateBr(NewEnd); - EmitBlock(NewNull); - Builder.CreateBr(NewEnd); - EmitBlock(NewEnd); - - llvm::PHINode *PHI = Builder.CreatePHI(NewPtr->getType()); - PHI->reserveOperandSpace(2); - PHI->addIncoming(NewPtr, NewNotNull); - PHI->addIncoming(llvm::Constant::getNullValue(NewPtr->getType()), NewNull); - - NewPtr = PHI; - } - - return NewPtr; -} -static bool canGenerateCXXstructor(const CXXRecordDecl *RD, - ASTContext &Context) { - // The class has base classes - we don't support that right now. - if (RD->getNumBases() > 0) - return false; - - for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); - I != E; ++I) { - // We don't support ctors for fields that aren't POD. - if (!I->getType()->isPODType()) - return false; + // Code gen optimization to eliminate copy constructor and return + // its first argument instead. + if (getContext().getLangOptions().ElideConstructors && E->isElidable()) { + CXXConstructExpr::const_arg_iterator i = E->arg_begin(); + EmitAggExpr((*i), Dest, false); + return; } - - return true; + // Call the constructor. + EmitCXXConstructorCall(E->getConstructor(), Ctor_Complete, Dest, + E->arg_begin(), E->arg_end()); } void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) { - if (!canGenerateCXXstructor(D->getParent(), getContext())) { - ErrorUnsupported(D, "C++ constructor", true); - return; - } - EmitGlobal(GlobalDecl(D, Ctor_Complete)); EmitGlobal(GlobalDecl(D, Ctor_Base)); } -void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D, +void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D, CXXCtorType Type) { - + llvm::Function *Fn = GetAddrOfCXXConstructor(D, Type); - - CodeGenFunction(*this).GenerateCode(D, Fn); - + + CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn); + SetFunctionDefinitionAttributes(D, Fn); SetLLVMFunctionAttributesForDefinition(D, Fn); } llvm::Function * -CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D, +CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D, CXXCtorType Type) { const llvm::FunctionType *FTy = getTypes().GetFunctionType(getTypes().getFunctionInfo(D), false); - + const char *Name = getMangledCXXCtorName(D, Type); return cast( GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type))); } -const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D, +const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D, CXXCtorType Type) { llvm::SmallString<256> Name; llvm::raw_svector_ostream Out(Name); - mangleCXXCtor(D, Type, Context, Out); - + mangleCXXCtor(getMangleContext(), D, Type, Out); + Name += '\0'; return UniqueMangledName(Name.begin(), Name.end()); } void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) { - if (!canGenerateCXXstructor(D->getParent(), getContext())) { - ErrorUnsupported(D, "C++ destructor", true); - return; - } - EmitCXXDestructor(D, Dtor_Complete); EmitCXXDestructor(D, Dtor_Base); } -void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D, +void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type) { llvm::Function *Fn = GetAddrOfCXXDestructor(D, Type); - - CodeGenFunction(*this).GenerateCode(D, Fn); - + + CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn); + SetFunctionDefinitionAttributes(D, Fn); SetLLVMFunctionAttributesForDefinition(D, Fn); } llvm::Function * -CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D, +CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type) { const llvm::FunctionType *FTy = getTypes().GetFunctionType(getTypes().getFunctionInfo(D), false); - + const char *Name = getMangledCXXDtorName(D, Type); return cast( GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type))); } -const char *CodeGenModule::getMangledCXXDtorName(const CXXDestructorDecl *D, +const char *CodeGenModule::getMangledCXXDtorName(const CXXDestructorDecl *D, CXXDtorType Type) { llvm::SmallString<256> Name; llvm::raw_svector_ostream Out(Name); - mangleCXXDtor(D, Type, Context, Out); - + mangleCXXDtor(getMangleContext(), D, Type, Out); + Name += '\0'; return UniqueMangledName(Name.begin(), Name.end()); } + +llvm::Constant *CodeGenFunction::GenerateThunk(llvm::Function *Fn, + const CXXMethodDecl *MD, + bool Extern, int64_t nv, + int64_t v) { + QualType R = MD->getType()->getAs()->getResultType(); + + FunctionArgList Args; + ImplicitParamDecl *ThisDecl = + ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, + MD->getThisType(getContext())); + Args.push_back(std::make_pair(ThisDecl, ThisDecl->getType())); + for (FunctionDecl::param_const_iterator i = MD->param_begin(), + e = MD->param_end(); + i != e; ++i) { + ParmVarDecl *D = *i; + Args.push_back(std::make_pair(D, D->getType())); + } + IdentifierInfo *II + = &CGM.getContext().Idents.get("__thunk_named_foo_"); + FunctionDecl *FD = FunctionDecl::Create(getContext(), + getContext().getTranslationUnitDecl(), + SourceLocation(), II, R, 0, + Extern + ? FunctionDecl::Extern + : FunctionDecl::Static, + false, true); + StartFunction(FD, R, Fn, Args, SourceLocation()); + // FIXME: generate body + FinishFunction(); + return Fn; +} + +llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, + const CXXMethodDecl *MD, + bool Extern, + int64_t nv_t, + int64_t v_t, + int64_t nv_r, + int64_t v_r) { + QualType R = MD->getType()->getAs()->getResultType(); + + FunctionArgList Args; + ImplicitParamDecl *ThisDecl = + ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, + MD->getThisType(getContext())); + Args.push_back(std::make_pair(ThisDecl, ThisDecl->getType())); + for (FunctionDecl::param_const_iterator i = MD->param_begin(), + e = MD->param_end(); + i != e; ++i) { + ParmVarDecl *D = *i; + Args.push_back(std::make_pair(D, D->getType())); + } + IdentifierInfo *II + = &CGM.getContext().Idents.get("__thunk_named_foo_"); + FunctionDecl *FD = FunctionDecl::Create(getContext(), + getContext().getTranslationUnitDecl(), + SourceLocation(), II, R, 0, + Extern + ? FunctionDecl::Extern + : FunctionDecl::Static, + false, true); + StartFunction(FD, R, Fn, Args, SourceLocation()); + // FIXME: generate body + FinishFunction(); + return Fn; +} + +llvm::Constant *CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern, + int64_t nv, int64_t v) { + llvm::SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + mangleThunk(getMangleContext(), MD, nv, v, Out); + llvm::GlobalVariable::LinkageTypes linktype; + linktype = llvm::GlobalValue::WeakAnyLinkage; + if (!Extern) + linktype = llvm::GlobalValue::InternalLinkage; + llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); + const FunctionProtoType *FPT = MD->getType()->getAs(); + const llvm::FunctionType *FTy = + getTypes().GetFunctionType(getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + + llvm::Function *Fn = llvm::Function::Create(FTy, linktype, Out.str(), + &getModule()); + CodeGenFunction(*this).GenerateThunk(Fn, MD, Extern, nv, v); + // Fn = Builder.CreateBitCast(Fn, Ptr8Ty); + llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); + return m; +} + +llvm::Constant *CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD, + bool Extern, int64_t nv_t, + int64_t v_t, int64_t nv_r, + int64_t v_r) { + llvm::SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + mangleCovariantThunk(getMangleContext(), MD, nv_t, v_t, nv_r, v_r, Out); + llvm::GlobalVariable::LinkageTypes linktype; + linktype = llvm::GlobalValue::WeakAnyLinkage; + if (!Extern) + linktype = llvm::GlobalValue::InternalLinkage; + llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); + const FunctionProtoType *FPT = MD->getType()->getAs(); + const llvm::FunctionType *FTy = + getTypes().GetFunctionType(getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + + llvm::Function *Fn = llvm::Function::Create(FTy, linktype, Out.str(), + &getModule()); + CodeGenFunction(*this).GenerateCovariantThunk(Fn, MD, Extern, nv_t, v_t, nv_r, + v_r); + // Fn = Builder.CreateBitCast(Fn, Ptr8Ty); + llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); + return m; +} + +llvm::Value * +CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl) { + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8Ty(VMContext)->getPointerTo(); + + llvm::Value *VTablePtr = Builder.CreateBitCast(This, + Int8PtrTy->getPointerTo()); + VTablePtr = Builder.CreateLoad(VTablePtr, "vtable"); + + int64_t VBaseOffsetIndex = + CGM.getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl); + + llvm::Value *VBaseOffsetPtr = + Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetIndex, "vbase.offset.ptr"); + const llvm::Type *PtrDiffTy = + ConvertType(getContext().getPointerDiffType()); + + VBaseOffsetPtr = Builder.CreateBitCast(VBaseOffsetPtr, + PtrDiffTy->getPointerTo()); + + llvm::Value *VBaseOffset = Builder.CreateLoad(VBaseOffsetPtr, "vbase.offset"); + + return VBaseOffset; +} + +llvm::Value * +CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *&This, + const llvm::Type *Ty) { + int64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD); + + Ty = llvm::PointerType::get(Ty, 0); + Ty = llvm::PointerType::get(Ty, 0); + Ty = llvm::PointerType::get(Ty, 0); + llvm::Value *vtbl = Builder.CreateBitCast(This, Ty); + vtbl = Builder.CreateLoad(vtbl); + llvm::Value *vfn = Builder.CreateConstInBoundsGEP1_64(vtbl, + Index, "vfn"); + vfn = Builder.CreateLoad(vfn); + return vfn; +} + +/// EmitClassAggrMemberwiseCopy - This routine generates code to copy a class +/// array of objects from SrcValue to DestValue. Copying can be either a bitwise +/// copy or via a copy constructor call. +// FIXME. Consolidate this with EmitCXXAggrConstructorCall. +void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, + llvm::Value *Src, + const ArrayType *Array, + const CXXRecordDecl *BaseClassDecl, + QualType Ty) { + const ConstantArrayType *CA = dyn_cast(Array); + assert(CA && "VLA cannot be copied over"); + bool BitwiseCopy = BaseClassDecl->hasTrivialCopyConstructor(); + + // Create a temporary for the loop index and initialize it with 0. + llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), + "loop.index"); + llvm::Value* zeroConstant = + llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); + Builder.CreateStore(zeroConstant, IndexPtr, false); + // Start the loop with a block that tests the condition. + llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); + llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); + + EmitBlock(CondBlock); + + llvm::BasicBlock *ForBody = createBasicBlock("for.body"); + // Generate: if (loop-index < number-of-elements fall to the loop body, + // otherwise, go to the block after the for-loop. + uint64_t NumElements = getContext().getConstantArrayElementCount(CA); + llvm::Value * NumElementsPtr = + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements); + llvm::Value *Counter = Builder.CreateLoad(IndexPtr); + llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr, + "isless"); + // If the condition is true, execute the body. + Builder.CreateCondBr(IsLess, ForBody, AfterFor); + + EmitBlock(ForBody); + llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); + // Inside the loop body, emit the constructor call on the array element. + Counter = Builder.CreateLoad(IndexPtr); + Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress"); + Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress"); + if (BitwiseCopy) + EmitAggregateCopy(Dest, Src, Ty); + else if (CXXConstructorDecl *BaseCopyCtor = + BaseClassDecl->getCopyConstructor(getContext(), 0)) { + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, + Ctor_Complete); + CallArgList CallArgs; + // Push the this (Dest) ptr. + CallArgs.push_back(std::make_pair(RValue::get(Dest), + BaseCopyCtor->getThisType(getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + BaseCopyCtor->getParamDecl(0)->getType())); + QualType ResultType = + BaseCopyCtor->getType()->getAs()->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, BaseCopyCtor); + } + EmitBlock(ContinueBlock); + + // Emit the increment of the loop counter. + llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1); + Counter = Builder.CreateLoad(IndexPtr); + NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); + Builder.CreateStore(NextVal, IndexPtr, false); + + // Finally, branch back up to the condition for the next iteration. + EmitBranch(CondBlock); + + // Emit the fall-through block. + EmitBlock(AfterFor, true); +} + +/// EmitClassAggrCopyAssignment - This routine generates code to assign a class +/// array of objects from SrcValue to DestValue. Assignment can be either a +/// bitwise assignment or via a copy assignment operator function call. +/// FIXME. This can be consolidated with EmitClassAggrMemberwiseCopy +void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, + llvm::Value *Src, + const ArrayType *Array, + const CXXRecordDecl *BaseClassDecl, + QualType Ty) { + const ConstantArrayType *CA = dyn_cast(Array); + assert(CA && "VLA cannot be asssigned"); + bool BitwiseAssign = BaseClassDecl->hasTrivialCopyAssignment(); + + // Create a temporary for the loop index and initialize it with 0. + llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), + "loop.index"); + llvm::Value* zeroConstant = + llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); + Builder.CreateStore(zeroConstant, IndexPtr, false); + // Start the loop with a block that tests the condition. + llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); + llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); + + EmitBlock(CondBlock); + + llvm::BasicBlock *ForBody = createBasicBlock("for.body"); + // Generate: if (loop-index < number-of-elements fall to the loop body, + // otherwise, go to the block after the for-loop. + uint64_t NumElements = getContext().getConstantArrayElementCount(CA); + llvm::Value * NumElementsPtr = + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements); + llvm::Value *Counter = Builder.CreateLoad(IndexPtr); + llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr, + "isless"); + // If the condition is true, execute the body. + Builder.CreateCondBr(IsLess, ForBody, AfterFor); + + EmitBlock(ForBody); + llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); + // Inside the loop body, emit the assignment operator call on array element. + Counter = Builder.CreateLoad(IndexPtr); + Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress"); + Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress"); + const CXXMethodDecl *MD = 0; + if (BitwiseAssign) + EmitAggregateCopy(Dest, Src, Ty); + else { + bool hasCopyAssign = BaseClassDecl->hasConstCopyAssignment(getContext(), + MD); + assert(hasCopyAssign && "EmitClassAggrCopyAssignment - No user assign"); + (void)hasCopyAssign; + const FunctionProtoType *FPT = MD->getType()->getAs(); + const llvm::Type *LTy = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy); + + CallArgList CallArgs; + // Push the this (Dest) ptr. + CallArgs.push_back(std::make_pair(RValue::get(Dest), + MD->getThisType(getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + MD->getParamDecl(0)->getType())); + QualType ResultType = MD->getType()->getAs()->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, MD); + } + EmitBlock(ContinueBlock); + + // Emit the increment of the loop counter. + llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1); + Counter = Builder.CreateLoad(IndexPtr); + NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); + Builder.CreateStore(NextVal, IndexPtr, false); + + // Finally, branch back up to the condition for the next iteration. + EmitBranch(CondBlock); + + // Emit the fall-through block. + EmitBlock(AfterFor, true); +} + +/// EmitClassMemberwiseCopy - This routine generates code to copy a class +/// object from SrcValue to DestValue. Copying can be either a bitwise copy +/// or via a copy constructor call. +void CodeGenFunction::EmitClassMemberwiseCopy( + llvm::Value *Dest, llvm::Value *Src, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl, QualType Ty) { + if (ClassDecl) { + Dest = GetAddressCXXOfBaseClass(Dest, ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + Src = GetAddressCXXOfBaseClass(Src, ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + } + if (BaseClassDecl->hasTrivialCopyConstructor()) { + EmitAggregateCopy(Dest, Src, Ty); + return; + } + + if (CXXConstructorDecl *BaseCopyCtor = + BaseClassDecl->getCopyConstructor(getContext(), 0)) { + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, + Ctor_Complete); + CallArgList CallArgs; + // Push the this (Dest) ptr. + CallArgs.push_back(std::make_pair(RValue::get(Dest), + BaseCopyCtor->getThisType(getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + BaseCopyCtor->getParamDecl(0)->getType())); + QualType ResultType = + BaseCopyCtor->getType()->getAs()->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, BaseCopyCtor); + } +} + +/// EmitClassCopyAssignment - This routine generates code to copy assign a class +/// object from SrcValue to DestValue. Assignment can be either a bitwise +/// assignment of via an assignment operator call. +// FIXME. Consolidate this with EmitClassMemberwiseCopy as they share a lot. +void CodeGenFunction::EmitClassCopyAssignment( + llvm::Value *Dest, llvm::Value *Src, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl, + QualType Ty) { + if (ClassDecl) { + Dest = GetAddressCXXOfBaseClass(Dest, ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + Src = GetAddressCXXOfBaseClass(Src, ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + } + if (BaseClassDecl->hasTrivialCopyAssignment()) { + EmitAggregateCopy(Dest, Src, Ty); + return; + } + + const CXXMethodDecl *MD = 0; + bool ConstCopyAssignOp = BaseClassDecl->hasConstCopyAssignment(getContext(), + MD); + assert(ConstCopyAssignOp && "EmitClassCopyAssignment - missing copy assign"); + (void)ConstCopyAssignOp; + + const FunctionProtoType *FPT = MD->getType()->getAs(); + const llvm::Type *LTy = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy); + + CallArgList CallArgs; + // Push the this (Dest) ptr. + CallArgs.push_back(std::make_pair(RValue::get(Dest), + MD->getThisType(getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + MD->getParamDecl(0)->getType())); + QualType ResultType = + MD->getType()->getAs()->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, MD); +} + +/// SynthesizeDefaultConstructor - synthesize a default constructor +void +CodeGenFunction::SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor, + CXXCtorType Type, + llvm::Function *Fn, + const FunctionArgList &Args) { + StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args, + SourceLocation()); + EmitCtorPrologue(Ctor, Type); + FinishFunction(); +} + +/// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a copy +/// constructor, in accordance with section 12.8 (p7 and p8) of C++03 +/// The implicitly-defined copy constructor for class X performs a memberwise +/// copy of its subobjects. The order of copying is the same as the order +/// of initialization of bases and members in a user-defined constructor +/// Each subobject is copied in the manner appropriate to its type: +/// if the subobject is of class type, the copy constructor for the class is +/// used; +/// if the subobject is an array, each element is copied, in the manner +/// appropriate to the element type; +/// if the subobject is of scalar type, the built-in assignment operator is +/// used. +/// Virtual base class subobjects shall be copied only once by the +/// implicitly-defined copy constructor + +void +CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, + CXXCtorType Type, + llvm::Function *Fn, + const FunctionArgList &Args) { + const CXXRecordDecl *ClassDecl = Ctor->getParent(); + assert(!ClassDecl->hasUserDeclaredCopyConstructor() && + "SynthesizeCXXCopyConstructor - copy constructor has definition already"); + StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args, + SourceLocation()); + + FunctionArgList::const_iterator i = Args.begin(); + const VarDecl *ThisArg = i->first; + llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg); + llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this"); + const VarDecl *SrcArg = (i+1)->first; + llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg); + llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj); + + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + // FIXME. copy constrution of virtual base NYI + if (Base->isVirtual()) + continue; + + CXXRecordDecl *BaseClassDecl + = cast(Base->getType()->getAs()->getDecl()); + EmitClassMemberwiseCopy(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl, + Base->getType()); + } + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + QualType FieldType = getContext().getCanonicalType((*Field)->getType()); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + + if (const RecordType *FieldClassType = FieldType->getAs()) { + CXXRecordDecl *FieldClassDecl + = cast(FieldClassType->getDecl()); + LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *DestBaseAddrPtr = + Builder.CreateBitCast(LHS.getAddress(), BasePtr); + llvm::Value *SrcBaseAddrPtr = + Builder.CreateBitCast(RHS.getAddress(), BasePtr); + EmitClassAggrMemberwiseCopy(DestBaseAddrPtr, SrcBaseAddrPtr, Array, + FieldClassDecl, FieldType); + } + else + EmitClassMemberwiseCopy(LHS.getAddress(), RHS.getAddress(), + 0 /*ClassDecl*/, FieldClassDecl, FieldType); + continue; + } + // Do a built-in assignment of scalar data members. + LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); + RValue RVRHS = EmitLoadOfLValue(RHS, FieldType); + EmitStoreThroughLValue(RVRHS, LHS, FieldType); + } + FinishFunction(); +} + +/// SynthesizeCXXCopyAssignment - Implicitly define copy assignment operator. +/// Before the implicitly-declared copy assignment operator for a class is +/// implicitly defined, all implicitly- declared copy assignment operators for +/// its direct base classes and its nonstatic data members shall have been +/// implicitly defined. [12.8-p12] +/// The implicitly-defined copy assignment operator for class X performs +/// memberwise assignment of its subob- jects. The direct base classes of X are +/// assigned first, in the order of their declaration in +/// the base-specifier-list, and then the immediate nonstatic data members of X +/// are assigned, in the order in which they were declared in the class +/// definition.Each subobject is assigned in the manner appropriate to its type: +/// if the subobject is of class type, the copy assignment operator for the +/// class is used (as if by explicit qualification; that is, ignoring any +/// possible virtual overriding functions in more derived classes); +/// +/// if the subobject is an array, each element is assigned, in the manner +/// appropriate to the element type; +/// +/// if the subobject is of scalar type, the built-in assignment operator is +/// used. +void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD, + llvm::Function *Fn, + const FunctionArgList &Args) { + + const CXXRecordDecl *ClassDecl = cast(CD->getDeclContext()); + assert(!ClassDecl->hasUserDeclaredCopyAssignment() && + "SynthesizeCXXCopyAssignment - copy assignment has user declaration"); + StartFunction(CD, CD->getResultType(), Fn, Args, SourceLocation()); + + FunctionArgList::const_iterator i = Args.begin(); + const VarDecl *ThisArg = i->first; + llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg); + llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this"); + const VarDecl *SrcArg = (i+1)->first; + llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg); + llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj); + + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + // FIXME. copy assignment of virtual base NYI + if (Base->isVirtual()) + continue; + + CXXRecordDecl *BaseClassDecl + = cast(Base->getType()->getAs()->getDecl()); + EmitClassCopyAssignment(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl, + Base->getType()); + } + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + QualType FieldType = getContext().getCanonicalType((*Field)->getType()); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + + if (const RecordType *FieldClassType = FieldType->getAs()) { + CXXRecordDecl *FieldClassDecl + = cast(FieldClassType->getDecl()); + LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *DestBaseAddrPtr = + Builder.CreateBitCast(LHS.getAddress(), BasePtr); + llvm::Value *SrcBaseAddrPtr = + Builder.CreateBitCast(RHS.getAddress(), BasePtr); + EmitClassAggrCopyAssignment(DestBaseAddrPtr, SrcBaseAddrPtr, Array, + FieldClassDecl, FieldType); + } + else + EmitClassCopyAssignment(LHS.getAddress(), RHS.getAddress(), + 0 /*ClassDecl*/, FieldClassDecl, FieldType); + continue; + } + // Do a built-in assignment of scalar data members. + LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); + RValue RVRHS = EmitLoadOfLValue(RHS, FieldType); + EmitStoreThroughLValue(RVRHS, LHS, FieldType); + } + + // return *this; + Builder.CreateStore(LoadOfThis, ReturnValue); + + FinishFunction(); +} + +/// EmitCtorPrologue - This routine generates necessary code to initialize +/// base classes and non-static data members belonging to this constructor. +/// FIXME: This needs to take a CXXCtorType. +void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, + CXXCtorType CtorType) { + const CXXRecordDecl *ClassDecl = cast(CD->getDeclContext()); + // FIXME: Add vbase initialization + llvm::Value *LoadOfThis = 0; + + for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(), + E = CD->init_end(); + B != E; ++B) { + CXXBaseOrMemberInitializer *Member = (*B); + if (Member->isBaseInitializer()) { + LoadOfThis = LoadCXXThis(); + Type *BaseType = Member->getBaseClass(); + CXXRecordDecl *BaseClassDecl = + cast(BaseType->getAs()->getDecl()); + llvm::Value *V = GetAddressCXXOfBaseClass(LoadOfThis, ClassDecl, + BaseClassDecl, + /*NullCheckValue=*/false); + EmitCXXConstructorCall(Member->getConstructor(), + CtorType, V, + Member->const_arg_begin(), + Member->const_arg_end()); + } else { + // non-static data member initilaizers. + FieldDecl *Field = Member->getMember(); + QualType FieldType = getContext().getCanonicalType((Field)->getType()); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + + LoadOfThis = LoadCXXThis(); + LValue LHS; + if (FieldType->isReferenceType()) { + // FIXME: This is really ugly; should be refactored somehow + unsigned idx = CGM.getTypes().getLLVMFieldNo(Field); + llvm::Value *V = Builder.CreateStructGEP(LoadOfThis, idx, "tmp"); + assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs"); + LHS = LValue::MakeAddr(V, MakeQualifiers(FieldType)); + } else { + LHS = EmitLValueForField(LoadOfThis, Field, false, 0); + } + if (FieldType->getAs()) { + if (!Field->isAnonymousStructOrUnion()) { + assert(Member->getConstructor() && + "EmitCtorPrologue - no constructor to initialize member"); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(LHS.getAddress(), BasePtr); + EmitCXXAggrConstructorCall(Member->getConstructor(), + Array, BaseAddrPtr); + } + else + EmitCXXConstructorCall(Member->getConstructor(), + Ctor_Complete, LHS.getAddress(), + Member->const_arg_begin(), + Member->const_arg_end()); + continue; + } + else { + // Initializing an anonymous union data member. + FieldDecl *anonMember = Member->getAnonUnionMember(); + LHS = EmitLValueForField(LHS.getAddress(), anonMember, + /*IsUnion=*/true, 0); + FieldType = anonMember->getType(); + } + } + + assert(Member->getNumArgs() == 1 && "Initializer count must be 1 only"); + Expr *RhsExpr = *Member->arg_begin(); + RValue RHS; + if (FieldType->isReferenceType()) + RHS = EmitReferenceBindingToExpr(RhsExpr, FieldType, + /*IsInitializer=*/true); + else + RHS = RValue::get(EmitScalarExpr(RhsExpr, true)); + EmitStoreThroughLValue(RHS, LHS, FieldType); + } + } + + if (!CD->getNumBaseOrMemberInitializers() && !CD->isTrivial()) { + // Nontrivial default constructor with no initializer list. It may still + // have bases classes and/or contain non-static data members which require + // construction. + for (CXXRecordDecl::base_class_const_iterator Base = + ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + // FIXME. copy assignment of virtual base NYI + if (Base->isVirtual()) + continue; + + CXXRecordDecl *BaseClassDecl + = cast(Base->getType()->getAs()->getDecl()); + if (BaseClassDecl->hasTrivialConstructor()) + continue; + if (CXXConstructorDecl *BaseCX = + BaseClassDecl->getDefaultConstructor(getContext())) { + LoadOfThis = LoadCXXThis(); + llvm::Value *V = GetAddressCXXOfBaseClass(LoadOfThis, ClassDecl, + BaseClassDecl, + /*NullCheckValue=*/false); + EmitCXXConstructorCall(BaseCX, Ctor_Complete, V, 0, 0); + } + } + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + QualType FieldType = getContext().getCanonicalType((*Field)->getType()); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + if (!FieldType->getAs() || Field->isAnonymousStructOrUnion()) + continue; + const RecordType *ClassRec = FieldType->getAs(); + CXXRecordDecl *MemberClassDecl = + dyn_cast(ClassRec->getDecl()); + if (!MemberClassDecl || MemberClassDecl->hasTrivialConstructor()) + continue; + if (CXXConstructorDecl *MamberCX = + MemberClassDecl->getDefaultConstructor(getContext())) { + LoadOfThis = LoadCXXThis(); + LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(LHS.getAddress(), BasePtr); + EmitCXXAggrConstructorCall(MamberCX, Array, BaseAddrPtr); + } + else + EmitCXXConstructorCall(MamberCX, Ctor_Complete, LHS.getAddress(), + 0, 0); + } + } + } + + // Initialize the vtable pointer + if (ClassDecl->isDynamicClass()) { + if (!LoadOfThis) + LoadOfThis = LoadCXXThis(); + llvm::Value *VtableField; + llvm::Type *Ptr8Ty, *PtrPtr8Ty; + Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); + PtrPtr8Ty = llvm::PointerType::get(Ptr8Ty, 0); + VtableField = Builder.CreateBitCast(LoadOfThis, PtrPtr8Ty); + llvm::Value *vtable = GenerateVtable(ClassDecl); + Builder.CreateStore(vtable, VtableField); + } +} + +/// EmitDtorEpilogue - Emit all code that comes at the end of class's +/// destructor. This is to call destructors on members and base classes +/// in reverse order of their construction. +/// FIXME: This needs to take a CXXDtorType. +void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, + CXXDtorType DtorType) { + const CXXRecordDecl *ClassDecl = cast(DD->getDeclContext()); + assert(!ClassDecl->getNumVBases() && + "FIXME: Destruction of virtual bases not supported"); + (void)ClassDecl; // prevent warning. + + for (CXXDestructorDecl::destr_const_iterator *B = DD->destr_begin(), + *E = DD->destr_end(); B != E; ++B) { + uintptr_t BaseOrMember = (*B); + if (DD->isMemberToDestroy(BaseOrMember)) { + FieldDecl *FD = DD->getMemberToDestroy(BaseOrMember); + QualType FieldType = getContext().getCanonicalType((FD)->getType()); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + const RecordType *RT = FieldType->getAs(); + CXXRecordDecl *FieldClassDecl = cast(RT->getDecl()); + if (FieldClassDecl->hasTrivialDestructor()) + continue; + llvm::Value *LoadOfThis = LoadCXXThis(); + LValue LHS = EmitLValueForField(LoadOfThis, FD, false, 0); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(LHS.getAddress(), BasePtr); + EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()), + Array, BaseAddrPtr); + } + else + EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()), + Dtor_Complete, LHS.getAddress()); + } else { + const RecordType *RT = + DD->getAnyBaseClassToDestroy(BaseOrMember)->getAs(); + CXXRecordDecl *BaseClassDecl = cast(RT->getDecl()); + if (BaseClassDecl->hasTrivialDestructor()) + continue; + llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(), + ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()), + DtorType, V); + } + } + if (DD->getNumBaseOrMemberDestructions() || DD->isTrivial()) + return; + // Case of destructor synthesis with fields and base classes + // which have non-trivial destructors. They must be destructed in + // reverse order of their construction. + llvm::SmallVector DestructedFields; + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + QualType FieldType = getContext().getCanonicalType((*Field)->getType()); + if (getContext().getAsConstantArrayType(FieldType)) + FieldType = getContext().getBaseElementType(FieldType); + if (const RecordType *RT = FieldType->getAs()) { + CXXRecordDecl *FieldClassDecl = cast(RT->getDecl()); + if (FieldClassDecl->hasTrivialDestructor()) + continue; + DestructedFields.push_back(*Field); + } + } + if (!DestructedFields.empty()) + for (int i = DestructedFields.size() -1; i >= 0; --i) { + FieldDecl *Field = DestructedFields[i]; + QualType FieldType = Field->getType(); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + const RecordType *RT = FieldType->getAs(); + CXXRecordDecl *FieldClassDecl = cast(RT->getDecl()); + llvm::Value *LoadOfThis = LoadCXXThis(); + LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(LHS.getAddress(), BasePtr); + EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()), + Array, BaseAddrPtr); + } + else + EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()), + Dtor_Complete, LHS.getAddress()); + } + + llvm::SmallVector DestructedBases; + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + // FIXME. copy assignment of virtual base NYI + if (Base->isVirtual()) + continue; + + CXXRecordDecl *BaseClassDecl + = cast(Base->getType()->getAs()->getDecl()); + if (BaseClassDecl->hasTrivialDestructor()) + continue; + DestructedBases.push_back(BaseClassDecl); + } + if (DestructedBases.empty()) + return; + for (int i = DestructedBases.size() -1; i >= 0; --i) { + CXXRecordDecl *BaseClassDecl = DestructedBases[i]; + llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(), + ClassDecl,BaseClassDecl, + /*NullCheckValue=*/false); + EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()), + Dtor_Complete, V); + } +} + +void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor, + CXXDtorType DtorType, + llvm::Function *Fn, + const FunctionArgList &Args) { + + const CXXRecordDecl *ClassDecl = Dtor->getParent(); + assert(!ClassDecl->hasUserDeclaredDestructor() && + "SynthesizeDefaultDestructor - destructor has user declaration"); + (void) ClassDecl; + + StartFunction(GlobalDecl(Dtor, DtorType), Dtor->getResultType(), Fn, Args, + SourceLocation()); + EmitDtorEpilogue(Dtor, DtorType); + FinishFunction(); +} + +// FIXME: Move this to CGCXXStmt.cpp +void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { + // FIXME: We need to do more here. + EmitStmt(S.getTryBlock()); +} diff --git a/lib/CodeGen/CGCXX.h b/lib/CodeGen/CGCXX.h index 6051d9133c02..1e6adb05a0d9 100644 --- a/lib/CodeGen/CGCXX.h +++ b/lib/CodeGen/CGCXX.h @@ -30,7 +30,7 @@ enum CXXDtorType { Dtor_Complete, // Complete object dtor Dtor_Base // Base object dtor }; - + } // end namespace clang #endif // CLANG_CODEGEN_CGCXX_H diff --git a/lib/CodeGen/CGCXXClass.cpp b/lib/CodeGen/CGCXXClass.cpp new file mode 100644 index 000000000000..56a28fc9a007 --- /dev/null +++ b/lib/CodeGen/CGCXXClass.cpp @@ -0,0 +1,176 @@ +//===--- CGCXXClass.cpp - Emit LLVM Code for C++ classes ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with C++ code generation of classes +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/RecordLayout.h" + +using namespace clang; +using namespace CodeGen; + +static uint64_t +ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths, + 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]; + + // Get the layout. + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); + + const CXXBaseSpecifier *BS = Element.Base; + assert(!BS->isVirtual() && "Should not see virtual bases here!"); + + const CXXRecordDecl *Base = + cast(BS->getType()->getAs()->getDecl()); + + // Add the offset. + Offset += Layout.getBaseClassOffset(Base) / 8; + } + + return Offset; +} + +llvm::Constant * +CodeGenModule::GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl) { + if (ClassDecl == BaseClassDecl) + return 0; + + CXXBasePaths Paths(/*FindAmbiguities=*/false, + /*RecordPaths=*/true, /*DetectVirtual=*/false); + if (!const_cast(ClassDecl)-> + isDerivedFrom(const_cast(BaseClassDecl), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return 0; + } + + uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(), Paths, 0); + if (!Offset) + return 0; + + const llvm::Type *PtrDiffTy = + Types.ConvertType(getContext().getPointerDiffType()); + + 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=*/true); + if (!const_cast(ClassDecl)-> + isDerivedFrom(const_cast(BaseClassDecl), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return 0; + } + + unsigned Start = 0; + llvm::Value *VirtualOffset = 0; + if (const RecordType *RT = Paths.getDetectedVirtual()) { + const CXXRecordDecl *VBase = cast(RT->getDecl()); + + VirtualOffset = + CGF.GetVirtualCXXBaseClassOffset(BaseValue, ClassDecl, VBase); + + const CXXBasePath &Path = Paths.front(); + unsigned e = Path.size(); + for (Start = 0; Start != e; ++Start) { + const CXXBasePathElement& Element = Path[Start]; + + if (Element.Class == VBase) + break; + } + } + + 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; +} + +llvm::Value * +CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl, + bool NullCheckValue) { + QualType BTy = + getContext().getCanonicalType( + getContext().getTypeDeclType(const_cast(BaseClassDecl))); + const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy)); + + if (ClassDecl == BaseClassDecl) { + // Just cast back. + return Builder.CreateBitCast(BaseValue, BasePtrTy); + } + + llvm::BasicBlock *CastNull = 0; + llvm::BasicBlock *CastNotNull = 0; + llvm::BasicBlock *CastEnd = 0; + + if (NullCheckValue) { + CastNull = createBasicBlock("cast.null"); + CastNotNull = createBasicBlock("cast.notnull"); + CastEnd = createBasicBlock("cast.end"); + + llvm::Value *IsNull = + Builder.CreateICmpEQ(BaseValue, + llvm::Constant::getNullValue(BaseValue->getType())); + Builder.CreateCondBr(IsNull, CastNull, CastNotNull); + EmitBlock(CastNotNull); + } + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + + llvm::Value *Offset = + GetCXXBaseClassOffset(*this, BaseValue, ClassDecl, BaseClassDecl); + + if (Offset) { + // Apply the offset. + BaseValue = Builder.CreateBitCast(BaseValue, Int8PtrTy); + BaseValue = Builder.CreateGEP(BaseValue, Offset, "add.ptr"); + } + + // Cast back. + BaseValue = Builder.CreateBitCast(BaseValue, BasePtrTy); + + if (NullCheckValue) { + Builder.CreateBr(CastEnd); + EmitBlock(CastNull); + Builder.CreateBr(CastEnd); + EmitBlock(CastEnd); + + llvm::PHINode *PHI = Builder.CreatePHI(BaseValue->getType()); + PHI->reserveOperandSpace(2); + PHI->addIncoming(BaseValue, CastNotNull); + PHI->addIncoming(llvm::Constant::getNullValue(BaseValue->getType()), + CastNull); + BaseValue = PHI; + } + + return BaseValue; +} diff --git a/lib/CodeGen/CGCXXExpr.cpp b/lib/CodeGen/CGCXXExpr.cpp new file mode 100644 index 000000000000..2d62df6c58a4 --- /dev/null +++ b/lib/CodeGen/CGCXXExpr.cpp @@ -0,0 +1,304 @@ +//===--- CGCXXExpr.cpp - Emit LLVM Code for C++ expressions ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with code generation of C++ expressions +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +using namespace clang; +using namespace CodeGen; + +static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { + if (!E->isArray()) + return 0; + + QualType T = E->getAllocatedType(); + + const RecordType *RT = T->getAs(); + if (!RT) + return 0; + + const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); + if (!RD) + return 0; + + // Check if the class has a trivial destructor. + if (RD->hasTrivialDestructor()) { + // FIXME: Check for a two-argument delete. + return 0; + } + + // Padding is the maximum of sizeof(size_t) and alignof(T) + return std::max(Ctx.getTypeSize(Ctx.getSizeType()), + static_cast(Ctx.getTypeAlign(T))) / 8; +} + +static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, + const CXXNewExpr *E, + llvm::Value *& NumElements) { + QualType Type = E->getAllocatedType(); + uint64_t TypeSizeInBytes = CGF.getContext().getTypeSize(Type) / 8; + const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); + + if (!E->isArray()) + return llvm::ConstantInt::get(SizeTy, TypeSizeInBytes); + + uint64_t 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; + + NumElements = + llvm::ConstantInt::get(SizeTy, Result.Val.getInt().getZExtValue()); + + return llvm::ConstantInt::get(SizeTy, AllocSize); + } + + // Emit the array size expression. + NumElements = CGF.EmitScalarExpr(E->getArraySize()); + + // Multiply with the type size. + llvm::Value *V = + CGF.Builder.CreateMul(NumElements, + llvm::ConstantInt::get(SizeTy, TypeSizeInBytes)); + + // And add the cookie padding if necessary. + if (CookiePadding) + V = CGF.Builder.CreateAdd(V, llvm::ConstantInt::get(SizeTy, CookiePadding)); + + return V; +} + +static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, + llvm::Value *NewPtr, + llvm::Value *NumElements) { + QualType AllocType = E->getAllocatedType(); + + if (!E->isArray()) { + if (CXXConstructorDecl *Ctor = E->getConstructor()) { + CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr, + E->constructor_arg_begin(), + E->constructor_arg_end()); + + return; + } + + // We have a POD type. + if (E->getNumConstructorArgs() == 0) + return; + + assert(E->getNumConstructorArgs() == 1 && + "Can only have one argument to initializer of POD type."); + + const Expr *Init = E->getConstructorArg(0); + + if (!CGF.hasAggregateLLVMType(AllocType)) + CGF.Builder.CreateStore(CGF.EmitScalarExpr(Init), NewPtr); + else if (AllocType->isAnyComplexType()) + CGF.EmitComplexExprIntoAddr(Init, NewPtr, + AllocType.isVolatileQualified()); + else + CGF.EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified()); + return; + } + + if (CXXConstructorDecl *Ctor = E->getConstructor()) + CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr); +} + +llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { + QualType AllocType = E->getAllocatedType(); + FunctionDecl *NewFD = E->getOperatorNew(); + const FunctionProtoType *NewFTy = NewFD->getType()->getAs(); + + CallArgList NewArgs; + + // The allocation size is the first argument. + QualType SizeTy = getContext().getSizeType(); + + llvm::Value *NumElements = 0; + llvm::Value *AllocSize = EmitCXXNewAllocSize(*this, E, NumElements); + + NewArgs.push_back(std::make_pair(RValue::get(AllocSize), SizeTy)); + + // Emit the rest of the arguments. + // FIXME: Ideally, this should just use EmitCallArgs. + CXXNewExpr::const_arg_iterator NewArg = E->placement_arg_begin(); + + // First, use the types from the function type. + // We start at 1 here because the first argument (the allocation size) + // has already been emitted. + for (unsigned i = 1, e = NewFTy->getNumArgs(); i != e; ++i, ++NewArg) { + QualType ArgType = NewFTy->getArgType(i); + + assert(getContext().getCanonicalType(ArgType.getNonReferenceType()). + getTypePtr() == + getContext().getCanonicalType(NewArg->getType()).getTypePtr() && + "type mismatch in call argument!"); + + NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType), + ArgType)); + + } + + // Either we've emitted all the call args, or we have a call to a + // variadic function. + assert((NewArg == E->placement_arg_end() || NewFTy->isVariadic()) && + "Extra arguments in non-variadic function!"); + + // If we still have any arguments, emit them using the type of the argument. + for (CXXNewExpr::const_arg_iterator NewArgEnd = E->placement_arg_end(); + NewArg != NewArgEnd; ++NewArg) { + QualType ArgType = NewArg->getType(); + NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType), + ArgType)); + } + + // Emit the call to new. + RValue RV = + EmitCall(CGM.getTypes().getFunctionInfo(NewFTy->getResultType(), NewArgs), + CGM.GetAddrOfFunction(NewFD), NewArgs, NewFD); + + // If an allocation function is declared with an empty exception specification + // it returns null to indicate failure to allocate storage. [expr.new]p13. + // (We don't need to check for null when there's no new initializer and + // we're allocating a POD type). + bool NullCheckResult = NewFTy->hasEmptyExceptionSpec() && + !(AllocType->isPODType() && !E->hasInitializer()); + + llvm::BasicBlock *NewNull = 0; + llvm::BasicBlock *NewNotNull = 0; + llvm::BasicBlock *NewEnd = 0; + + llvm::Value *NewPtr = RV.getScalarVal(); + + if (NullCheckResult) { + NewNull = createBasicBlock("new.null"); + NewNotNull = createBasicBlock("new.notnull"); + NewEnd = createBasicBlock("new.end"); + + llvm::Value *IsNull = + Builder.CreateICmpEQ(NewPtr, + llvm::Constant::getNullValue(NewPtr->getType()), + "isnull"); + + Builder.CreateCondBr(IsNull, NewNull, NewNotNull); + EmitBlock(NewNotNull); + } + + if (uint64_t CookiePadding = CalculateCookiePadding(getContext(), E)) { + uint64_t CookieOffset = + CookiePadding - getContext().getTypeSize(SizeTy) / 8; + + llvm::Value *NumElementsPtr = + Builder.CreateConstInBoundsGEP1_64(NewPtr, CookieOffset); + + 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.CreateBitCast(NewPtr, ConvertType(E->getType())); + + EmitNewInitializer(*this, E, NewPtr, NumElements); + + if (NullCheckResult) { + Builder.CreateBr(NewEnd); + EmitBlock(NewNull); + Builder.CreateBr(NewEnd); + EmitBlock(NewEnd); + + llvm::PHINode *PHI = Builder.CreatePHI(NewPtr->getType()); + PHI->reserveOperandSpace(2); + PHI->addIncoming(NewPtr, NewNotNull); + PHI->addIncoming(llvm::Constant::getNullValue(NewPtr->getType()), NewNull); + + NewPtr = PHI; + } + + return NewPtr; +} + +void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { + if (E->isArrayForm()) { + ErrorUnsupported(E, "delete[] expression"); + return; + }; + + // Get at the argument before we performed the implicit conversion + // to void*. + const Expr *Arg = E->getArgument(); + while (const ImplicitCastExpr *ICE = dyn_cast(Arg)) { + if (ICE->getCastKind() != CastExpr::CK_UserDefinedConversion && + ICE->getType()->isVoidPointerType()) + Arg = ICE->getSubExpr(); + else + break; + } + + QualType DeleteTy = Arg->getType()->getAs()->getPointeeType(); + + llvm::Value *Ptr = EmitScalarExpr(Arg); + + // Null check the pointer. + llvm::BasicBlock *DeleteNotNull = createBasicBlock("delete.notnull"); + llvm::BasicBlock *DeleteEnd = createBasicBlock("delete.end"); + + llvm::Value *IsNull = + Builder.CreateICmpEQ(Ptr, llvm::Constant::getNullValue(Ptr->getType()), + "isnull"); + + Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull); + EmitBlock(DeleteNotNull); + + // Call the destructor if necessary. + if (const RecordType *RT = DeleteTy->getAs()) { + if (CXXRecordDecl *RD = dyn_cast(RT->getDecl())) { + if (!RD->hasTrivialDestructor()) { + const CXXDestructorDecl *Dtor = RD->getDestructor(getContext()); + if (Dtor->isVirtual()) { + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(Dtor), + /*isVariadic=*/false); + + llvm::Value *Callee = BuildVirtualCall(Dtor, Ptr, Ty); + EmitCXXMemberCall(Dtor, Callee, Ptr, 0, 0); + } else + EmitCXXDestructorCall(Dtor, Dtor_Complete, Ptr); + } + } + } + + // Call delete. + FunctionDecl *DeleteFD = E->getOperatorDelete(); + const FunctionProtoType *DeleteFTy = + DeleteFD->getType()->getAs(); + + CallArgList DeleteArgs; + + QualType ArgTy = DeleteFTy->getArgType(0); + llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy)); + DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy)); + + // Emit the call to delete. + EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(), + DeleteArgs), + CGM.GetAddrOfFunction(DeleteFD), + DeleteArgs, DeleteFD); + + EmitBlock(DeleteEnd); +} diff --git a/lib/CodeGen/CGCXXTemp.cpp b/lib/CodeGen/CGCXXTemp.cpp index a6e6d11505b6..4768556f6bca 100644 --- a/lib/CodeGen/CGCXXTemp.cpp +++ b/lib/CodeGen/CGCXXTemp.cpp @@ -15,29 +15,29 @@ using namespace clang; using namespace CodeGen; -void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, +void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, llvm::Value *Ptr) { llvm::BasicBlock *DtorBlock = createBasicBlock("temp.dtor"); - + llvm::Value *CondPtr = 0; - - // Check if temporaries need to be conditional. If so, we'll create a - // condition boolean, initialize it to 0 and + + // Check if temporaries need to be conditional. If so, we'll create a + // condition boolean, initialize it to 0 and if (!ConditionalTempDestructionStack.empty()) { - CondPtr = CreateTempAlloca(llvm::Type::Int1Ty, "cond"); - + CondPtr = CreateTempAlloca(llvm::Type::getInt1Ty(VMContext), "cond"); + // Initialize it to false. This initialization takes place right after // the alloca insert point. - llvm::StoreInst *SI = - new llvm::StoreInst(llvm::ConstantInt::getFalse(), CondPtr); + llvm::StoreInst *SI = + new llvm::StoreInst(llvm::ConstantInt::getFalse(VMContext), CondPtr); llvm::BasicBlock *Block = AllocaInsertPt->getParent(); Block->getInstList().insertAfter((llvm::Instruction *)AllocaInsertPt, SI); // Now set it to true. - Builder.CreateStore(llvm::ConstantInt::getTrue(), CondPtr); + Builder.CreateStore(llvm::ConstantInt::getTrue(VMContext), CondPtr); } - - LiveTemporaries.push_back(CXXLiveTemporaryInfo(Temporary, Ptr, DtorBlock, + + LiveTemporaries.push_back(CXXLiveTemporaryInfo(Temporary, Ptr, DtorBlock, CondPtr)); PushCleanupBlock(DtorBlock); @@ -45,16 +45,22 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, void CodeGenFunction::PopCXXTemporary() { const CXXLiveTemporaryInfo& Info = LiveTemporaries.back(); - + CleanupBlockInfo CleanupInfo = PopCleanupBlock(); - assert(CleanupInfo.CleanupBlock == Info.DtorBlock && + assert(CleanupInfo.CleanupBlock == Info.DtorBlock && "Cleanup block mismatch!"); - assert(!CleanupInfo.SwitchBlock && + assert(!CleanupInfo.SwitchBlock && "Should not have a switch block for temporary cleanup!"); - assert(!CleanupInfo.EndBlock && + assert(!CleanupInfo.EndBlock && "Should not have an end block for temporary cleanup!"); - - EmitBlock(Info.DtorBlock); + + llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); + if (CurBB && !CurBB->getTerminator() && + Info.DtorBlock->getNumUses() == 0) { + CurBB->getInstList().splice(CurBB->end(), Info.DtorBlock->getInstList()); + delete Info.DtorBlock; + } else + EmitBlock(Info.DtorBlock); llvm::BasicBlock *CondEnd = 0; @@ -63,52 +69,80 @@ void CodeGenFunction::PopCXXTemporary() { if (Info.CondPtr) { llvm::BasicBlock *CondBlock = createBasicBlock("cond.dtor.call"); CondEnd = createBasicBlock("cond.dtor.end"); - + llvm::Value *Cond = Builder.CreateLoad(Info.CondPtr); Builder.CreateCondBr(Cond, CondBlock, CondEnd); EmitBlock(CondBlock); } - + EmitCXXDestructorCall(Info.Temporary->getDestructor(), Dtor_Complete, Info.ThisPtr); if (CondEnd) { // Reset the condition. to false. - Builder.CreateStore(llvm::ConstantInt::getFalse(), Info.CondPtr); + Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext), Info.CondPtr); EmitBlock(CondEnd); } - + LiveTemporaries.pop_back(); } RValue CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E, llvm::Value *AggLoc, - bool isAggLocVolatile) { + bool IsAggLocVolatile, + bool IsInitializer) { // If we shouldn't destroy the temporaries, just emit the // child expression. if (!E->shouldDestroyTemporaries()) - return EmitAnyExpr(E->getSubExpr(), AggLoc, isAggLocVolatile); + return EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile, + /*IgnoreResult=*/false, IsInitializer); // Keep track of the current cleanup stack depth. size_t CleanupStackDepth = CleanupEntries.size(); (void) CleanupStackDepth; unsigned OldNumLiveTemporaries = LiveTemporaries.size(); - - RValue RV = EmitAnyExpr(E->getSubExpr(), AggLoc, isAggLocVolatile); - + + RValue RV = EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile, + /*IgnoreResult=*/false, IsInitializer); + // Pop temporaries. while (LiveTemporaries.size() > OldNumLiveTemporaries) PopCXXTemporary(); - + assert(CleanupEntries.size() == CleanupStackDepth && "Cleanup size mismatch!"); - + return RV; } -void +LValue CodeGenFunction::EmitCXXExprWithTemporariesLValue( + const CXXExprWithTemporaries *E) { + // If we shouldn't destroy the temporaries, just emit the + // child expression. + if (!E->shouldDestroyTemporaries()) + return EmitLValue(E->getSubExpr()); + + // Keep track of the current cleanup stack depth. + size_t CleanupStackDepth = CleanupEntries.size(); + (void) CleanupStackDepth; + + unsigned OldNumLiveTemporaries = LiveTemporaries.size(); + + LValue LV = EmitLValue(E->getSubExpr()); + + // Pop temporaries. + while (LiveTemporaries.size() > OldNumLiveTemporaries) + PopCXXTemporary(); + + assert(CleanupEntries.size() == CleanupStackDepth && + "Cleanup size mismatch!"); + + return LV; +} + +void CodeGenFunction::PushConditionalTempDestruction() { // Store the current number of live temporaries. ConditionalTempDestructionStack.push_back(LiveTemporaries.size()); @@ -117,13 +151,13 @@ CodeGenFunction::PushConditionalTempDestruction() { void CodeGenFunction::PopConditionalTempDestruction() { size_t NumLiveTemporaries = ConditionalTempDestructionStack.back(); ConditionalTempDestructionStack.pop_back(); - + // Pop temporaries. while (LiveTemporaries.size() > NumLiveTemporaries) { - assert(LiveTemporaries.back().CondPtr && + assert(LiveTemporaries.back().CondPtr && "Conditional temporary must have a cond ptr!"); PopCXXTemporary(); - } + } } - + diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 97391bc620be..bad166f01ef5 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -33,19 +33,49 @@ using namespace CodeGen; // FIXME: Use iterator and sidestep silly type array creation. -const +const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionNoProtoType *FTNP) { - return getFunctionInfo(FTNP->getResultType(), - llvm::SmallVector()); + // FIXME: Set calling convention correctly, it needs to be associated with the + // type somehow. + return getFunctionInfo(FTNP->getResultType(), + llvm::SmallVector(), 0); } -const +const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionProtoType *FTP) { llvm::SmallVector ArgTys; // FIXME: Kill copy. for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) ArgTys.push_back(FTP->getArgType(i)); - return getFunctionInfo(FTP->getResultType(), ArgTys); + // FIXME: Set calling convention correctly, it needs to be associated with the + // type somehow. + return getFunctionInfo(FTP->getResultType(), ArgTys, 0); +} + +static unsigned getCallingConventionForDecl(const Decl *D) { + // Set the appropriate calling convention for the Function. + if (D->hasAttr()) + return llvm::CallingConv::X86_StdCall; + + if (D->hasAttr()) + return llvm::CallingConv::X86_FastCall; + + return llvm::CallingConv::C; +} + +const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD, + const FunctionProtoType *FTP) { + llvm::SmallVector ArgTys; + + // Add the 'this' pointer. + ArgTys.push_back(Context.getPointerType(Context.getTagDeclType(RD))); + + 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); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) { @@ -53,22 +83,32 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) { // Add the 'this' pointer unless this is a static method. if (MD->isInstance()) ArgTys.push_back(MD->getThisType(Context)); - - const FunctionProtoType *FTP = MD->getType()->getAsFunctionProtoType(); + + const FunctionProtoType *FTP = MD->getType()->getAs(); for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) ArgTys.push_back(FTP->getArgType(i)); - return getFunctionInfo(FTP->getResultType(), ArgTys); + return getFunctionInfo(FTP->getResultType(), ArgTys, + getCallingConventionForDecl(MD)); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) { if (const CXXMethodDecl *MD = dyn_cast(FD)) if (MD->isInstance()) return getFunctionInfo(MD); + + unsigned CallingConvention = getCallingConventionForDecl(FD); + const FunctionType *FTy = FD->getType()->getAs(); + if (const FunctionNoProtoType *FNTP = dyn_cast(FTy)) + return getFunctionInfo(FNTP->getResultType(), + llvm::SmallVector(), + CallingConvention); - const FunctionType *FTy = FD->getType()->getAsFunctionType(); - if (const FunctionProtoType *FTP = dyn_cast(FTy)) - return getFunctionInfo(FTP); - return getFunctionInfo(cast(FTy)); + const FunctionProtoType *FPT = cast(FTy); + llvm::SmallVector 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); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) { @@ -79,34 +119,39 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) { for (ObjCMethodDecl::param_iterator i = MD->param_begin(), e = MD->param_end(); i != e; ++i) ArgTys.push_back((*i)->getType()); - return getFunctionInfo(MD->getResultType(), ArgTys); + return getFunctionInfo(MD->getResultType(), ArgTys, + getCallingConventionForDecl(MD)); } -const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, - const CallArgList &Args) { +const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, + const CallArgList &Args, + unsigned CallingConvention){ // FIXME: Kill copy. llvm::SmallVector ArgTys; - for (CallArgList::const_iterator i = Args.begin(), e = Args.end(); + for (CallArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i) ArgTys.push_back(i->second); - return getFunctionInfo(ResTy, ArgTys); + return getFunctionInfo(ResTy, ArgTys, CallingConvention); } -const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, - const FunctionArgList &Args) { +const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, + const FunctionArgList &Args, + unsigned CallingConvention){ // FIXME: Kill copy. llvm::SmallVector ArgTys; - for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); + for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i) ArgTys.push_back(i->second); - return getFunctionInfo(ResTy, ArgTys); + return getFunctionInfo(ResTy, ArgTys, CallingConvention); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, - const llvm::SmallVector &ArgTys) { + const llvm::SmallVector &ArgTys, + unsigned CallingConvention){ // Lookup or create unique function info. llvm::FoldingSetNodeID ID; - CGFunctionInfo::Profile(ID, ResTy, ArgTys.begin(), ArgTys.end()); + CGFunctionInfo::Profile(ID, CallingConvention, ResTy, + ArgTys.begin(), ArgTys.end()); void *InsertPos = 0; CGFunctionInfo *FI = FunctionInfos.FindNodeOrInsertPos(ID, InsertPos); @@ -114,17 +159,21 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, return *FI; // Construct the function info. - FI = new CGFunctionInfo(ResTy, ArgTys); + FI = new CGFunctionInfo(CallingConvention, ResTy, ArgTys); FunctionInfos.InsertNode(FI, InsertPos); // Compute ABI information. - getABIInfo().computeInfo(*FI, getContext()); + getABIInfo().computeInfo(*FI, getContext(), TheModule.getContext()); return *FI; } -CGFunctionInfo::CGFunctionInfo(QualType ResTy, - const llvm::SmallVector &ArgTys) { +CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention, + QualType ResTy, + const llvm::SmallVector &ArgTys) + : CallingConvention(_CallingConvention), + EffectiveCallingConvention(_CallingConvention) +{ NumArgs = ArgTys.size(); Args = new ArgInfo[1 + NumArgs]; Args[0].type = ResTy; @@ -134,20 +183,20 @@ CGFunctionInfo::CGFunctionInfo(QualType ResTy, /***/ -void CodeGenTypes::GetExpandedTypes(QualType Ty, +void CodeGenTypes::GetExpandedTypes(QualType Ty, std::vector &ArgTys) { const RecordType *RT = Ty->getAsStructureType(); assert(RT && "Can only expand structure types."); const RecordDecl *RD = RT->getDecl(); - assert(!RD->hasFlexibleArrayMember() && + assert(!RD->hasFlexibleArrayMember() && "Cannot expand structure with flexible array."); - + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i) { const FieldDecl *FD = *i; - assert(!FD->isBitField() && + assert(!FD->isBitField() && "Cannot expand structure with bit-field members."); - + QualType FT = FD->getType(); if (CodeGenFunction::hasAggregateLLVMType(FT)) { GetExpandedTypes(FT, ArgTys); @@ -157,19 +206,19 @@ void CodeGenTypes::GetExpandedTypes(QualType Ty, } } -llvm::Function::arg_iterator +llvm::Function::arg_iterator CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV, llvm::Function::arg_iterator AI) { const RecordType *RT = Ty->getAsStructureType(); assert(RT && "Can only expand structure types."); RecordDecl *RD = RT->getDecl(); - assert(LV.isSimple() && - "Unexpected non-simple lvalue during struct expansion."); + assert(LV.isSimple() && + "Unexpected non-simple lvalue during struct expansion."); llvm::Value *Addr = LV.getAddress(); for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i) { - FieldDecl *FD = *i; + FieldDecl *FD = *i; QualType FT = FD->getType(); // FIXME: What are the right qualifiers here? @@ -185,8 +234,8 @@ CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV, return AI; } -void -CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV, +void +CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV, llvm::SmallVector &Args) { const RecordType *RT = Ty->getAsStructureType(); assert(RT && "Can only expand structure types."); @@ -196,16 +245,16 @@ CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV, llvm::Value *Addr = RV.getAggregateAddr(); for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i) { - FieldDecl *FD = *i; + FieldDecl *FD = *i; QualType FT = FD->getType(); - + // FIXME: What are the right qualifiers here? LValue LV = EmitLValueForField(Addr, FD, false, 0); if (CodeGenFunction::hasAggregateLLVMType(FT)) { ExpandTypeToArgs(FT, RValue::getAggregate(LV.getAddress()), Args); } else { RValue RV = EmitLoadOfLValue(LV, FT); - assert(RV.isScalar() && + assert(RV.isScalar() && "Unexpected non-scalar rvalue during struct expansion."); Args.push_back(RV.getScalarVal()); } @@ -221,7 +270,7 @@ CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV, static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, const llvm::Type *Ty, CodeGenFunction &CGF) { - const llvm::Type *SrcTy = + const llvm::Type *SrcTy = cast(SrcPtr->getType())->getElementType(); uint64_t SrcSize = CGF.CGM.getTargetData().getTypeAllocSize(SrcTy); uint64_t DstSize = CGF.CGM.getTargetData().getTypeAllocSize(Ty); @@ -244,9 +293,9 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, // Otherwise do coercion through memory. This is stupid, but // simple. llvm::Value *Tmp = CGF.CreateTempAlloca(Ty); - llvm::Value *Casted = + llvm::Value *Casted = CGF.Builder.CreateBitCast(Tmp, llvm::PointerType::getUnqual(SrcTy)); - llvm::StoreInst *Store = + llvm::StoreInst *Store = CGF.Builder.CreateStore(CGF.Builder.CreateLoad(SrcPtr), Casted); // FIXME: Use better alignment / avoid requiring aligned store. Store->setAlignment(1); @@ -263,7 +312,7 @@ static void CreateCoercedStore(llvm::Value *Src, llvm::Value *DstPtr, CodeGenFunction &CGF) { const llvm::Type *SrcTy = Src->getType(); - const llvm::Type *DstTy = + const llvm::Type *DstTy = cast(DstPtr->getType())->getElementType(); uint64_t SrcSize = CGF.CGM.getTargetData().getTypeAllocSize(SrcTy); @@ -287,7 +336,7 @@ static void CreateCoercedStore(llvm::Value *Src, // to that information. llvm::Value *Tmp = CGF.CreateTempAlloca(SrcTy); CGF.Builder.CreateStore(Src, Tmp); - llvm::Value *Casted = + llvm::Value *Casted = CGF.Builder.CreateBitCast(Tmp, llvm::PointerType::getUnqual(DstTy)); llvm::LoadInst *Load = CGF.Builder.CreateLoad(Casted); // FIXME: Use better alignment / avoid requiring aligned load. @@ -321,25 +370,25 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic) { case ABIArgInfo::Indirect: { assert(!RetAI.getIndirectAlign() && "Align unused on indirect return."); - ResultType = llvm::Type::VoidTy; + ResultType = llvm::Type::getVoidTy(getLLVMContext()); const llvm::Type *STy = ConvertType(RetTy); ArgTys.push_back(llvm::PointerType::get(STy, RetTy.getAddressSpace())); break; } case ABIArgInfo::Ignore: - ResultType = llvm::Type::VoidTy; + ResultType = llvm::Type::getVoidTy(getLLVMContext()); break; case ABIArgInfo::Coerce: ResultType = RetAI.getCoerceToType(); break; } - - for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(), + + for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) { const ABIArgInfo &AI = it->info; - + switch (AI.getKind()) { case ABIArgInfo::Ignore: break; @@ -359,7 +408,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic) { case ABIArgInfo::Direct: ArgTys.push_back(ConvertType(it->type)); break; - + case ABIArgInfo::Expand: GetExpandedTypes(it->type, ArgTys); break; @@ -371,10 +420,13 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic) { void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, const Decl *TargetDecl, - AttributeListType &PAL) { + AttributeListType &PAL, + unsigned &CallingConv) { unsigned FuncAttrs = 0; unsigned RetAttrs = 0; + CallingConv = FI.getEffectiveCallingConvention(); + // FIXME: handle sseregparm someday... if (TargetDecl) { if (TargetDecl->hasAttr()) @@ -385,6 +437,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, FuncAttrs |= llvm::Attribute::ReadNone; else if (TargetDecl->hasAttr()) FuncAttrs |= llvm::Attribute::ReadOnly; + if (TargetDecl->hasAttr()) + RetAttrs |= llvm::Attribute::NoAlias; } if (CompileOpts.DisableRedZone) @@ -412,7 +466,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, break; case ABIArgInfo::Indirect: - PAL.push_back(llvm::AttributeWithIndex::get(Index, + PAL.push_back(llvm::AttributeWithIndex::get(Index, llvm::Attribute::StructRet | llvm::Attribute::NoAlias)); ++Index; @@ -426,7 +480,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, break; case ABIArgInfo::Expand: - assert(0 && "Invalid ABI kind for return argument"); + assert(0 && "Invalid ABI kind for return argument"); } if (RetAttrs) @@ -437,12 +491,12 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, // register variable. signed RegParm = 0; if (TargetDecl) - if (const RegparmAttr *RegParmAttr + if (const RegparmAttr *RegParmAttr = TargetDecl->getAttr()) RegParm = RegParmAttr->getNumParams(); unsigned PointerWidth = getContext().Target.getPointerWidth(0); - for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(), + for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) { QualType ParamType = it->type; const ABIArgInfo &AI = it->info; @@ -453,7 +507,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, break; case ABIArgInfo::Indirect: - Attributes |= llvm::Attribute::ByVal; + if (AI.getIndirectByVal()) + Attributes |= llvm::Attribute::ByVal; + Attributes |= llvm::Attribute::constructAlignmentFromInt(AI.getIndirectAlign()); // byval disables readnone and readonly. @@ -481,10 +537,10 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, case ABIArgInfo::Ignore: // Skip increment, no matching LLVM parameter. - continue; + continue; case ABIArgInfo::Expand: { - std::vector Tys; + std::vector Tys; // FIXME: This is rather inefficient. Do we ever actually need to do // anything here? The result should be just reconstructed on the other // side, so extension should be a non-issue. @@ -493,7 +549,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, continue; } } - + if (Attributes) PAL.push_back(llvm::AttributeWithIndex::get(Index, Attributes)); ++Index; @@ -505,18 +561,31 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, llvm::Function *Fn, const FunctionArgList &Args) { + // If this is an implicit-return-zero function, go ahead and + // initialize the return value. TODO: it might be nice to have + // a more general mechanism for this that didn't require synthesized + // return statements. + if (const FunctionDecl* FD = dyn_cast_or_null(CurFuncDecl)) { + if (FD->hasImplicitReturnZero()) { + QualType RetTy = FD->getResultType().getUnqualifiedType(); + const llvm::Type* LLVMTy = CGM.getTypes().ConvertType(RetTy); + llvm::Constant* Zero = llvm::Constant::getNullValue(LLVMTy); + Builder.CreateStore(Zero, ReturnValue); + } + } + // FIXME: We no longer need the types from FunctionArgList; lift up and // simplify. // Emit allocs for param decls. Give the LLVM Argument nodes names. llvm::Function::arg_iterator AI = Fn->arg_begin(); - + // Name the struct return argument. if (CGM.ReturnTypeUsesSret(FI)) { AI->setName("agg.result"); ++AI; } - + assert(FI.arg_size() == Args.size() && "Mismatch between function signature & arguments."); CGFunctionInfo::const_arg_iterator info_it = FI.arg_begin(); @@ -541,7 +610,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, V = EmitScalarConversion(V, Ty, Arg->getType()); } } - EmitParmDecl(*Arg, V); + EmitParmDecl(*Arg, V); break; } @@ -565,36 +634,36 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, EmitParmDecl(*Arg, V); break; } - + case ABIArgInfo::Expand: { // If this structure was expanded into multiple arguments then // we need to create a temporary and reconstruct it from the // arguments. std::string Name = Arg->getNameAsString(); - llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(Ty), + llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(Ty), (Name + ".addr").c_str()); // FIXME: What are the right qualifiers here? - llvm::Function::arg_iterator End = - ExpandTypeFromArgs(Ty, LValue::MakeAddr(Temp,0), AI); + llvm::Function::arg_iterator End = + ExpandTypeFromArgs(Ty, LValue::MakeAddr(Temp, Qualifiers()), AI); EmitParmDecl(*Arg, Temp); // Name the arguments used in expansion and increment AI. unsigned Index = 0; for (; AI != End; ++AI, ++Index) - AI->setName(Name + "." + llvm::utostr(Index)); + AI->setName(Name + "." + llvm::Twine(Index)); continue; } case ABIArgInfo::Ignore: // Initialize the local variable appropriately. - if (hasAggregateLLVMType(Ty)) { + if (hasAggregateLLVMType(Ty)) { EmitParmDecl(*Arg, CreateTempAlloca(ConvertTypeForMem(Ty))); } else { EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType()))); } - + // Skip increment, no matching LLVM parameter. - continue; + continue; case ABIArgInfo::Coerce: { assert(AI != Fn->arg_end() && "Argument mismatch!"); @@ -653,16 +722,16 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, case ABIArgInfo::Ignore: break; - + case ABIArgInfo::Coerce: RV = CreateCoercedLoad(ReturnValue, RetAI.getCoerceToType(), *this); break; case ABIArgInfo::Expand: - assert(0 && "Invalid ABI kind for return argument"); + assert(0 && "Invalid ABI kind for return argument"); } } - + if (RV) { Builder.CreateRet(RV); } else { @@ -673,12 +742,12 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, RValue CodeGenFunction::EmitCallArg(const Expr *E, QualType ArgType) { if (ArgType->isReferenceType()) return EmitReferenceBindingToExpr(E, ArgType); - + return EmitAnyExprToTemp(E); } RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, - llvm::Value *Callee, + llvm::Value *Callee, const CallArgList &CallArgs, const Decl *TargetDecl) { // FIXME: We no longer need the types from CallArgs; lift up and simplify. @@ -688,17 +757,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // location that we would like to return into. QualType RetTy = CallInfo.getReturnType(); const ABIArgInfo &RetAI = CallInfo.getReturnInfo(); - - + + // If the call returns a temporary with struct return, create a temporary // alloca to hold the result. if (CGM.ReturnTypeUsesSret(CallInfo)) Args.push_back(CreateTempAlloca(ConvertTypeForMem(RetTy))); - + assert(CallInfo.arg_size() == CallArgs.size() && "Mismatch between function signature & arguments."); CGFunctionInfo::const_arg_iterator info_it = CallInfo.arg_begin(); - for (CallArgList::const_iterator I = CallArgs.begin(), E = CallArgs.end(); + for (CallArgList::const_iterator I = CallArgs.begin(), E = CallArgs.end(); I != E; ++I, ++info_it) { const ABIArgInfo &ArgInfo = info_it->info; RValue RV = I->first; @@ -711,7 +780,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (RV.isScalar()) EmitStoreOfScalar(RV.getScalarVal(), Args.back(), false, I->second); else - StoreComplexToAddr(RV.getComplexVal(), Args.back(), false); + StoreComplexToAddr(RV.getComplexVal(), Args.back(), false); } else { Args.push_back(RV.getAggregateAddr()); } @@ -730,7 +799,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, Args.push_back(Builder.CreateLoad(RV.getAggregateAddr())); } break; - + case ABIArgInfo::Ignore: break; @@ -743,9 +812,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, } else if (RV.isComplex()) { SrcPtr = CreateTempAlloca(ConvertTypeForMem(I->second), "coerce"); StoreComplexToAddr(RV.getComplexVal(), SrcPtr, false); - } else + } else SrcPtr = RV.getAggregateAddr(); - Args.push_back(CreateCoercedLoad(SrcPtr, ArgInfo.getCoerceToType(), + Args.push_back(CreateCoercedLoad(SrcPtr, ArgInfo.getCoerceToType(), *this)); break; } @@ -755,7 +824,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, break; } } - + // If the callee is a bitcast of a function to a varargs pointer to function // type, check to see if we can remove the bitcast. This handles some cases // with unprototyped functions. @@ -765,7 +834,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, const llvm::FunctionType *CurFT = cast(CurPT->getElementType()); const llvm::FunctionType *ActualFT = CalleeF->getFunctionType(); - + if (CE->getOpcode() == llvm::Instruction::BitCast && ActualFT->getReturnType() == CurFT->getReturnType() && ActualFT->getNumParams() == CurFT->getNumParams() && @@ -776,7 +845,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, ArgsMatch = false; break; } - + // Strip the cast if we can get away with it. This is a nice cleanup, // but also allows us to inline the function at -O0 if it is marked // always_inline. @@ -784,28 +853,27 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, Callee = CalleeF; } } - + llvm::BasicBlock *InvokeDest = getInvokeDest(); + unsigned CallingConv; CodeGen::AttributeListType AttributeList; - CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList); + CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList, CallingConv); llvm::AttrListPtr Attrs = llvm::AttrListPtr::get(AttributeList.begin(), AttributeList.end()); - + llvm::CallSite CS; if (!InvokeDest || (Attrs.getFnAttributes() & llvm::Attribute::NoUnwind)) { CS = Builder.CreateCall(Callee, Args.data(), Args.data()+Args.size()); } else { llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); - CS = Builder.CreateInvoke(Callee, Cont, InvokeDest, + CS = Builder.CreateInvoke(Callee, Cont, InvokeDest, Args.data(), Args.data()+Args.size()); EmitBlock(Cont); } CS.setAttributes(Attrs); - if (const llvm::Function *F = - dyn_cast(Callee->stripPointerCasts())) - CS.setCallingConv(F->getCallingConv()); + CS.setCallingConv(static_cast(CallingConv)); // If the call doesn't return, finish the basic block and clear the // insertion point; this allows the rest of IRgen to discard @@ -813,18 +881,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (CS.doesNotReturn()) { Builder.CreateUnreachable(); Builder.ClearInsertionPoint(); - + // FIXME: For now, emit a dummy basic block because expr emitters in // generally are not ready to handle emitting expressions at unreachable // points. EnsureInsertPoint(); - + // Return a reasonable RValue. return GetUndefRValue(RetTy); - } + } llvm::Instruction *CI = CS.getInstruction(); - if (Builder.isNamePreserving() && CI->getType() != llvm::Type::VoidTy) + if (Builder.isNamePreserving() && !CI->getType()->isVoidTy()) CI->setName("call"); switch (RetAI.getKind()) { @@ -866,7 +934,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, } case ABIArgInfo::Expand: - assert(0 && "Invalid ABI kind for return argument"); + assert(0 && "Invalid ABI kind for return argument"); } assert(0 && "Unhandled ABIArgInfo::Kind"); diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h index daf6f0004501..ebf801dcaad1 100644 --- a/lib/CodeGen/CGCall.h +++ b/lib/CodeGen/CGCall.h @@ -49,9 +49,9 @@ namespace CodeGen { /// FunctionArgList - Type for representing both the decl and type /// of parameters to a function. The decl must be either a /// ParmVarDecl or ImplicitParamDecl. - typedef llvm::SmallVector, + typedef llvm::SmallVector, 16> FunctionArgList; - + /// CGFunctionInfo - Class to encapsulate the information about a /// function definition. class CGFunctionInfo : public llvm::FoldingSetNode { @@ -60,6 +60,14 @@ namespace CodeGen { ABIArgInfo info; }; + /// The LLVM::CallingConv to use for this function (as specified by the + /// user). + unsigned CallingConvention; + + /// The LLVM::CallingConv to actually use for this function, which may + /// depend on the ABI. + unsigned EffectiveCallingConvention; + unsigned NumArgs; ArgInfo *Args; @@ -67,7 +75,8 @@ namespace CodeGen { typedef const ArgInfo *const_arg_iterator; typedef ArgInfo *arg_iterator; - CGFunctionInfo(QualType ResTy, + CGFunctionInfo(unsigned CallingConvention, + QualType ResTy, const llvm::SmallVector &ArgTys); ~CGFunctionInfo() { delete[] Args; } @@ -78,21 +87,37 @@ namespace CodeGen { unsigned arg_size() const { return NumArgs; } + /// getCallingConvention - Return the user specified calling + /// convention. + unsigned getCallingConvention() const { return CallingConvention; } + + /// getEffectiveCallingConvention - Return the actual calling convention to + /// use, which may depend on the ABI. + unsigned getEffectiveCallingConvention() const { + return EffectiveCallingConvention; + } + void setEffectiveCallingConvention(unsigned Value) { + EffectiveCallingConvention = Value; + } + QualType getReturnType() const { return Args[0].type; } ABIArgInfo &getReturnInfo() { return Args[0].info; } const ABIArgInfo &getReturnInfo() const { return Args[0].info; } void Profile(llvm::FoldingSetNodeID &ID) { + ID.AddInteger(getCallingConvention()); getReturnType().Profile(ID); for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it) it->type.Profile(ID); } template - static void Profile(llvm::FoldingSetNodeID &ID, + static void Profile(llvm::FoldingSetNodeID &ID, + unsigned CallingConvention, QualType ResTy, Iterator begin, Iterator end) { + ID.AddInteger(CallingConvention); ResTy.Profile(ID); for (; begin != end; ++begin) begin->Profile(ID); diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 2bf8a222a253..4c624205b4ca 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CGDebugInfo.h" +#include "CodeGenFunction.h" #include "CodeGenModule.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -19,6 +20,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/Version.h" #include "clang/Frontend/CompileOptions.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" @@ -47,6 +49,22 @@ void CGDebugInfo::setLocation(SourceLocation Loc) { CurLoc = M->getContext().getSourceManager().getInstantiationLoc(Loc); } +/// getContext - Get context info for the decl. +llvm::DIDescriptor CGDebugInfo::getContext(const VarDecl *Decl, + llvm::DIDescriptor &CompileUnit) { + if (Decl->isFileVarDecl()) + 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; + } + } + return CompileUnit; +} + /// getOrCreateCompileUnit - Get the compile unit from the cache or create a new /// one if necessary. This returns null for invalid source locations. llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { @@ -59,7 +77,7 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { FileName = PLoc.getFilename(); FID = PLoc.getIncludeLoc().getRawEncoding(); } - + // See if this compile unit has been used before. llvm::DICompileUnit &Unit = CompileUnitCache[FID]; if (!Unit.isNull()) return Unit; @@ -104,7 +122,11 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { LangTag = llvm::dwarf::DW_LANG_C89; } - std::string Producer = "clang 1.0";// FIXME: clang version. + std::string Producer = +#ifdef CLANG_VENDOR + CLANG_VENDOR +#endif + "clang " CLANG_VERSION_STRING; bool isOptimized = LO.Optimize; const char *Flags = ""; // FIXME: Encode command line options. @@ -112,10 +134,10 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { unsigned RuntimeVers = 0; if (LO.ObjC1) RuntimeVers = LO.ObjCNonFragileABI ? 2 : 1; - + // Create new compile unit. return Unit = DebugFactory.CreateCompileUnit(LangTag, AbsFileName.getLast(), - AbsFileName.getDirname(), + AbsFileName.getDirname(), Producer, isMain, isOptimized, Flags, RuntimeVers); } @@ -143,14 +165,15 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT, case BuiltinType::LongLong: Encoding = llvm::dwarf::DW_ATE_signed; break; case BuiltinType::Bool: Encoding = llvm::dwarf::DW_ATE_boolean; break; case BuiltinType::Float: + case BuiltinType::LongDouble: case BuiltinType::Double: Encoding = llvm::dwarf::DW_ATE_float; break; - } + } // Bit size, align and offset of the type. uint64_t Size = M->getContext().getTypeSize(BT); uint64_t Align = M->getContext().getTypeAlign(BT); uint64_t Offset = 0; - - return DebugFactory.CreateBasicType(Unit, + + return DebugFactory.CreateBasicType(Unit, BT->getName(M->getContext().getLangOptions()), Unit, 0, Size, Align, Offset, /*flags*/ 0, Encoding); @@ -162,52 +185,72 @@ llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty, unsigned Encoding = llvm::dwarf::DW_ATE_complex_float; if (Ty->isComplexIntegerType()) Encoding = llvm::dwarf::DW_ATE_lo_user; - + uint64_t Size = M->getContext().getTypeSize(Ty); uint64_t Align = M->getContext().getTypeAlign(Ty); uint64_t Offset = 0; - + return DebugFactory.CreateBasicType(Unit, "complex", Unit, 0, Size, Align, Offset, /*flags*/ 0, Encoding); } -/// getOrCreateCVRType - Get the CVR qualified type from the cache or create +/// CreateCVRType - Get the qualified type from the cache or create /// a new one if necessary. -llvm::DIType CGDebugInfo::CreateCVRType(QualType Ty, llvm::DICompileUnit Unit) { +llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DICompileUnit Unit) { + QualifierCollector Qc; + const Type *T = Qc.strip(Ty); + + // Ignore these qualifiers for now. + Qc.removeObjCGCAttr(); + Qc.removeAddressSpace(); + // We will create one Derived type for one qualifier and recurse to handle any // additional ones. - llvm::DIType FromTy; unsigned Tag; - if (Ty.isConstQualified()) { + if (Qc.hasConst()) { Tag = llvm::dwarf::DW_TAG_const_type; - Ty.removeConst(); - FromTy = getOrCreateType(Ty, Unit); - } else if (Ty.isVolatileQualified()) { + Qc.removeConst(); + } else if (Qc.hasVolatile()) { Tag = llvm::dwarf::DW_TAG_volatile_type; - Ty.removeVolatile(); - FromTy = getOrCreateType(Ty, Unit); - } else { - assert(Ty.isRestrictQualified() && "Unknown type qualifier for debug info"); + Qc.removeVolatile(); + } else if (Qc.hasRestrict()) { Tag = llvm::dwarf::DW_TAG_restrict_type; - Ty.removeRestrict(); - FromTy = getOrCreateType(Ty, Unit); + Qc.removeRestrict(); + } else { + assert(Qc.empty() && "Unknown type qualifier for debug info"); + return getOrCreateType(QualType(T, 0), Unit); } - + + llvm::DIType FromTy = getOrCreateType(Qc.apply(T), Unit); + // No need to fill in the Name, Line, Size, Alignment, Offset in case of // CVR derived types. return DebugFactory.CreateDerivedType(Tag, Unit, "", llvm::DICompileUnit(), 0, 0, 0, 0, 0, FromTy); } +llvm::DIType CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty, + llvm::DICompileUnit Unit) { + llvm::DIType EltTy = getOrCreateType(Ty->getPointeeType(), Unit); + + // Bit size, align and offset of the type. + uint64_t Size = M->getContext().getTypeSize(Ty); + uint64_t Align = M->getContext().getTypeAlign(Ty); + + return DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, + "", llvm::DICompileUnit(), + 0, Size, Align, 0, 0, EltTy); +} + llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty, llvm::DICompileUnit Unit) { llvm::DIType EltTy = getOrCreateType(Ty->getPointeeType(), Unit); - + // Bit size, align and offset of the type. uint64_t Size = M->getContext().getTypeSize(Ty); uint64_t Align = M->getContext().getTypeAlign(Ty); - + return DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, "", llvm::DICompileUnit(), 0, Size, Align, 0, 0, EltTy); @@ -258,14 +301,16 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); EltTys.clear(); + unsigned Flags = llvm::DIType::FlagAppleBlock; + EltTy = DebugFactory.CreateCompositeType(Tag, Unit, "__block_descriptor", - DefUnit, 0, FieldOffset, 0, 0, 0, + DefUnit, 0, FieldOffset, 0, 0, Flags, llvm::DIType(), Elements); - + // Bit size, align and offset of the type. uint64_t Size = M->getContext().getTypeSize(Ty); uint64_t Align = M->getContext().getTypeAlign(Ty); - + DescTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, "", llvm::DICompileUnit(), 0, Size, Align, 0, 0, EltTy); @@ -329,9 +374,9 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); EltTy = DebugFactory.CreateCompositeType(Tag, Unit, "__block_literal_generic", - DefUnit, 0, FieldOffset, 0, 0, 0, + DefUnit, 0, FieldOffset, 0, 0, Flags, llvm::DIType(), Elements); - + BlockLiteralGenericSet = true; BlockLiteralGeneric = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, @@ -345,7 +390,7 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, // Typedefs are derived from some other type. If we have a typedef of a // typedef, make sure to emit the whole chain. llvm::DIType Src = getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit); - + // We don't set size information, but do specify where the typedef was // declared. std::string TyName = Ty->getDecl()->getNameAsString(); @@ -366,7 +411,7 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty, // Add the result type at least. EltTys.push_back(getOrCreateType(Ty->getResultType(), Unit)); - + // Set up remainder of arguments if there is a prototype. // FIXME: IF NOT, HOW IS THIS REPRESENTED? llvm-gcc doesn't represent '...'! if (const FunctionProtoType *FTP = dyn_cast(Ty)) { @@ -378,7 +423,7 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty, llvm::DIArray EltTypeArray = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); - + return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_subroutine_type, Unit, "", llvm::DICompileUnit(), 0, 0, 0, 0, 0, @@ -389,7 +434,7 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty, llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, llvm::DICompileUnit Unit) { RecordDecl *Decl = Ty->getDecl(); - + unsigned Tag; if (Decl->isStruct()) Tag = llvm::dwarf::DW_TAG_structure_type; @@ -412,24 +457,24 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, DefUnit = getOrCreateCompileUnit(Decl->getLocation()); Line = PLoc.getLine(); } - + // Records and classes and unions can all be recursive. To handle them, we // first generate a debug descriptor for the struct as a forward declaration. // Then (if it is a definition) we go through and get debug info for all of // its members. Finally, we create a descriptor for the complete type (which // may refer to the forward decl if the struct is recursive) and replace all // uses of the forward declaration with the final definition. - llvm::DIType FwdDecl = + llvm::DICompositeType FwdDecl = DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, 0, 0, 0, 0, llvm::DIType(), llvm::DIArray()); - + // If this is just a forward declaration, return it. if (!Decl->getDefinition(M->getContext())) return FwdDecl; // Otherwise, insert it into the TypeCache so that recursive uses will find // it. - TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl; + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode(); // Convert all the elements. llvm::SmallVector EltTys; @@ -438,7 +483,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, unsigned FieldNo = 0; for (RecordDecl::field_iterator I = Decl->field_begin(), - E = Decl->field_end(); + E = Decl->field_end(); I != E; ++I, ++FieldNo) { FieldDecl *Field = *I; llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit); @@ -454,7 +499,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, PresumedLoc PLoc = SM.getPresumedLoc(FieldDefLoc); llvm::DICompileUnit FieldDefUnit; unsigned FieldLine = 0; - + if (!PLoc.isInvalid()) { FieldDefUnit = getOrCreateCompileUnit(FieldDefLoc); FieldLine = PLoc.getLine(); @@ -464,18 +509,18 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, uint64_t FieldSize = 0; unsigned FieldAlign = 0; if (!FType->isIncompleteArrayType()) { - + // Bit size, align and offset of the type. FieldSize = M->getContext().getTypeSize(FType); Expr *BitWidth = Field->getBitWidth(); if (BitWidth) FieldSize = BitWidth->EvaluateAsInt(M->getContext()).getZExtValue(); - + FieldAlign = M->getContext().getTypeAlign(FType); } - uint64_t FieldOffset = RL.getFieldOffset(FieldNo); - + uint64_t FieldOffset = RL.getFieldOffset(FieldNo); + // Create a DW_TAG_member node to remember the offset of this field in the // struct. FIXME: This is an absolutely insane way to capture this // information. When we gut debug info, this should be fixed. @@ -485,23 +530,25 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, FieldOffset, 0, FieldTy); EltTys.push_back(FieldTy); } - + llvm::DIArray Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); // Bit size, align and offset of the type. uint64_t Size = M->getContext().getTypeSize(Ty); uint64_t Align = M->getContext().getTypeAlign(Ty); - - llvm::DIType RealDecl = + + llvm::DICompositeType RealDecl = DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, Size, Align, 0, 0, llvm::DIType(), Elements); + // Update TypeCache. + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl.getNode(); + // Now that we have a real decl for the struct, replace anything using the // old decl with the new one. This will recursively update the debug info. - FwdDecl.getGV()->replaceAllUsesWith(RealDecl.getGV()); - FwdDecl.getGV()->eraseFromParent(); - + FwdDecl.replaceAllUsesWith(RealDecl); + return RealDecl; } @@ -509,7 +556,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, llvm::DICompileUnit Unit) { ObjCInterfaceDecl *Decl = Ty->getDecl(); - + unsigned Tag = llvm::dwarf::DW_TAG_structure_type; SourceManager &SM = M->getContext().getSourceManager(); @@ -520,7 +567,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine(); - + unsigned RuntimeLang = DefUnit.getLanguage(); // To handle recursive interface, we @@ -529,27 +576,27 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, // its members. Finally, we create a descriptor for the complete type (which // may refer to the forward decl if the struct is recursive) and replace all // uses of the forward declaration with the final definition. - llvm::DIType FwdDecl = + llvm::DICompositeType FwdDecl = DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, 0, 0, 0, 0, llvm::DIType(), llvm::DIArray(), RuntimeLang); - + // If this is just a forward declaration, return it. if (Decl->isForwardDecl()) return FwdDecl; // Otherwise, insert it into the TypeCache so that recursive uses will find // it. - TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl; + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode(); // Convert all the elements. llvm::SmallVector EltTys; ObjCInterfaceDecl *SClass = Decl->getSuperClass(); if (SClass) { - llvm::DIType SClassTy = + llvm::DIType SClassTy = getOrCreateType(M->getContext().getObjCInterfaceType(SClass), Unit); - llvm::DIType InhTag = + llvm::DIType InhTag = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_inheritance, Unit, "", llvm::DICompileUnit(), 0, 0, 0, 0 /* offset */, 0, SClassTy); @@ -576,13 +623,13 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, PresumedLoc PLoc = SM.getPresumedLoc(FieldDefLoc); unsigned FieldLine = PLoc.isInvalid() ? 0 : PLoc.getLine(); - + QualType FType = Field->getType(); uint64_t FieldSize = 0; unsigned FieldAlign = 0; if (!FType->isIncompleteArrayType()) { - + // Bit size, align and offset of the type. FieldSize = M->getContext().getTypeSize(FType); Expr *BitWidth = Field->getBitWidth(); @@ -592,14 +639,14 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, FieldAlign = M->getContext().getTypeAlign(FType); } - uint64_t FieldOffset = RL.getFieldOffset(FieldNo); - + uint64_t FieldOffset = RL.getFieldOffset(FieldNo); + unsigned Flags = 0; if (Field->getAccessControl() == ObjCIvarDecl::Protected) Flags = llvm::DIType::FlagProtected; else if (Field->getAccessControl() == ObjCIvarDecl::Private) Flags = llvm::DIType::FlagPrivate; - + // Create a DW_TAG_member node to remember the offset of this field in the // struct. FIXME: This is an absolutely insane way to capture this // information. When we gut debug info, this should be fixed. @@ -609,24 +656,26 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, FieldOffset, Flags, FieldTy); EltTys.push_back(FieldTy); } - + llvm::DIArray Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); // Bit size, align and offset of the type. uint64_t Size = M->getContext().getTypeSize(Ty); uint64_t Align = M->getContext().getTypeAlign(Ty); - - llvm::DIType RealDecl = + + llvm::DICompositeType RealDecl = DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, Size, Align, 0, 0, llvm::DIType(), Elements, RuntimeLang); + // Update TypeCache. + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl.getNode(); + // Now that we have a real decl for the struct, replace anything using the // old decl with the new one. This will recursively update the debug info. - FwdDecl.getGV()->replaceAllUsesWith(RealDecl.getGV()); - FwdDecl.getGV()->eraseFromParent(); - + FwdDecl.replaceAllUsesWith(RealDecl); + return RealDecl; } @@ -637,13 +686,13 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, llvm::SmallVector Enumerators; // Create DIEnumerator elements for each enumerator. - for (EnumDecl::enumerator_iterator + for (EnumDecl::enumerator_iterator Enum = Decl->enumerator_begin(), EnumEnd = Decl->enumerator_end(); Enum != EnumEnd; ++Enum) { Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getNameAsString(), Enum->getInitVal().getZExtValue())); } - + // Return a CompositeType for the enum itself. llvm::DIArray EltArray = DebugFactory.GetOrCreateArray(Enumerators.data(), Enumerators.size()); @@ -655,7 +704,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, PresumedLoc PLoc = SM.getPresumedLoc(DefLoc); unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine(); - + // Size and align of the type. uint64_t Size = 0; unsigned Align = 0; @@ -663,7 +712,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, Size = M->getContext().getTypeSize(Ty); Align = M->getContext().getTypeAlign(Ty); } - + return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_enumeration_type, Unit, EnumName, DefUnit, Line, Size, Align, 0, 0, @@ -676,7 +725,7 @@ llvm::DIType CGDebugInfo::CreateType(const TagType *Ty, return CreateType(RT, Unit); else if (const EnumType *ET = dyn_cast(Ty)) return CreateType(ET, Unit); - + return llvm::DIType(); } @@ -684,8 +733,8 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, llvm::DICompileUnit Unit) { uint64_t Size; uint64_t Align; - - + + // FIXME: make getTypeAlign() aware of VLAs and incomplete array types if (const VariableArrayType *VAT = dyn_cast(Ty)) { Size = 0; @@ -699,7 +748,7 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, Size = M->getContext().getTypeSize(Ty); Align = M->getContext().getTypeAlign(Ty); } - + // Add the dimensions of the array. FIXME: This loses CV qualifiers from // interior arrays, do we care? Why aren't nested arrays represented the // obvious/recursive way? @@ -708,12 +757,13 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, while ((Ty = dyn_cast(EltTy))) { uint64_t Upper = 0; if (const ConstantArrayType *CAT = dyn_cast(Ty)) - Upper = CAT->getSize().getZExtValue() - 1; + if (CAT->getSize().getZExtValue()) + Upper = CAT->getSize().getZExtValue() - 1; // FIXME: Verify this is right for VLAs. Subscripts.push_back(DebugFactory.GetOrCreateSubrange(0, Upper)); EltTy = Ty->getElementType(); } - + llvm::DIArray SubscriptArray = DebugFactory.GetOrCreateArray(Subscripts.data(), Subscripts.size()); @@ -731,14 +781,29 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DICompileUnit Unit) { if (Ty.isNull()) return llvm::DIType(); - - // Check to see if the compile unit already has created this type. - llvm::DIType &Slot = TypeCache[Ty.getAsOpaquePtr()]; - if (!Slot.isNull()) return Slot; - // Handle CVR qualifiers, which recursively handles what they refer to. - if (Ty.getCVRQualifiers()) - return Slot = CreateCVRType(Ty, Unit); + // Check for existing entry. + std::map::iterator it = + TypeCache.find(Ty.getAsOpaquePtr()); + if (it != TypeCache.end()) { + // Verify that the debug info still exists. + if (&*it->second) + return llvm::DIType(cast(it->second)); + } + + // Otherwise create the type. + llvm::DIType Res = CreateTypeNode(Ty, Unit); + TypeCache.insert(std::make_pair(Ty.getAsOpaquePtr(), Res.getNode())); + return Res; +} + +/// getOrCreateTypeNode - Get the type metadata node from the cache or create a +/// new one if necessary. +llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, + llvm::DICompileUnit Unit) { + // Handle qualifiers, which recursively handles what they refer to. + if (Ty.hasQualifiers()) + return CreateQualifiedType(Ty, Unit); // Work out details of type. switch (Ty->getTypeClass()) { @@ -748,53 +813,52 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, #define DEPENDENT_TYPE(Class, Base) case Type::Class: #include "clang/AST/TypeNodes.def" assert(false && "Dependent types cannot show up in debug information"); - + + default: case Type::LValueReference: case Type::RValueReference: case Type::Vector: case Type::ExtVector: - case Type::ExtQual: case Type::FixedWidthInt: case Type::MemberPointer: case Type::TemplateSpecialization: case Type::QualifiedName: // Unsupported types return llvm::DIType(); - case Type::ObjCObjectPointer: // Encode id

in debug info just like id. - return Slot = getOrCreateType(M->getContext().getObjCIdType(), Unit); - - case Type::ObjCQualifiedInterface: // Drop protocols from interface. - case Type::ObjCInterface: - return Slot = CreateType(cast(Ty), Unit); - case Type::Builtin: return Slot = CreateType(cast(Ty), Unit); - case Type::Complex: return Slot = CreateType(cast(Ty), Unit); - case Type::Pointer: return Slot = CreateType(cast(Ty), Unit); + case Type::ObjCObjectPointer: + return CreateType(cast(Ty), Unit); + case Type::ObjCInterface: + return CreateType(cast(Ty), Unit); + case Type::Builtin: return CreateType(cast(Ty), Unit); + case Type::Complex: return CreateType(cast(Ty), Unit); + case Type::Pointer: return CreateType(cast(Ty), Unit); case Type::BlockPointer: - return Slot = CreateType(cast(Ty), Unit); - case Type::Typedef: return Slot = CreateType(cast(Ty), Unit); + return CreateType(cast(Ty), Unit); + case Type::Typedef: return CreateType(cast(Ty), Unit); case Type::Record: case Type::Enum: - return Slot = CreateType(cast(Ty), Unit); + return CreateType(cast(Ty), Unit); case Type::FunctionProto: case Type::FunctionNoProto: - return Slot = CreateType(cast(Ty), Unit); - + return CreateType(cast(Ty), Unit); + case Type::Elaborated: + return getOrCreateType(cast(Ty)->getUnderlyingType(), + Unit); + case Type::ConstantArray: + case Type::ConstantArrayWithExpr: + case Type::ConstantArrayWithoutExpr: case Type::VariableArray: case Type::IncompleteArray: - return Slot = CreateType(cast(Ty), Unit); + return CreateType(cast(Ty), Unit); case Type::TypeOfExpr: - return Slot = getOrCreateType(cast(Ty)->getUnderlyingExpr() - ->getType(), Unit); + return getOrCreateType(cast(Ty)->getUnderlyingExpr() + ->getType(), Unit); case Type::TypeOf: - return Slot = getOrCreateType(cast(Ty)->getUnderlyingType(), - Unit); + return getOrCreateType(cast(Ty)->getUnderlyingType(), Unit); case Type::Decltype: - return Slot = getOrCreateType(cast(Ty)->getUnderlyingExpr() - ->getType(), Unit); + return getOrCreateType(cast(Ty)->getUnderlyingType(), Unit); } - - return Slot; } /// EmitFunctionStart - Constructs the debug code for entering a function - @@ -803,25 +867,27 @@ void CGDebugInfo::EmitFunctionStart(const char *Name, QualType ReturnType, llvm::Function *Fn, CGBuilderTy &Builder) { const char *LinkageName = Name; - + // Skip the asm prefix if it exists. // // FIXME: This should probably be the unmangled name? if (Name[0] == '\01') ++Name; - + // FIXME: Why is this using CurLoc??? llvm::DICompileUnit Unit = getOrCreateCompileUnit(CurLoc); SourceManager &SM = M->getContext().getSourceManager(); unsigned LineNo = SM.getPresumedLoc(CurLoc).getLine(); - + llvm::DISubprogram SP = DebugFactory.CreateSubprogram(Unit, Name, Name, LinkageName, Unit, LineNo, getOrCreateType(ReturnType, Unit), Fn->hasInternalLinkage(), true/*definition*/); - + +#ifndef ATTACH_DEBUG_INFO_TO_AN_INSN DebugFactory.InsertSubprogramStart(SP, Builder.GetInsertBlock()); - +#endif + // Push function on region stack. RegionStack.push_back(SP); } @@ -829,10 +895,10 @@ void CGDebugInfo::EmitFunctionStart(const char *Name, QualType ReturnType, void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) { if (CurLoc.isInvalid() || CurLoc.isMacroID()) return; - + // Don't bother if things are the same as last time. SourceManager &SM = M->getContext().getSourceManager(); - if (CurLoc == PrevLoc + if (CurLoc == PrevLoc || (SM.getInstantiationLineNumber(CurLoc) == SM.getInstantiationLineNumber(PrevLoc) && SM.isFromSameFile(CurLoc, PrevLoc))) @@ -844,8 +910,19 @@ void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) { // Get the appropriate compile unit. llvm::DICompileUnit Unit = getOrCreateCompileUnit(CurLoc); PresumedLoc PLoc = SM.getPresumedLoc(CurLoc); + +#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN + llvm::DIDescriptor DR = RegionStack.back(); + llvm::DIScope DS = llvm::DIScope(DR.getNode()); + llvm::DILocation DO(NULL); + llvm::DILocation DL = + DebugFactory.CreateLocation(PLoc.getLine(), PLoc.getColumn(), + DS, DO); + Builder.SetCurrentDebugLocation(DL.getNode()); +#else DebugFactory.InsertStopPoint(Unit, PLoc.getLine(), PLoc.getColumn(), - Builder.GetInsertBlock()); + Builder.GetInsertBlock()); +#endif } /// EmitRegionStart- Constructs the debug code for entering a declarative @@ -854,9 +931,11 @@ void CGDebugInfo::EmitRegionStart(llvm::Function *Fn, CGBuilderTy &Builder) { llvm::DIDescriptor D; if (!RegionStack.empty()) D = RegionStack.back(); - D = DebugFactory.CreateBlock(D); + D = DebugFactory.CreateLexicalBlock(D); RegionStack.push_back(D); +#ifndef ATTACH_DEBUG_INFO_TO_AN_INSN DebugFactory.InsertRegionStart(D, Builder.GetInsertBlock()); +#endif } /// EmitRegionEnd - Constructs the debug code for exiting a declarative @@ -866,8 +945,10 @@ void CGDebugInfo::EmitRegionEnd(llvm::Function *Fn, CGBuilderTy &Builder) { // Provide an region stop point. EmitStopPoint(Fn, Builder); - + +#ifndef ATTACH_DEBUG_INFO_TO_AN_INSN DebugFactory.InsertRegionEnd(RegionStack.back(), Builder.GetInsertBlock()); +#endif RegionStack.pop_back(); } @@ -884,7 +965,139 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, return; llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation()); - llvm::DIType Ty = getOrCreateType(Decl->getType(), Unit); + QualType Type = Decl->getType(); + llvm::DIType Ty = getOrCreateType(Type, Unit); + if (Decl->hasAttr()) { + llvm::DICompileUnit DefUnit; + unsigned Tag = llvm::dwarf::DW_TAG_structure_type; + + llvm::SmallVector 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 = M->getContext().getPointerType(M->getContext().VoidTy); + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = M->getContext().getTypeSize(FType); + FieldAlign = M->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 = M->getContext().getPointerType(M->getContext().VoidTy); + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = M->getContext().getTypeSize(FType); + FieldAlign = M->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 = M->getContext().getFixedWidthIntType(32, true); // Int32Ty; + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = M->getContext().getTypeSize(FType); + FieldAlign = M->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 = M->getContext().getFixedWidthIntType(32, true); // Int32Ty; + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = M->getContext().getTypeSize(FType); + FieldAlign = M->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 = M->BlockRequiresCopying(Type); + if (HasCopyAndDispose) { + FType = M->getContext().getPointerType(M->getContext().VoidTy); + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = M->getContext().getTypeSize(FType); + FieldAlign = M->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 = M->getContext().getPointerType(M->getContext().VoidTy); + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = M->getContext().getTypeSize(FType); + FieldAlign = M->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 = M->getContext().getDeclAlignInBytes(Decl); + if (Align > M->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 = M->getContext().getConstantArrayType(M->getContext().CharTy, + pad, ArrayType::Normal, 0); + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = M->getContext().getTypeSize(FType); + FieldAlign = M->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 = M->getContext().getTypeSize(FType); + FieldAlign = Align*8; + std::string Name = Decl->getNameAsString(); + + FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, + Name, 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); + } // Get location information. SourceManager &SM = M->getContext().getSourceManager(); @@ -895,21 +1108,222 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, else Unit = llvm::DICompileUnit(); - + // Create the descriptor for the variable. - llvm::DIVariable D = + llvm::DIVariable D = DebugFactory.CreateVariable(Tag, RegionStack.back(),Decl->getNameAsString(), Unit, Line, Ty); // Insert an llvm.dbg.declare into the current block. DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock()); } +/// EmitDeclare - Emit local variable declaration debug info. +void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, + llvm::Value *Storage, CGBuilderTy &Builder, + CodeGenFunction *CGF) { + const ValueDecl *Decl = BDRE->getDecl(); + 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 CompileOptions &CO = M->getCompileOpts(); + if (CO.OptimizationLevel || Builder.GetInsertBlock() == 0) + return; + + uint64_t XOffset = 0; + llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation()); + QualType Type = Decl->getType(); + llvm::DIType Ty = getOrCreateType(Type, Unit); + if (Decl->hasAttr()) { + llvm::DICompileUnit DefUnit; + unsigned Tag = llvm::dwarf::DW_TAG_structure_type; + + llvm::SmallVector 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 = M->getContext().getPointerType(M->getContext().VoidTy); + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = M->getContext().getTypeSize(FType); + FieldAlign = M->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 = M->getContext().getPointerType(M->getContext().VoidTy); + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = M->getContext().getTypeSize(FType); + FieldAlign = M->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 = M->getContext().getFixedWidthIntType(32, true); // Int32Ty; + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = M->getContext().getTypeSize(FType); + FieldAlign = M->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 = M->getContext().getFixedWidthIntType(32, true); // Int32Ty; + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = M->getContext().getTypeSize(FType); + FieldAlign = M->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 = M->BlockRequiresCopying(Type); + if (HasCopyAndDispose) { + FType = M->getContext().getPointerType(M->getContext().VoidTy); + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = M->getContext().getTypeSize(FType); + FieldAlign = M->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 = M->getContext().getPointerType(M->getContext().VoidTy); + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = M->getContext().getTypeSize(FType); + FieldAlign = M->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 = M->getContext().getDeclAlignInBytes(Decl); + if (Align > M->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 = M->getContext().getConstantArrayType(M->getContext().CharTy, + pad, ArrayType::Normal, 0); + FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + FieldSize = M->getContext().getTypeSize(FType); + FieldAlign = M->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 = M->getContext().getTypeSize(FType); + FieldAlign = Align*8; + std::string Name = Decl->getNameAsString(); + + XOffset = FieldOffset; + FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, + Name, DefUnit, + 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); + } + + // Get location information. + SourceManager &SM = M->getContext().getSourceManager(); + PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); + unsigned Line = 0; + if (!PLoc.isInvalid()) + Line = PLoc.getLine(); + else + Unit = llvm::DICompileUnit(); + + uint64_t offset = CGF->BlockDecls[Decl]; + llvm::SmallVector addr; + llvm::LLVMContext &VMContext = M->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)); + 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)); + offset = CGF->LLVMPointerWidth/8; // offset of __forwarding field + addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), + offset)); + 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)); + offset = XOffset/8; // offset of x field + addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), + offset)); + } + + // Create the descriptor for the variable. + llvm::DIVariable D = + DebugFactory.CreateComplexVariable(Tag, RegionStack.back(), + Decl->getNameAsString(), Unit, Line, Ty, + addr); + // Insert an llvm.dbg.declare into the current block. + DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertPoint()); +} + void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *Decl, llvm::Value *Storage, CGBuilderTy &Builder) { EmitDeclare(Decl, llvm::dwarf::DW_TAG_auto_variable, Storage, Builder); } +void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( + const BlockDeclRefExpr *BDRE, llvm::Value *Storage, CGBuilderTy &Builder, + CodeGenFunction *CGF) { + EmitDeclare(BDRE, llvm::dwarf::DW_TAG_auto_variable, Storage, Builder, CGF); +} + /// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument /// variable declaration. void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI, @@ -920,7 +1334,7 @@ void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI, /// EmitGlobalVariable - Emit information about a global variable. -void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, +void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, const VarDecl *Decl) { // Do not emit variable debug information while generating optimized code. @@ -936,29 +1350,30 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine(); - std::string Name = Decl->getNameAsString(); + std::string Name = Var->getName(); QualType T = Decl->getType(); if (T->isIncompleteArrayType()) { - + // CodeGen turns int[] into int[1] so we'll do the same here. llvm::APSInt ConstVal(32); - + ConstVal = 1; QualType ET = M->getContext().getAsArrayType(T)->getElementType(); - - T = M->getContext().getConstantArrayType(ET, ConstVal, + + T = M->getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } - DebugFactory.CreateGlobalVariable(Unit, Name, Name, "", Unit, LineNo, + DebugFactory.CreateGlobalVariable(getContext(Decl, Unit), + Name, Name, "", Unit, LineNo, getOrCreateType(T, Unit), Var->hasInternalLinkage(), true/*definition*/, Var); } /// EmitGlobalVariable - Emit information about an objective-c interface. -void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, +void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, ObjCInterfaceDecl *Decl) { // Create global variable debug descriptor. llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation()); @@ -970,14 +1385,14 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, QualType T = M->getContext().getObjCInterfaceType(Decl); if (T->isIncompleteArrayType()) { - + // CodeGen turns int[] into int[1] so we'll do the same here. llvm::APSInt ConstVal(32); - + ConstVal = 1; QualType ET = M->getContext().getAsArrayType(T)->getElementType(); - - T = M->getContext().getConstantArrayType(ET, ConstVal, + + T = M->getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } @@ -986,4 +1401,3 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, Var->hasInternalLinkage(), true/*definition*/, Var); } - diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index de655800fa08..0a617b999240 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This is the source level debug info generator for llvm translation. +// This is the source level debug info generator for llvm translation. // //===----------------------------------------------------------------------===// @@ -15,28 +15,35 @@ #define CLANG_CODEGEN_CGDEBUGINFO_H #include "clang/AST/Type.h" +#include "clang/AST/Expr.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Analysis/DebugInfo.h" +#include "llvm/Support/ValueHandle.h" #include #include "CGBuilder.h" +namespace llvm { + class MDNode; +} + namespace clang { class VarDecl; class ObjCInterfaceDecl; namespace CodeGen { class CodeGenModule; + class CodeGenFunction; -/// CGDebugInfo - This class gathers all debug information during compilation -/// and is responsible for emitting to llvm globals or pass directly to +/// CGDebugInfo - This class gathers all debug information during compilation +/// and is responsible for emitting to llvm globals or pass directly to /// the backend. class CGDebugInfo { CodeGenModule *M; bool isMainCompileUnitCreated; llvm::DIFactory DebugFactory; - + SourceLocation CurLoc, PrevLoc; /// CompileUnitCache - Cache of previously constructed CompileUnits. @@ -44,8 +51,8 @@ class CGDebugInfo { /// TypeCache - Cache of previously constructed Types. // FIXME: Eliminate this map. Be careful of iterator invalidation. - std::map TypeCache; - + std::map TypeCache; + bool BlockLiteralGenericSet; llvm::DIType BlockLiteralGeneric; @@ -54,8 +61,10 @@ class CGDebugInfo { /// Helper functions for getOrCreateType. llvm::DIType CreateType(const BuiltinType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const ComplexType *Ty, llvm::DICompileUnit U); - llvm::DIType CreateCVRType(QualType Ty, llvm::DICompileUnit U); + llvm::DIType CreateQualifiedType(QualType Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const TypedefType *Ty, llvm::DICompileUnit U); + llvm::DIType CreateType(const ObjCObjectPointerType *Ty, + llvm::DICompileUnit Unit); llvm::DIType CreateType(const PointerType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const BlockPointerType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const FunctionType *Ty, llvm::DICompileUnit U); @@ -81,12 +90,12 @@ public: /// start of a new function. void EmitFunctionStart(const char *Name, QualType ReturnType, llvm::Function *Fn, CGBuilderTy &Builder); - + /// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start - /// of a new block. + /// of a new block. void EmitRegionStart(llvm::Function *Fn, CGBuilderTy &Builder); - - /// EmitRegionEnd - Emit call to llvm.dbg.region.end to indicate end of a + + /// EmitRegionEnd - Emit call to llvm.dbg.region.end to indicate end of a /// block. void EmitRegionEnd(llvm::Function *Fn, CGBuilderTy &Builder); @@ -95,23 +104,36 @@ public: void EmitDeclareOfAutoVariable(const VarDecl *Decl, llvm::Value *AI, CGBuilderTy &Builder); + /// EmitDeclareOfBlockDeclRefVariable - Emit call to llvm.dbg.declare for an + /// imported variable declaration in a block. + void EmitDeclareOfBlockDeclRefVariable(const BlockDeclRefExpr *BDRE, + llvm::Value *AI, + CGBuilderTy &Builder, + CodeGenFunction *CGF); + /// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument /// variable declaration. void EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI, CGBuilderTy &Builder); - + /// EmitGlobalVariable - Emit information about a global variable. void EmitGlobalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl); /// EmitGlobalVariable - Emit information about an objective-c interface. void EmitGlobalVariable(llvm::GlobalVariable *GV, ObjCInterfaceDecl *Decl); - + private: /// EmitDeclare - Emit call to llvm.dbg.declare for a variable declaration. void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI, CGBuilderTy &Builder); - - + + /// EmitDeclare - Emit call to llvm.dbg.declare for a variable declaration. + 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); + /// getOrCreateCompileUnit - Get the compile unit from the cache or create a /// new one if necessary. llvm::DICompileUnit getOrCreateCompileUnit(SourceLocation Loc); @@ -119,8 +141,12 @@ private: /// getOrCreateType - Get the type from the cache or create a new type if /// necessary. llvm::DIType getOrCreateType(QualType Ty, llvm::DICompileUnit Unit); + + /// CreateTypeNode - Create type metadata for a source language type. + llvm::DIType CreateTypeNode(QualType Ty, llvm::DICompileUnit Unit); }; } // namespace CodeGen } // namespace clang + #endif diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 2ae7e225ebbf..7feff83dee6b 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -35,22 +35,22 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Function: // void X(); case Decl::Record: // struct/union/class X; case Decl::Enum: // enum X; - case Decl::EnumConstant: // enum ? { X = ? } + case Decl::EnumConstant: // enum ? { X = ? } case Decl::CXXRecord: // struct/union/class X; [C++] // None of these decls require codegen support. return; - + case Decl::Var: { const VarDecl &VD = cast(D); - assert(VD.isBlockVarDecl() && + assert(VD.isBlockVarDecl() && "Should not see file-scope variables inside a function!"); return EmitBlockVarDecl(VD); } - + case Decl::Typedef: { // typedef int X; const TypedefDecl &TD = cast(D); QualType Ty = TD.getUnderlyingType(); - + if (Ty->isVariablyModifiedType()) EmitVLASize(Ty); } @@ -62,7 +62,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) { if (D.hasAttr()) CGM.ErrorUnsupported(&D, "__asm__"); - + switch (D.getStorageClass()) { case VarDecl::None: case VarDecl::Auto: @@ -95,27 +95,28 @@ CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D, if (const FunctionDecl *FD = dyn_cast(CurFuncDecl)) ContextName = CGM.getMangledName(FD); else if (isa(CurFuncDecl)) - ContextName = std::string(CurFn->getNameStart(), - CurFn->getNameStart() + CurFn->getNameLen()); + ContextName = CurFn->getName(); else assert(0 && "Unknown context for block var decl"); - + Name = ContextName + Separator + D.getNameAsString(); } const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty); - return new llvm::GlobalVariable(LTy, Ty.isConstant(getContext()), Linkage, - llvm::Constant::getNullValue(LTy), Name, - &CGM.getModule(), D.isThreadSpecified(), - Ty.getAddressSpace()); + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(CGM.getModule(), LTy, + Ty.isConstant(getContext()), Linkage, + CGM.EmitNullConstant(D.getType()), Name, 0, + D.isThreadSpecified(), Ty.getAddressSpace()); + GV->setAlignment(getContext().getDeclAlignInBytes(&D)); + return GV; } -void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { - +void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { llvm::Value *&DMEntry = LocalDeclMap[&D]; assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); - - llvm::GlobalVariable *GV = + + llvm::GlobalVariable *GV = CreateStaticBlockVarDecl(D, ".", llvm::GlobalValue::InternalLinkage); // Store into LocalDeclMap before generating initializer to handle @@ -123,14 +124,11 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { DMEntry = GV; // Make sure to evaluate VLA bounds now so that we have them for later. + // + // FIXME: Can this happen? if (D.getType()->isVariablyModifiedType()) EmitVLASize(D.getType()); - if (D.getType()->isReferenceType()) { - CGM.ErrorUnsupported(&D, "static declaration with reference type"); - return; - } - if (D.getInit()) { llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), D.getType(), this); @@ -140,7 +138,7 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { if (!getContext().getLangOptions().CPlusPlus) CGM.ErrorUnsupported(D.getInit(), "constant l-value expression"); else - GenerateStaticCXXBlockVarDeclInit(D, GV); + EmitStaticCXXBlockVarDeclInit(D, GV); } else { // The initializer may differ in type from the global. Rewrite // the global to match the initializer. (We have to do this @@ -148,23 +146,24 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { // in the LLVM type system.) if (GV->getType() != Init->getType()) { llvm::GlobalVariable *OldGV = GV; - - GV = new llvm::GlobalVariable(Init->getType(), OldGV->isConstant(), + + GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), + OldGV->isConstant(), OldGV->getLinkage(), Init, "", - &CGM.getModule(), D.isThreadSpecified(), + 0, D.isThreadSpecified(), D.getType().getAddressSpace()); // Steal the name of the old global GV->takeName(OldGV); // Replace all uses of the old global with the new global - llvm::Constant *NewPtrForOldDecl = + llvm::Constant *NewPtrForOldDecl = llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); OldGV->replaceAllUsesWith(NewPtrForOldDecl); // Erase the old global, since it is no longer used. OldGV->eraseFromParent(); - } + } GV->setInitializer(Init); } @@ -174,14 +173,14 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { if (const AnnotateAttr *AA = D.getAttr()) { SourceManager &SM = CGM.getContext().getSourceManager(); llvm::Constant *Ann = - CGM.EmitAnnotateAttr(GV, AA, + CGM.EmitAnnotateAttr(GV, AA, SM.getInstantiationLineNumber(D.getLocation())); CGM.AddAnnotation(Ann); } if (const SectionAttr *SA = D.getAttr()) GV->setSection(SA->getName()); - + if (D.hasAttr()) CGM.AddUsedGlobal(GV); @@ -202,7 +201,13 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { DI->EmitGlobalVariable(static_cast(GV), &D); } } + +unsigned CodeGenFunction::getByRefValueLLVMField(const ValueDecl *VD) const { + assert(ByRefValueInfo.count(VD) && "Did not find value!"); + return ByRefValueInfo.find(VD)->second.second; +} + /// BuildByRefType - This routine changes a __block variable declared as T x /// into: /// @@ -211,32 +216,91 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { /// void *__forwarding; /// int32_t __flags; /// int32_t __size; -/// void *__copy_helper; -/// void *__destroy_helper; +/// void *__copy_helper; // only if needed +/// void *__destroy_helper; // only if needed +/// char padding[X]; // only if needed /// T x; /// } x /// -/// Align is the alignment needed in bytes for x. -const llvm::Type *CodeGenFunction::BuildByRefType(QualType Ty, - uint64_t Align) { - const llvm::Type *LTy = ConvertType(Ty); - bool needsCopyDispose = BlockRequiresCopying(Ty); - std::vector Types(needsCopyDispose*2+5); - const llvm::PointerType *PtrToInt8Ty - = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); - Types[0] = PtrToInt8Ty; - Types[1] = PtrToInt8Ty; - Types[2] = llvm::Type::Int32Ty; - Types[3] = llvm::Type::Int32Ty; - if (needsCopyDispose) { - Types[4] = PtrToInt8Ty; - Types[5] = PtrToInt8Ty; +const llvm::Type *CodeGenFunction::BuildByRefType(const ValueDecl *D) { + std::pair &Info = ByRefValueInfo[D]; + if (Info.first) + return Info.first; + + QualType Ty = D->getType(); + + std::vector Types; + + const llvm::PointerType *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + + llvm::PATypeHolder ByRefTypeHolder = llvm::OpaqueType::get(VMContext); + + // void *__isa; + Types.push_back(Int8PtrTy); + + // void *__forwarding; + Types.push_back(llvm::PointerType::getUnqual(ByRefTypeHolder)); + + // int32_t __flags; + Types.push_back(llvm::Type::getInt32Ty(VMContext)); + + // int32_t __size; + Types.push_back(llvm::Type::getInt32Ty(VMContext)); + + bool HasCopyAndDispose = BlockRequiresCopying(Ty); + if (HasCopyAndDispose) { + /// void *__copy_helper; + Types.push_back(Int8PtrTy); + + /// void *__destroy_helper; + Types.push_back(Int8PtrTy); } - // FIXME: Align this on at least an Align boundary, assert if we can't. - assert((Align <= unsigned(Target.getPointerAlign(0))/8) - && "Can't align more than pointer yet"); - Types[needsCopyDispose*2 + 4] = LTy; - return llvm::StructType::get(Types, false); + + bool Packed = false; + unsigned Align = getContext().getDeclAlignInBytes(D); + if (Align > Target.getPointerAlign(0) / 8) { + // We have to insert padding. + + // The struct above has 2 32-bit integers. + unsigned CurrentOffsetInBytes = 4 * 2; + + // And either 2 or 4 pointers. + CurrentOffsetInBytes += (HasCopyAndDispose ? 4 : 2) * + CGM.getTargetData().getTypeAllocSize(Int8PtrTy); + + // Align the offset. + unsigned AlignedOffsetInBytes = + llvm::RoundUpToAlignment(CurrentOffsetInBytes, Align); + + unsigned NumPaddingBytes = AlignedOffsetInBytes - CurrentOffsetInBytes; + if (NumPaddingBytes > 0) { + const llvm::Type *Ty = llvm::Type::getInt8Ty(VMContext); + // FIXME: We need a sema error for alignment larger than the minimum of the + // maximal stack alignmint and the alignment of malloc on the system. + if (NumPaddingBytes > 1) + Ty = llvm::ArrayType::get(Ty, NumPaddingBytes); + + Types.push_back(Ty); + + // We want a packed struct. + Packed = true; + } + } + + // T x; + Types.push_back(ConvertType(Ty)); + + const llvm::Type *T = llvm::StructType::get(VMContext, Types, Packed); + + cast(ByRefTypeHolder.get())->refineAbstractTypeTo(T); + CGM.getModule().addTypeName("struct.__block_byref_" + D->getNameAsString(), + ByRefTypeHolder.get()); + + Info.first = ByRefTypeHolder.get(); + + Info.second = Types.size() - 1; + + return Info.first; } /// EmitLocalBlockVarDecl - Emit code and set up an entry in LocalDeclMap for a @@ -255,10 +319,10 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { const llvm::Type *LTy = ConvertTypeForMem(Ty); Align = getContext().getDeclAlignInBytes(&D); if (isByRef) - LTy = BuildByRefType(Ty, Align); + LTy = BuildByRefType(&D); llvm::AllocaInst *Alloc = CreateTempAlloca(LTy); Alloc->setName(D.getNameAsString().c_str()); - + if (isByRef) Align = std::max(Align, unsigned(Target.getPointerAlign(0) / 8)); Alloc->setAlignment(Align); @@ -267,48 +331,55 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { // Targets that don't support recursion emit locals as globals. const char *Class = D.getStorageClass() == VarDecl::Register ? ".reg." : ".auto."; - DeclPtr = CreateStaticBlockVarDecl(D, Class, + DeclPtr = CreateStaticBlockVarDecl(D, Class, llvm::GlobalValue ::InternalLinkage); } - + + // FIXME: Can this happen? if (Ty->isVariablyModifiedType()) EmitVLASize(Ty); } else { + EnsureInsertPoint(); + if (!DidCallStackSave) { // Save the stack. - const llvm::Type *LTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *LTy = llvm::Type::getInt8PtrTy(VMContext); llvm::Value *Stack = CreateTempAlloca(LTy, "saved_stack"); - + llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::stacksave); llvm::Value *V = Builder.CreateCall(F); - + Builder.CreateStore(V, Stack); DidCallStackSave = true; - + { // Push a cleanup block and restore the stack there. CleanupScope scope(*this); - + V = Builder.CreateLoad(Stack, "tmp"); llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::stackrestore); Builder.CreateCall(F, V); } } - + // Get the element type. - const llvm::Type *LElemTy = ConvertTypeForMem(Ty); + const llvm::Type *LElemTy = ConvertTypeForMem(Ty); const llvm::Type *LElemPtrTy = llvm::PointerType::get(LElemTy, D.getType().getAddressSpace()); llvm::Value *VLASize = EmitVLASize(Ty); // Downcast the VLA size expression - VLASize = Builder.CreateIntCast(VLASize, llvm::Type::Int32Ty, false, "tmp"); - + VLASize = Builder.CreateIntCast(VLASize, llvm::Type::getInt32Ty(VMContext), + false, "tmp"); + // Allocate memory for the array. - llvm::Value *VLA = Builder.CreateAlloca(llvm::Type::Int8Ty, VLASize, "vla"); + llvm::AllocaInst *VLA = + Builder.CreateAlloca(llvm::Type::getInt8Ty(VMContext), VLASize, "vla"); + VLA->setAlignment(getContext().getDeclAlignInBytes(&D)); + DeclPtr = Builder.CreateBitCast(VLA, LElemPtrTy, "tmp"); } @@ -318,35 +389,39 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { // Emit debug info for local var declaration. if (CGDebugInfo *DI = getDebugInfo()) { + assert(HaveInsertPoint() && "Unexpected unreachable point!"); + DI->setLocation(D.getLocation()); if (Target.useGlobalsForAutomaticVariables()) { DI->EmitGlobalVariable(static_cast(DeclPtr), &D); - } - else if (isByRef) { - llvm::Value *Loc; - bool needsCopyDispose = BlockRequiresCopying(Ty); - Loc = Builder.CreateStructGEP(DeclPtr, 1, "forwarding"); - Loc = Builder.CreateLoad(Loc, false); - Loc = Builder.CreateBitCast(Loc, DeclPtr->getType()); - Loc = Builder.CreateStructGEP(Loc, needsCopyDispose*2+4, "x"); - DI->EmitDeclareOfAutoVariable(&D, Loc, Builder); } else DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder); } // If this local has an initializer, emit it now. - if (const Expr *Init = D.getInit()) { + const Expr *Init = D.getInit(); + + // If we are at an unreachable point, we don't need to emit the initializer + // unless it contains a label. + if (!HaveInsertPoint()) { + if (!ContainsLabel(Init)) + Init = 0; + else + EnsureInsertPoint(); + } + + if (Init) { llvm::Value *Loc = DeclPtr; - if (isByRef) { - bool needsCopyDispose = BlockRequiresCopying(Ty); - Loc = Builder.CreateStructGEP(DeclPtr, needsCopyDispose*2+4, "x"); - } + if (isByRef) + Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), + D.getNameAsString()); + if (Ty->isReferenceType()) { - llvm::Value *V = EmitReferenceBindingToExpr(Init, Ty).getScalarVal(); - EmitStoreOfScalar(V, Loc, false, Ty); + RValue RV = EmitReferenceBindingToExpr(Init, Ty, /*IsInitializer=*/true); + EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Ty); } else if (!hasAggregateLLVMType(Init->getType())) { llvm::Value *V = EmitScalarExpr(Init); - EmitStoreOfScalar(V, Loc, D.getType().isVolatileQualified(), + EmitStoreOfScalar(V, Loc, D.getType().isVolatileQualified(), D.getType()); } else if (Init->getType()->isAnyComplexType()) { EmitComplexExprIntoAddr(Init, Loc, D.getType().isVolatileQualified()); @@ -354,10 +429,11 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { EmitAggExpr(Init, Loc, D.getType().isVolatileQualified()); } } + if (isByRef) { - const llvm::PointerType *PtrToInt8Ty - = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::PointerType *PtrToInt8Ty = llvm::Type::getInt8PtrTy(VMContext); + EnsureInsertPoint(); llvm::Value *isa_field = Builder.CreateStructGEP(DeclPtr, 0); llvm::Value *forwarding_field = Builder.CreateStructGEP(DeclPtr, 1); llvm::Value *flags_field = Builder.CreateStructGEP(DeclPtr, 2); @@ -383,19 +459,18 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { int isa = 0; if (flag&BLOCK_FIELD_IS_WEAK) isa = 1; - V = llvm::ConstantInt::get(llvm::Type::Int32Ty, isa); + V = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), isa); V = Builder.CreateIntToPtr(V, PtrToInt8Ty, "isa"); Builder.CreateStore(V, isa_field); - V = Builder.CreateBitCast(DeclPtr, PtrToInt8Ty, "forwarding"); - Builder.CreateStore(V, forwarding_field); + Builder.CreateStore(DeclPtr, forwarding_field); - V = llvm::ConstantInt::get(llvm::Type::Int32Ty, flags); + V = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), flags); Builder.CreateStore(V, flags_field); const llvm::Type *V1; V1 = cast(DeclPtr->getType())->getElementType(); - V = llvm::ConstantInt::get(llvm::Type::Int32Ty, + V = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), (CGM.getTargetData().getTypeStoreSizeInBits(V1) / 8)); Builder.CreateStore(V, size_field); @@ -413,13 +488,29 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { } } + // Handle CXX destruction of variables. + QualType DtorTy(Ty); + if (const ArrayType *Array = DtorTy->getAs()) + DtorTy = Array->getElementType(); + if (const RecordType *RT = DtorTy->getAs()) + if (CXXRecordDecl *ClassDecl = dyn_cast(RT->getDecl())) { + if (!ClassDecl->hasTrivialDestructor()) { + const CXXDestructorDecl *D = ClassDecl->getDestructor(getContext()); + assert(D && "EmitLocalBlockVarDecl - destructor is nul"); + assert(!Ty->getAs() && "FIXME - destruction of arrays NYI"); + + CleanupScope scope(*this); + EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + } + } + // Handle the cleanup attribute if (const CleanupAttr *CA = D.getAttr()) { const FunctionDecl *FD = CA->getFunctionDecl(); - - llvm::Constant* F = CGM.GetAddrOfFunction(GlobalDecl(FD)); + + llvm::Constant* F = CGM.GetAddrOfFunction(FD); assert(F && "Could not find function!"); - + CleanupScope scope(*this); const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD); @@ -428,15 +519,15 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { // the type of the pointer. An example of this is // void f(void* arg); // __attribute__((cleanup(f))) void *g; - // + // // To fix this we insert a bitcast here. QualType ArgTy = Info.arg_begin()->type; DeclPtr = Builder.CreateBitCast(DeclPtr, ConvertType(ArgTy)); - + CallArgList Args; - Args.push_back(std::make_pair(RValue::get(DeclPtr), + Args.push_back(std::make_pair(RValue::get(DeclPtr), getContext().getPointerType(D.getType()))); - + EmitCall(Info, F, Args); } @@ -448,14 +539,14 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { } } -/// Emit an alloca (or GlobalValue depending on target) +/// Emit an alloca (or GlobalValue depending on target) /// for the specified parameter and set up LocalDeclMap. void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) { // FIXME: Why isn't ImplicitParamDecl a ParmVarDecl? assert((isa(D) || isa(D)) && "Invalid argument to EmitParmDecl"); QualType Ty = D.getType(); - + llvm::Value *DeclPtr; if (!Ty->isConstantSizeType()) { // Variable sized values always are passed by-reference. @@ -469,7 +560,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) { Name += ".addr"; DeclPtr = CreateTempAlloca(LTy); DeclPtr->setName(Name.c_str()); - + // Store the initial value into the alloca. EmitStoreOfScalar(Arg, DeclPtr, Ty.isVolatileQualified(), Ty); } else { diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 0951019f0108..2834dfeb780a 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -46,33 +46,38 @@ llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) { /// EmitAnyExpr - Emit code to compute the specified expression which can have /// any type. The result is returned as an RValue struct. If this is an -/// aggregate expression, the aggloc/agglocvolatile arguments indicate where -/// the result should be returned. -RValue CodeGenFunction::EmitAnyExpr(const Expr *E, llvm::Value *AggLoc, - bool isAggLocVolatile, bool IgnoreResult) { +/// aggregate expression, the aggloc/agglocvolatile arguments indicate where the +/// result should be returned. +RValue CodeGenFunction::EmitAnyExpr(const Expr *E, llvm::Value *AggLoc, + bool IsAggLocVolatile, bool IgnoreResult, + bool IsInitializer) { if (!hasAggregateLLVMType(E->getType())) return RValue::get(EmitScalarExpr(E, IgnoreResult)); else if (E->getType()->isAnyComplexType()) return RValue::getComplex(EmitComplexExpr(E, false, false, IgnoreResult, IgnoreResult)); - - EmitAggExpr(E, AggLoc, isAggLocVolatile, IgnoreResult); - return RValue::getAggregate(AggLoc, isAggLocVolatile); + + EmitAggExpr(E, AggLoc, IsAggLocVolatile, IgnoreResult, IsInitializer); + return RValue::getAggregate(AggLoc, IsAggLocVolatile); } -/// EmitAnyExprToTemp - Similary to EmitAnyExpr(), however, the result -/// will always be accessible even if no aggregate location is -/// provided. -RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E, llvm::Value *AggLoc, - bool isAggLocVolatile) { - if (!AggLoc && hasAggregateLLVMType(E->getType()) && +/// EmitAnyExprToTemp - Similary to EmitAnyExpr(), however, the result will +/// always be accessible even if no aggregate location is provided. +RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E, + bool IsAggLocVolatile, + bool IsInitializer) { + llvm::Value *AggLoc = 0; + + if (hasAggregateLLVMType(E->getType()) && !E->getType()->isAnyComplexType()) AggLoc = CreateTempAlloca(ConvertType(E->getType()), "agg.tmp"); - return EmitAnyExpr(E, AggLoc, isAggLocVolatile); + return EmitAnyExpr(E, AggLoc, IsAggLocVolatile, /*IgnoreResult=*/false, + IsInitializer); } RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, - QualType DestType) { + QualType DestType, + bool IsInitializer) { RValue Val; if (E->isLvalue(getContext()) == Expr::LV_Valid) { // Emit the expr as an lvalue. @@ -81,14 +86,33 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, return RValue::get(LV.getAddress()); Val = EmitLoadOfLValue(LV, E->getType()); } else { - Val = EmitAnyExprToTemp(E); + // FIXME: Initializers don't work with casts yet. For example + // const A& a = B(); + // if B inherits from A. + Val = EmitAnyExprToTemp(E, /*IsAggLocVolatile=*/false, + IsInitializer); + + if (IsInitializer) { + // We might have to destroy the temporary variable. + if (const RecordType *RT = E->getType()->getAs()) { + if (CXXRecordDecl *ClassDecl = dyn_cast(RT->getDecl())) { + if (!ClassDecl->hasTrivialDestructor()) { + const CXXDestructorDecl *Dtor = + ClassDecl->getDestructor(getContext()); + + CleanupScope scope(*this); + EmitCXXDestructorCall(Dtor, Dtor_Complete, Val.getAggregateAddr()); + } + } + } + } } if (Val.isAggregate()) { Val = RValue::get(Val.getAggregateAddr()); } else { // Create a temporary variable that we can bind the reference to. - llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(E->getType()), + llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(E->getType()), "reftmp"); if (Val.isScalar()) EmitStoreOfScalar(Val.getScalarVal(), Temp, false, E->getType()); @@ -101,13 +125,13 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, } -/// getAccessedFieldNo - Given an encoded value and a result number, return -/// the input field number being accessed. -unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx, +/// getAccessedFieldNo - Given an encoded value and a result number, return the +/// input field number being accessed. +unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx, const llvm::Constant *Elts) { if (isa(Elts)) return 0; - + return cast(Elts->getOperand(Idx))->getZExtValue(); } @@ -119,7 +143,7 @@ unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx, RValue CodeGenFunction::GetUndefRValue(QualType Ty) { if (Ty->isVoidType()) { return RValue::get(0); - } else if (const ComplexType *CTy = Ty->getAsComplexType()) { + } else if (const ComplexType *CTy = Ty->getAs()) { const llvm::Type *EltTy = ConvertType(CTy->getElementType()); llvm::Value *U = llvm::UndefValue::get(EltTy); return RValue::getComplex(std::make_pair(U, U)); @@ -142,38 +166,37 @@ LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E, ErrorUnsupported(E, Name); llvm::Type *Ty = llvm::PointerType::getUnqual(ConvertType(E->getType())); return LValue::MakeAddr(llvm::UndefValue::get(Ty), - E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType())); + MakeQualifiers(E->getType())); } /// EmitLValue - Emit code to compute a designator that specifies the location /// of the expression. /// -/// This can return one of two things: a simple address or a bitfield -/// reference. In either case, the LLVM Value* in the LValue structure is -/// guaranteed to be an LLVM pointer type. +/// This can return one of two things: a simple address or a bitfield reference. +/// In either case, the LLVM Value* in the LValue structure is guaranteed to be +/// an LLVM pointer type. /// -/// If this returns a bitfield reference, nothing about the pointee type of -/// the LLVM value is known: For example, it may not be a pointer to an -/// integer. +/// If this returns a bitfield reference, nothing about the pointee type of the +/// LLVM value is known: For example, it may not be a pointer to an integer. /// -/// If this returns a normal address, and if the lvalue's C type is fixed -/// size, this method guarantees that the returned pointer type will point to -/// an LLVM type of the same size of the lvalue's type. If the lvalue has a -/// variable length type, this is not possible. +/// If this returns a normal address, and if the lvalue's C type is fixed size, +/// this method guarantees that the returned pointer type will point to an LLVM +/// type of the same size of the lvalue's type. If the lvalue has a variable +/// length type, this is not possible. /// LValue CodeGenFunction::EmitLValue(const Expr *E) { switch (E->getStmtClass()) { default: return EmitUnsupportedLValue(E, "l-value expression"); - case Expr::BinaryOperatorClass: + case Expr::BinaryOperatorClass: return EmitBinaryOperatorLValue(cast(E)); - case Expr::CallExprClass: + case Expr::CallExprClass: + case Expr::CXXMemberCallExprClass: case Expr::CXXOperatorCallExprClass: return EmitCallExprLValue(cast(E)); case Expr::VAArgExprClass: return EmitVAArgExprLValue(cast(E)); - case Expr::DeclRefExprClass: + case Expr::DeclRefExprClass: case Expr::QualifiedDeclRefExprClass: return EmitDeclRefLValue(cast(E)); case Expr::ParenExprClass:return EmitLValue(cast(E)->getSubExpr()); @@ -184,7 +207,7 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { case Expr::ObjCEncodeExprClass: return EmitObjCEncodeExprLValue(cast(E)); - case Expr::BlockDeclRefExprClass: + case Expr::BlockDeclRefExprClass: return EmitBlockDeclRefLValue(cast(E)); case Expr::CXXConditionDeclExprClass: @@ -194,31 +217,34 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitCXXConstructLValue(cast(E)); case Expr::CXXBindTemporaryExprClass: return EmitCXXBindTemporaryLValue(cast(E)); + case Expr::CXXExprWithTemporariesClass: + return EmitCXXExprWithTemporariesLValue(cast(E)); case Expr::ObjCMessageExprClass: return EmitObjCMessageExprLValue(cast(E)); - case Expr::ObjCIvarRefExprClass: + case Expr::ObjCIvarRefExprClass: return EmitObjCIvarRefLValue(cast(E)); case Expr::ObjCPropertyRefExprClass: return EmitObjCPropertyRefLValue(cast(E)); - case Expr::ObjCKVCRefExprClass: - return EmitObjCKVCRefLValue(cast(E)); + case Expr::ObjCImplicitSetterGetterRefExprClass: + return EmitObjCKVCRefLValue(cast(E)); case Expr::ObjCSuperExprClass: return EmitObjCSuperExprLValue(cast(E)); case Expr::StmtExprClass: return EmitStmtExprLValue(cast(E)); - case Expr::UnaryOperatorClass: + case Expr::UnaryOperatorClass: return EmitUnaryOpLValue(cast(E)); case Expr::ArraySubscriptExprClass: return EmitArraySubscriptExpr(cast(E)); case Expr::ExtVectorElementExprClass: return EmitExtVectorElementExpr(cast(E)); - case Expr::MemberExprClass: return EmitMemberExpr(cast(E)); + case Expr::MemberExprClass: + return EmitMemberExpr(cast(E)); case Expr::CompoundLiteralExprClass: return EmitCompoundLiteralLValue(cast(E)); case Expr::ConditionalOperatorClass: - return EmitConditionalOperator(cast(E)); + return EmitConditionalOperatorLValue(cast(E)); case Expr::ChooseExprClass: return EmitLValue(cast(E)->getChosenSubExpr(getContext())); case Expr::ImplicitCastExprClass: @@ -238,55 +264,54 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile, // Bool can have different representation in memory than in registers. if (Ty->isBooleanType()) - if (V->getType() != llvm::Type::Int1Ty) - V = Builder.CreateTrunc(V, llvm::Type::Int1Ty, "tobool"); - + if (V->getType() != llvm::Type::getInt1Ty(VMContext)) + V = Builder.CreateTrunc(V, llvm::Type::getInt1Ty(VMContext), "tobool"); + return V; } void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr, bool Volatile, QualType Ty) { - + if (Ty->isBooleanType()) { // Bool can have different representation in memory than in registers. const llvm::Type *SrcTy = Value->getType(); const llvm::PointerType *DstPtr = cast(Addr->getType()); if (DstPtr->getElementType() != SrcTy) { - const llvm::Type *MemTy = + const llvm::Type *MemTy = llvm::PointerType::get(SrcTy, DstPtr->getAddressSpace()); Addr = Builder.CreateBitCast(Addr, MemTy, "storetmp"); } } - - Builder.CreateStore(Value, Addr, Volatile); + Builder.CreateStore(Value, Addr, Volatile); } -/// EmitLoadOfLValue - Given an expression that represents a value lvalue, -/// this method emits the address of the lvalue, then loads the result as an -/// rvalue, returning the rvalue. +/// EmitLoadOfLValue - Given an expression that represents a value lvalue, this +/// method emits the address of the lvalue, then loads the result as an rvalue, +/// returning the rvalue. RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) { if (LV.isObjCWeak()) { - // load of a __weak object. + // load of a __weak object. llvm::Value *AddrWeakObj = LV.getAddress(); - llvm::Value *read_weak = CGM.getObjCRuntime().EmitObjCWeakRead(*this, + llvm::Value *read_weak = CGM.getObjCRuntime().EmitObjCWeakRead(*this, AddrWeakObj); return RValue::get(read_weak); } - + if (LV.isSimple()) { llvm::Value *Ptr = LV.getAddress(); const llvm::Type *EltTy = cast(Ptr->getType())->getElementType(); - + // Simple scalar l-value. if (EltTy->isSingleValueType()) - return RValue::get(EmitLoadOfScalar(Ptr, LV.isVolatileQualified(), + return RValue::get(EmitLoadOfScalar(Ptr, LV.isVolatileQualified(), ExprType)); - + assert(ExprType->isFunctionType() && "Unknown scalar value"); return RValue::get(Ptr); } - + if (LV.isVectorElt()) { llvm::Value *Vec = Builder.CreateLoad(LV.getVectorAddr(), LV.isVolatileQualified(), "tmp"); @@ -315,59 +340,58 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV, unsigned BitfieldSize = LV.getBitfieldSize(); llvm::Value *Ptr = LV.getBitfieldAddr(); - const llvm::Type *EltTy = + const llvm::Type *EltTy = cast(Ptr->getType())->getElementType(); unsigned EltTySize = CGM.getTargetData().getTypeSizeInBits(EltTy); - // In some cases the bitfield may straddle two memory locations. - // Currently we load the entire bitfield, then do the magic to - // sign-extend it if necessary. This results in somewhat more code - // than necessary for the common case (one load), since two shifts - // accomplish both the masking and sign extension. + // In some cases the bitfield may straddle two memory locations. Currently we + // load the entire bitfield, then do the magic to sign-extend it if + // necessary. This results in somewhat more code than necessary for the common + // case (one load), since two shifts accomplish both the masking and sign + // extension. unsigned LowBits = std::min(BitfieldSize, EltTySize - StartBit); llvm::Value *Val = Builder.CreateLoad(Ptr, LV.isVolatileQualified(), "tmp"); - + // Shift to proper location. if (StartBit) - Val = Builder.CreateLShr(Val, llvm::ConstantInt::get(EltTy, StartBit), + Val = Builder.CreateLShr(Val, llvm::ConstantInt::get(EltTy, StartBit), "bf.lo"); - + // Mask off unused bits. - llvm::Constant *LowMask = - llvm::ConstantInt::get(llvm::APInt::getLowBitsSet(EltTySize, LowBits)); + llvm::Constant *LowMask = llvm::ConstantInt::get(VMContext, + llvm::APInt::getLowBitsSet(EltTySize, LowBits)); Val = Builder.CreateAnd(Val, LowMask, "bf.lo.cleared"); - + // Fetch the high bits if necessary. if (LowBits < BitfieldSize) { unsigned HighBits = BitfieldSize - LowBits; - llvm::Value *HighPtr = - Builder.CreateGEP(Ptr, llvm::ConstantInt::get(llvm::Type::Int32Ty, 1), - "bf.ptr.hi"); - llvm::Value *HighVal = Builder.CreateLoad(HighPtr, + llvm::Value *HighPtr = Builder.CreateGEP(Ptr, llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), 1), "bf.ptr.hi"); + llvm::Value *HighVal = Builder.CreateLoad(HighPtr, LV.isVolatileQualified(), "tmp"); - + // Mask off unused bits. - llvm::Constant *HighMask = - llvm::ConstantInt::get(llvm::APInt::getLowBitsSet(EltTySize, HighBits)); + llvm::Constant *HighMask = llvm::ConstantInt::get(VMContext, + llvm::APInt::getLowBitsSet(EltTySize, HighBits)); HighVal = Builder.CreateAnd(HighVal, HighMask, "bf.lo.cleared"); // Shift to proper location and or in to bitfield value. - HighVal = Builder.CreateShl(HighVal, + HighVal = Builder.CreateShl(HighVal, llvm::ConstantInt::get(EltTy, LowBits)); Val = Builder.CreateOr(Val, HighVal, "bf.val"); } // Sign extend if necessary. if (LV.isBitfieldSigned()) { - llvm::Value *ExtraBits = llvm::ConstantInt::get(EltTy, + llvm::Value *ExtraBits = llvm::ConstantInt::get(EltTy, EltTySize - BitfieldSize); - Val = Builder.CreateAShr(Builder.CreateShl(Val, ExtraBits), + Val = Builder.CreateAShr(Builder.CreateShl(Val, ExtraBits), ExtraBits, "bf.val.sext"); } - // The bitfield type and the normal type differ when the storage sizes - // differ (currently just _Bool). + // The bitfield type and the normal type differ when the storage sizes differ + // (currently just _Bool). Val = Builder.CreateIntCast(Val, ConvertType(ExprType), false, "tmp"); return RValue::get(Val); @@ -389,27 +413,29 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV, QualType ExprType) { llvm::Value *Vec = Builder.CreateLoad(LV.getExtVectorAddr(), LV.isVolatileQualified(), "tmp"); - + const llvm::Constant *Elts = LV.getExtVectorElts(); - - // If the result of the expression is a non-vector type, we must be - // extracting a single element. Just codegen as an extractelement. - const VectorType *ExprVT = ExprType->getAsVectorType(); + + // If the result of the expression is a non-vector type, we must be extracting + // a single element. Just codegen as an extractelement. + const VectorType *ExprVT = ExprType->getAs(); if (!ExprVT) { unsigned InIdx = getAccessedFieldNo(0, Elts); - llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx); + llvm::Value *Elt = llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), InIdx); return RValue::get(Builder.CreateExtractElement(Vec, Elt, "tmp")); } // Always use shuffle vector to try to retain the original program structure unsigned NumResultElts = ExprVT->getNumElements(); - + llvm::SmallVector Mask; for (unsigned i = 0; i != NumResultElts; ++i) { unsigned InIdx = getAccessedFieldNo(i, Elts); - Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx)); + Mask.push_back(llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), InIdx)); } - + llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size()); Vec = Builder.CreateShuffleVector(Vec, llvm::UndefValue::get(Vec->getType()), @@ -422,7 +448,7 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV, /// EmitStoreThroughLValue - Store the specified rvalue into the specified /// lvalue, where both are guaranteed to the have the same type, and that type /// is 'Ty'. -void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, +void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, QualType Ty) { if (!Dst.isSimple()) { if (Dst.isVectorElt()) { @@ -434,7 +460,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, Builder.CreateStore(Vec, Dst.getVectorAddr(),Dst.isVolatileQualified()); return; } - + // If this is an update of extended vector elements, insert them as // appropriate. if (Dst.isExtVectorElt()) @@ -451,58 +477,60 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, assert(0 && "Unknown LValue type"); } - + if (Dst.isObjCWeak() && !Dst.isNonGC()) { - // load of a __weak object. + // load of a __weak object. llvm::Value *LvalueDst = Dst.getAddress(); llvm::Value *src = Src.getScalarVal(); CGM.getObjCRuntime().EmitObjCWeakAssign(*this, src, LvalueDst); return; } - + if (Dst.isObjCStrong() && !Dst.isNonGC()) { - // load of a __strong object. + // load of a __strong object. llvm::Value *LvalueDst = Dst.getAddress(); llvm::Value *src = Src.getScalarVal(); -#if 0 - // FIXME. We cannot positively determine if we have an 'ivar' assignment, - // object assignment or an unknown assignment. For now, generate call to - // objc_assign_strongCast assignment which is a safe, but consevative - // assumption. - if (Dst.isObjCIvar()) - CGM.getObjCRuntime().EmitObjCIvarAssign(*this, src, LvalueDst); - else - CGM.getObjCRuntime().EmitObjCGlobalAssign(*this, src, LvalueDst); -#endif - if (Dst.isGlobalObjCRef()) + if (Dst.isObjCIvar()) { + assert(Dst.getBaseIvarExp() && "BaseIvarExp is NULL"); + const llvm::Type *ResultType = ConvertType(getContext().LongTy); + llvm::Value *RHS = EmitScalarExpr(Dst.getBaseIvarExp()); + llvm::Value *dst = RHS; + RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast"); + llvm::Value *LHS = + Builder.CreatePtrToInt(LvalueDst, ResultType, "sub.ptr.lhs.cast"); + llvm::Value *BytesBetween = Builder.CreateSub(LHS, RHS, "ivar.offset"); + CGM.getObjCRuntime().EmitObjCIvarAssign(*this, src, dst, + BytesBetween); + } + else if (Dst.isGlobalObjCRef()) CGM.getObjCRuntime().EmitObjCGlobalAssign(*this, src, LvalueDst); else CGM.getObjCRuntime().EmitObjCStrongCastAssign(*this, src, LvalueDst); return; } - + assert(Src.isScalar() && "Can't emit an agg store with this method"); EmitStoreOfScalar(Src.getScalarVal(), Dst.getAddress(), Dst.isVolatileQualified(), Ty); } void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, - QualType Ty, + QualType Ty, llvm::Value **Result) { unsigned StartBit = Dst.getBitfieldStartBit(); unsigned BitfieldSize = Dst.getBitfieldSize(); llvm::Value *Ptr = Dst.getBitfieldAddr(); - const llvm::Type *EltTy = + const llvm::Type *EltTy = cast(Ptr->getType())->getElementType(); unsigned EltTySize = CGM.getTargetData().getTypeSizeInBits(EltTy); - // Get the new value, cast to the appropriate type and masked to - // exactly the size of the bit-field. + // Get the new value, cast to the appropriate type and masked to exactly the + // size of the bit-field. llvm::Value *SrcVal = Src.getScalarVal(); llvm::Value *NewVal = Builder.CreateIntCast(SrcVal, EltTy, false, "tmp"); - llvm::Constant *Mask = - llvm::ConstantInt::get(llvm::APInt::getLowBitsSet(EltTySize, BitfieldSize)); + llvm::Constant *Mask = llvm::ConstantInt::get(VMContext, + llvm::APInt::getLowBitsSet(EltTySize, BitfieldSize)); NewVal = Builder.CreateAnd(NewVal, Mask, "bf.value"); // Return the new value of the bit-field, if requested. @@ -517,61 +545,60 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, unsigned SrcTySize = CGM.getTargetData().getTypeSizeInBits(SrcTy); llvm::Value *ExtraBits = llvm::ConstantInt::get(SrcTy, SrcTySize - BitfieldSize); - SrcTrunc = Builder.CreateAShr(Builder.CreateShl(SrcTrunc, ExtraBits), + SrcTrunc = Builder.CreateAShr(Builder.CreateShl(SrcTrunc, ExtraBits), ExtraBits, "bf.reload.sext"); } *Result = SrcTrunc; } - // In some cases the bitfield may straddle two memory locations. - // Emit the low part first and check to see if the high needs to be - // done. + // In some cases the bitfield may straddle two memory locations. Emit the low + // part first and check to see if the high needs to be done. unsigned LowBits = std::min(BitfieldSize, EltTySize - StartBit); llvm::Value *LowVal = Builder.CreateLoad(Ptr, Dst.isVolatileQualified(), "bf.prev.low"); // Compute the mask for zero-ing the low part of this bitfield. - llvm::Constant *InvMask = - llvm::ConstantInt::get(~llvm::APInt::getBitsSet(EltTySize, StartBit, - StartBit + LowBits)); - + llvm::Constant *InvMask = + llvm::ConstantInt::get(VMContext, + ~llvm::APInt::getBitsSet(EltTySize, StartBit, StartBit + LowBits)); + // Compute the new low part as // LowVal = (LowVal & InvMask) | (NewVal << StartBit), // with the shift of NewVal implicitly stripping the high bits. - llvm::Value *NewLowVal = - Builder.CreateShl(NewVal, llvm::ConstantInt::get(EltTy, StartBit), - "bf.value.lo"); + llvm::Value *NewLowVal = + Builder.CreateShl(NewVal, llvm::ConstantInt::get(EltTy, StartBit), + "bf.value.lo"); LowVal = Builder.CreateAnd(LowVal, InvMask, "bf.prev.lo.cleared"); LowVal = Builder.CreateOr(LowVal, NewLowVal, "bf.new.lo"); - + // Write back. Builder.CreateStore(LowVal, Ptr, Dst.isVolatileQualified()); // If the low part doesn't cover the bitfield emit a high part. if (LowBits < BitfieldSize) { unsigned HighBits = BitfieldSize - LowBits; - llvm::Value *HighPtr = - Builder.CreateGEP(Ptr, llvm::ConstantInt::get(llvm::Type::Int32Ty, 1), - "bf.ptr.hi"); - llvm::Value *HighVal = Builder.CreateLoad(HighPtr, + llvm::Value *HighPtr = Builder.CreateGEP(Ptr, llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), 1), "bf.ptr.hi"); + llvm::Value *HighVal = Builder.CreateLoad(HighPtr, Dst.isVolatileQualified(), "bf.prev.hi"); - + // Compute the mask for zero-ing the high part of this bitfield. - llvm::Constant *InvMask = - llvm::ConstantInt::get(~llvm::APInt::getLowBitsSet(EltTySize, HighBits)); - + llvm::Constant *InvMask = + llvm::ConstantInt::get(VMContext, ~llvm::APInt::getLowBitsSet(EltTySize, + HighBits)); + // Compute the new high part as // HighVal = (HighVal & InvMask) | (NewVal lshr LowBits), // where the high bits of NewVal have already been cleared and the // shift stripping the low bits. - llvm::Value *NewHighVal = - Builder.CreateLShr(NewVal, llvm::ConstantInt::get(EltTy, LowBits), - "bf.value.high"); + llvm::Value *NewHighVal = + Builder.CreateLShr(NewVal, llvm::ConstantInt::get(EltTy, LowBits), + "bf.value.high"); HighVal = Builder.CreateAnd(HighVal, InvMask, "bf.prev.hi.cleared"); HighVal = Builder.CreateOr(HighVal, NewHighVal, "bf.new.hi"); - + // Write back. Builder.CreateStore(HighVal, HighPtr, Dst.isVolatileQualified()); } @@ -597,29 +624,29 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, llvm::Value *Vec = Builder.CreateLoad(Dst.getExtVectorAddr(), Dst.isVolatileQualified(), "tmp"); const llvm::Constant *Elts = Dst.getExtVectorElts(); - + llvm::Value *SrcVal = Src.getScalarVal(); - - if (const VectorType *VTy = Ty->getAsVectorType()) { + + if (const VectorType *VTy = Ty->getAs()) { unsigned NumSrcElts = VTy->getNumElements(); unsigned NumDstElts = cast(Vec->getType())->getNumElements(); if (NumDstElts == NumSrcElts) { - // Use shuffle vector is the src and destination are the same number - // of elements and restore the vector mask since it is on the side - // it will be stored. + // Use shuffle vector is the src and destination are the same number of + // elements and restore the vector mask since it is on the side it will be + // stored. llvm::SmallVector Mask(NumDstElts); for (unsigned i = 0; i != NumSrcElts; ++i) { unsigned InIdx = getAccessedFieldNo(i, Elts); - Mask[InIdx] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); + Mask[InIdx] = llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), i); } - + llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size()); Vec = Builder.CreateShuffleVector(SrcVal, llvm::UndefValue::get(Vec->getType()), MaskV, "tmp"); - } - else if (NumDstElts > NumSrcElts) { + } else if (NumDstElts > NumSrcElts) { // Extended the source vector to the same length and then shuffle it // into the destination. // FIXME: since we're shuffling with undef, can we just use the indices @@ -627,96 +654,153 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, llvm::SmallVector ExtMask; unsigned i; for (i = 0; i != NumSrcElts; ++i) - ExtMask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, i)); + ExtMask.push_back(llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), i)); for (; i != NumDstElts; ++i) - ExtMask.push_back(llvm::UndefValue::get(llvm::Type::Int32Ty)); + ExtMask.push_back(llvm::UndefValue::get( + llvm::Type::getInt32Ty(VMContext))); llvm::Value *ExtMaskV = llvm::ConstantVector::get(&ExtMask[0], ExtMask.size()); - llvm::Value *ExtSrcVal = + llvm::Value *ExtSrcVal = Builder.CreateShuffleVector(SrcVal, llvm::UndefValue::get(SrcVal->getType()), ExtMaskV, "tmp"); // build identity llvm::SmallVector Mask; for (unsigned i = 0; i != NumDstElts; ++i) { - Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, i)); + Mask.push_back(llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), i)); } // modify when what gets shuffled in for (unsigned i = 0; i != NumSrcElts; ++i) { unsigned Idx = getAccessedFieldNo(i, Elts); - Mask[Idx] =llvm::ConstantInt::get(llvm::Type::Int32Ty, i+NumDstElts); + Mask[Idx] = llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), i+NumDstElts); } llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size()); Vec = Builder.CreateShuffleVector(Vec, ExtSrcVal, MaskV, "tmp"); - } - else { + } else { // We should never shorten the vector assert(0 && "unexpected shorten vector length"); } } else { // If the Src is a scalar (not a vector) it must be updating one element. unsigned InIdx = getAccessedFieldNo(0, Elts); - llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx); + llvm::Value *Elt = llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), InIdx); Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt, "tmp"); } - + Builder.CreateStore(Vec, Dst.getExtVectorAddr(), Dst.isVolatileQualified()); } +// setObjCGCLValueClass - sets class of he lvalue for the purpose of +// generating write-barries API. It is currently a global, ivar, +// or neither. +static +void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, LValue &LV) { + if (Ctx.getLangOptions().getGCMode() == LangOptions::NonGC) + return; + + if (isa(E)) { + LV.SetObjCIvar(LV, true); + ObjCIvarRefExpr *Exp = cast(const_cast(E)); + LV.setBaseIvarExp(Exp->getBase()); + LV.SetObjCArray(LV, E->getType()->isArrayType()); + return; + } + if (const DeclRefExpr *Exp = dyn_cast(E)) { + if (const VarDecl *VD = dyn_cast(Exp->getDecl())) { + if ((VD->isBlockVarDecl() && !VD->hasLocalStorage()) || + VD->isFileVarDecl()) + LV.SetGlobalObjCRef(LV, true); + } + LV.SetObjCArray(LV, E->getType()->isArrayType()); + } + else if (const UnaryOperator *Exp = dyn_cast(E)) + setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); + else if (const ParenExpr *Exp = dyn_cast(E)) { + setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); + if (LV.isObjCIvar()) { + // If cast is to a structure pointer, follow gcc's behavior and make it + // a non-ivar write-barrier. + QualType ExpTy = E->getType(); + if (ExpTy->isPointerType()) + ExpTy = ExpTy->getAs()->getPointeeType(); + if (ExpTy->isRecordType()) + LV.SetObjCIvar(LV, false); + } + } + else if (const ImplicitCastExpr *Exp = dyn_cast(E)) + setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); + else if (const CStyleCastExpr *Exp = dyn_cast(E)) + setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); + else if (const ArraySubscriptExpr *Exp = dyn_cast(E)) { + setObjCGCLValueClass(Ctx, Exp->getBase(), LV); + if (LV.isObjCIvar() && !LV.isObjCArray()) + // Using array syntax to assigning to what an ivar points to is not + // same as assigning to the ivar itself. {id *Names;} Names[i] = 0; + LV.SetObjCIvar(LV, false); + else if (LV.isGlobalObjCRef() && !LV.isObjCArray()) + // Using array syntax to assigning to what global points to is not + // same as assigning to the global itself. {id *G;} G[i] = 0; + LV.SetGlobalObjCRef(LV, false); + } + else if (const MemberExpr *Exp = dyn_cast(E)) { + setObjCGCLValueClass(Ctx, Exp->getBase(), LV); + // We don't know if member is an 'ivar', but this flag is looked at + // only in the context of LV.isObjCIvar(). + LV.SetObjCArray(LV, E->getType()->isArrayType()); + } +} + LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { const VarDecl *VD = dyn_cast(E->getDecl()); - + if (VD && (VD->isBlockVarDecl() || isa(VD) || isa(VD))) { LValue LV; - bool NonGCable = VD->hasLocalStorage() && + bool NonGCable = VD->hasLocalStorage() && !VD->hasAttr(); if (VD->hasExternalStorage()) { llvm::Value *V = CGM.GetAddrOfGlobalVar(VD); if (VD->getType()->isReferenceType()) V = Builder.CreateLoad(V, "tmp"); - LV = LValue::MakeAddr(V, E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType())); - } - else { + LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); + } else { llvm::Value *V = LocalDeclMap[VD]; assert(V && "DeclRefExpr not entered in LocalDeclMap?"); + + Qualifiers Quals = MakeQualifiers(E->getType()); // local variables do not get their gc attribute set. - QualType::GCAttrTypes attr = QualType::GCNone; // local static? - if (!NonGCable) - attr = getContext().getObjCGCAttrKind(E->getType()); + if (NonGCable) Quals.removeObjCGCAttr(); + if (VD->hasAttr()) { - bool needsCopyDispose = BlockRequiresCopying(VD->getType()); - const llvm::Type *PtrStructTy = V->getType(); - const llvm::Type *Ty = PtrStructTy; - Ty = llvm::PointerType::get(Ty, 0); V = Builder.CreateStructGEP(V, 1, "forwarding"); - V = Builder.CreateBitCast(V, Ty); V = Builder.CreateLoad(V, false); - V = Builder.CreateBitCast(V, PtrStructTy); - V = Builder.CreateStructGEP(V, needsCopyDispose*2 + 4, "x"); + V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD), + VD->getNameAsString()); } if (VD->getType()->isReferenceType()) V = Builder.CreateLoad(V, "tmp"); - LV = LValue::MakeAddr(V, E->getType().getCVRQualifiers(), attr); + LV = LValue::MakeAddr(V, Quals); } LValue::SetObjCNonGC(LV, NonGCable); + setObjCGCLValueClass(getContext(), E, LV); return LV; } else if (VD && VD->isFileVarDecl()) { llvm::Value *V = CGM.GetAddrOfGlobalVar(VD); if (VD->getType()->isReferenceType()) V = Builder.CreateLoad(V, "tmp"); - LValue LV = LValue::MakeAddr(V, E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType())); - if (LV.isObjCStrong()) - LV.SetGlobalObjCRef(LV, true); + LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); + setObjCGCLValueClass(getContext(), E, LV); return LV; } else if (const FunctionDecl *FD = dyn_cast(E->getDecl())) { - llvm::Value* V = CGM.GetAddrOfFunction(GlobalDecl(FD)); + llvm::Value* V = CGM.GetAddrOfFunction(FD); if (!FD->hasPrototype()) { if (const FunctionProtoType *Proto = - FD->getType()->getAsFunctionProtoType()) { + FD->getType()->getAs()) { // Ugly case: for a K&R-style definition, the type of the definition // isn't the same as the type of a use. Correct for this with a // bitcast. @@ -726,15 +810,12 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { V = Builder.CreateBitCast(V, ConvertType(NoProtoType), "tmp"); } } - return LValue::MakeAddr(V, E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType())); - } - else if (const ImplicitParamDecl *IPD = + return LValue::MakeAddr(V, MakeQualifiers(E->getType())); + } else if (const ImplicitParamDecl *IPD = dyn_cast(E->getDecl())) { llvm::Value *V = LocalDeclMap[IPD]; assert(V && "BlockVarDecl not entered in LocalDeclMap?"); - return LValue::MakeAddr(V, E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType())); + return LValue::MakeAddr(V, MakeQualifiers(E->getType())); } assert(0 && "Unimp declref"); //an invalid LValue, but the assert will @@ -743,27 +824,26 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { } LValue CodeGenFunction::EmitBlockDeclRefLValue(const BlockDeclRefExpr *E) { - return LValue::MakeAddr(GetAddrOfBlockDecl(E), - E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType())); + return LValue::MakeAddr(GetAddrOfBlockDecl(E), MakeQualifiers(E->getType())); } LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { // __extension__ doesn't affect lvalue-ness. if (E->getOpcode() == UnaryOperator::Extension) return EmitLValue(E->getSubExpr()); - + QualType ExprTy = getContext().getCanonicalType(E->getSubExpr()->getType()); switch (E->getOpcode()) { default: assert(0 && "Unknown unary operator lvalue!"); case UnaryOperator::Deref: { - QualType T = - E->getSubExpr()->getType()->getAsPointerType()->getPointeeType(); - LValue LV = LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()), - ExprTy->getAsPointerType()->getPointeeType() - .getCVRQualifiers(), - getContext().getObjCGCAttrKind(T)); + QualType T = E->getSubExpr()->getType()->getPointeeType(); + assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type"); + + Qualifiers Quals = MakeQualifiers(T); + Quals.setAddressSpace(ExprTy.getAddressSpace()); + + LValue LV = LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()), Quals); // We should not generate __weak write barrier on indirect reference // of a pointer to object; as in void foo (__weak id *param); *param = 0; // But, we continue to generate __strong write barrier on indirect write @@ -780,16 +860,18 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { unsigned Idx = E->getOpcode() == UnaryOperator::Imag; return LValue::MakeAddr(Builder.CreateStructGEP(LV.getAddress(), Idx, "idx"), - ExprTy.getCVRQualifiers()); + MakeQualifiers(ExprTy)); } } LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) { - return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromLiteral(E), 0); + return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromLiteral(E), + Qualifiers()); } LValue CodeGenFunction::EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E) { - return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromObjCEncode(E), 0); + return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromObjCEncode(E), + Qualifiers()); } @@ -806,32 +888,25 @@ LValue CodeGenFunction::EmitPredefinedFunctionName(unsigned Type) { GlobalVarName = "__FUNCTION__."; break; case PredefinedExpr::PrettyFunction: - // FIXME:: Demangle C++ method names GlobalVarName = "__PRETTY_FUNCTION__."; break; } - // FIXME: This isn't right at all. The logic for computing this should go - // into a method on PredefinedExpr. This would allow sema and codegen to be - // consistent for things like sizeof(__func__) etc. - std::string FunctionName; - if (const FunctionDecl *FD = dyn_cast_or_null(CurCodeDecl)) { - FunctionName = CGM.getMangledName(FD); - } else { - // Just get the mangled name; skipping the asm prefix if it - // exists. - FunctionName = CurFn->getName(); - if (FunctionName[0] == '\01') - FunctionName = FunctionName.substr(1, std::string::npos); - } + llvm::StringRef FnName = CurFn->getName(); + if (FnName.startswith("\01")) + FnName = FnName.substr(1); + GlobalVarName += FnName; - GlobalVarName += FunctionName; - llvm::Constant *C = + std::string FunctionName = + PredefinedExpr::ComputeName(getContext(), (PredefinedExpr::IdentType)Type, + CurCodeDecl); + + llvm::Constant *C = CGM.GetAddrOfConstantCString(FunctionName, GlobalVarName.c_str()); - return LValue::MakeAddr(C, 0); + return LValue::MakeAddr(C, Qualifiers()); } -LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) { +LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) { switch (E->getIdentType()) { default: return EmitUnsupportedLValue(E, "predefined expression"); @@ -854,68 +929,78 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { // Emit the vector as an lvalue to get its address. LValue LHS = EmitLValue(E->getBase()); assert(LHS.isSimple() && "Can only subscript lvalue vectors here!"); - Idx = Builder.CreateIntCast(Idx, llvm::Type::Int32Ty, IdxSigned, "vidx"); + Idx = Builder.CreateIntCast(Idx, + llvm::Type::getInt32Ty(VMContext), IdxSigned, "vidx"); return LValue::MakeVectorElt(LHS.getAddress(), Idx, - E->getBase()->getType().getCVRQualifiers()); + E->getBase()->getType().getCVRQualifiers()); } - + // The base must be a pointer, which is not an aggregate. Emit it. llvm::Value *Base = EmitScalarExpr(E->getBase()); - + // Extend or truncate the index type to 32 or 64-bits. unsigned IdxBitwidth = cast(Idx->getType())->getBitWidth(); if (IdxBitwidth != LLVMPointerWidth) - Idx = Builder.CreateIntCast(Idx, llvm::IntegerType::get(LLVMPointerWidth), + Idx = Builder.CreateIntCast(Idx, + llvm::IntegerType::get(VMContext, LLVMPointerWidth), IdxSigned, "idxprom"); - // We know that the pointer points to a type of the correct size, - // unless the size is a VLA or Objective-C interface. + // We know that the pointer points to a type of the correct size, unless the + // size is a VLA or Objective-C interface. llvm::Value *Address = 0; - if (const VariableArrayType *VAT = + if (const VariableArrayType *VAT = getContext().getAsVariableArrayType(E->getType())) { - llvm::Value *VLASize = VLASizeMap[VAT]; - + llvm::Value *VLASize = GetVLASize(VAT); + Idx = Builder.CreateMul(Idx, VLASize); - + QualType BaseType = getContext().getBaseElementType(VAT); - + uint64_t BaseTypeSize = getContext().getTypeSize(BaseType) / 8; Idx = Builder.CreateUDiv(Idx, - llvm::ConstantInt::get(Idx->getType(), + llvm::ConstantInt::get(Idx->getType(), BaseTypeSize)); - Address = Builder.CreateGEP(Base, Idx, "arrayidx"); - } else if (const ObjCInterfaceType *OIT = + Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx"); + } else if (const ObjCInterfaceType *OIT = dyn_cast(E->getType())) { - llvm::Value *InterfaceSize = + llvm::Value *InterfaceSize = llvm::ConstantInt::get(Idx->getType(), getContext().getTypeSize(OIT) / 8); - + Idx = Builder.CreateMul(Idx, InterfaceSize); - llvm::Type *i8PTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); - Address = Builder.CreateGEP(Builder.CreateBitCast(Base, i8PTy), + const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext); + Address = Builder.CreateGEP(Builder.CreateBitCast(Base, i8PTy), Idx, "arrayidx"); Address = Builder.CreateBitCast(Address, Base->getType()); } else { - Address = Builder.CreateGEP(Base, Idx, "arrayidx"); + Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx"); } - - QualType T = E->getBase()->getType()->getAsPointerType()->getPointeeType(); - LValue LV = LValue::MakeAddr(Address, - T.getCVRQualifiers(), - getContext().getObjCGCAttrKind(T)); + + QualType T = E->getBase()->getType()->getPointeeType(); + assert(!T.isNull() && + "CodeGenFunction::EmitArraySubscriptExpr(): Illegal base type"); + + Qualifiers Quals = MakeQualifiers(T); + Quals.setAddressSpace(E->getBase()->getType().getAddressSpace()); + + LValue LV = LValue::MakeAddr(Address, Quals); if (getContext().getLangOptions().ObjC1 && - getContext().getLangOptions().getGCMode() != LangOptions::NonGC) + getContext().getLangOptions().getGCMode() != LangOptions::NonGC) { LValue::SetObjCNonGC(LV, !E->isOBJCGCCandidate(getContext())); + setObjCGCLValueClass(getContext(), E, LV); + } return LV; } -static -llvm::Constant *GenerateConstantVector(llvm::SmallVector &Elts) { +static +llvm::Constant *GenerateConstantVector(llvm::LLVMContext &VMContext, + llvm::SmallVector &Elts) { llvm::SmallVector CElts; - + for (unsigned i = 0, e = Elts.size(); i != e; ++i) - CElts.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, Elts[i])); + CElts.push_back(llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), Elts[i])); return llvm::ConstantVector::get(&CElts[0], CElts.size()); } @@ -930,9 +1015,11 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { assert(E->getBase()->getType()->isVectorType()); Base = EmitLValue(E->getBase()); } else { - const PointerType *PT = E->getBase()->getType()->getAsPointerType(); + const PointerType *PT = E->getBase()->getType()->getAs(); llvm::Value *Ptr = EmitScalarExpr(E->getBase()); - Base = LValue::MakeAddr(Ptr, PT->getPointeeType().getCVRQualifiers()); + Qualifiers Quals = MakeQualifiers(PT->getPointeeType()); + Quals.removeObjCGCAttr(); + Base = LValue::MakeAddr(Ptr, Quals); } // Encode the element access list into a vector of unsigned indices. @@ -940,9 +1027,9 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { E->getEncodedElementAccess(Indices); if (Base.isSimple()) { - llvm::Constant *CV = GenerateConstantVector(Indices); + llvm::Constant *CV = GenerateConstantVector(VMContext, Indices); return LValue::MakeExtVectorElt(Base.getAddress(), CV, - Base.getQualifiers()); + Base.getVRQualifiers()); } assert(Base.isExtVectorElt() && "Can only subscript lvalue vec elts here!"); @@ -951,68 +1038,69 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { for (unsigned i = 0, e = Indices.size(); i != e; ++i) { if (isa(BaseElts)) - CElts.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, 0)); + CElts.push_back(llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), 0)); else CElts.push_back(BaseElts->getOperand(Indices[i])); } llvm::Constant *CV = llvm::ConstantVector::get(&CElts[0], CElts.size()); return LValue::MakeExtVectorElt(Base.getExtVectorAddr(), CV, - Base.getQualifiers()); + Base.getVRQualifiers()); } LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { bool isUnion = false; - bool isIvar = false; bool isNonGC = false; Expr *BaseExpr = E->getBase(); llvm::Value *BaseValue = NULL; - unsigned CVRQualifiers=0; + Qualifiers BaseQuals; // If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar. if (E->isArrow()) { BaseValue = EmitScalarExpr(BaseExpr); - const PointerType *PTy = - BaseExpr->getType()->getAsPointerType(); + const PointerType *PTy = + BaseExpr->getType()->getAs(); if (PTy->getPointeeType()->isUnionType()) isUnion = true; - CVRQualifiers = PTy->getPointeeType().getCVRQualifiers(); - } else if (isa(BaseExpr) || - isa(BaseExpr)) { + BaseQuals = PTy->getPointeeType().getQualifiers(); + } else if (isa(BaseExpr->IgnoreParens()) || + isa( + BaseExpr->IgnoreParens())) { RValue RV = EmitObjCPropertyGet(BaseExpr); BaseValue = RV.getAggregateAddr(); if (BaseExpr->getType()->isUnionType()) isUnion = true; - CVRQualifiers = BaseExpr->getType().getCVRQualifiers(); + BaseQuals = BaseExpr->getType().getQualifiers(); } else { LValue BaseLV = EmitLValue(BaseExpr); - if (BaseLV.isObjCIvar()) - isIvar = true; if (BaseLV.isNonGC()) isNonGC = true; // FIXME: this isn't right for bitfields. BaseValue = BaseLV.getAddress(); - if (BaseExpr->getType()->isUnionType()) + QualType BaseTy = BaseExpr->getType(); + if (BaseTy->isUnionType()) isUnion = true; - CVRQualifiers = BaseExpr->getType().getCVRQualifiers(); + BaseQuals = BaseTy.getQualifiers(); } FieldDecl *Field = dyn_cast(E->getMemberDecl()); // FIXME: Handle non-field member expressions assert(Field && "No code generation for non-field member references"); LValue MemExpLV = EmitLValueForField(BaseValue, Field, isUnion, - CVRQualifiers); - LValue::SetObjCIvar(MemExpLV, isIvar); + BaseQuals.getCVRQualifiers()); LValue::SetObjCNonGC(MemExpLV, isNonGC); + setObjCGCLValueClass(getContext(), E, MemExpLV); return MemExpLV; } LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue, FieldDecl* Field, unsigned CVRQualifiers) { - unsigned idx = CGM.getTypes().getLLVMFieldNo(Field); + CodeGenTypes::BitFieldInfo Info = CGM.getTypes().getBitFieldInfo(Field); + // FIXME: CodeGenTypes should expose a method to get the appropriate type for // FieldTy (the appropriate type is ABI-dependent). - const llvm::Type *FieldTy = + const llvm::Type *FieldTy = CGM.getTypes().ConvertTypeForMem(Field->getType()); const llvm::PointerType *BaseTy = cast(BaseValue->getType()); @@ -1020,13 +1108,12 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue, BaseValue = Builder.CreateBitCast(BaseValue, llvm::PointerType::get(FieldTy, AS), "tmp"); - llvm::Value *V = Builder.CreateGEP(BaseValue, - llvm::ConstantInt::get(llvm::Type::Int32Ty, idx), - "tmp"); - - CodeGenTypes::BitFieldInfo bitFieldInfo = - CGM.getTypes().getBitFieldInfo(Field); - return LValue::MakeBitfield(V, bitFieldInfo.Begin, bitFieldInfo.Size, + + llvm::Value *Idx = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Info.FieldNo); + llvm::Value *V = Builder.CreateGEP(BaseValue, Idx, "tmp"); + + return LValue::MakeBitfield(V, Info.Start, Info.Size, Field->getType()->isSignedIntegerType(), Field->getType().getCVRQualifiers()|CVRQualifiers); } @@ -1034,46 +1121,34 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue, LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue, FieldDecl* Field, bool isUnion, - unsigned CVRQualifiers) -{ + unsigned CVRQualifiers) { if (Field->isBitField()) return EmitLValueForBitfield(BaseValue, Field, CVRQualifiers); - + unsigned idx = CGM.getTypes().getLLVMFieldNo(Field); llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp"); // Match union field type. if (isUnion) { - const llvm::Type *FieldTy = + const llvm::Type *FieldTy = CGM.getTypes().ConvertTypeForMem(Field->getType()); - const llvm::PointerType * BaseTy = + const llvm::PointerType * BaseTy = cast(BaseValue->getType()); unsigned AS = BaseTy->getAddressSpace(); - V = Builder.CreateBitCast(V, - llvm::PointerType::get(FieldTy, AS), + V = Builder.CreateBitCast(V, + llvm::PointerType::get(FieldTy, AS), "tmp"); } if (Field->getType()->isReferenceType()) V = Builder.CreateLoad(V, "tmp"); - QualType::GCAttrTypes attr = QualType::GCNone; - if (CGM.getLangOptions().ObjC1 && - CGM.getLangOptions().getGCMode() != LangOptions::NonGC) { - QualType Ty = Field->getType(); - attr = Ty.getObjCGCAttr(); - if (attr != QualType::GCNone) { - // __weak attribute on a field is ignored. - if (attr == QualType::Weak) - attr = QualType::GCNone; - } - else if (getContext().isObjCObjectPointerType(Ty)) - attr = QualType::Strong; - } - LValue LV = - LValue::MakeAddr(V, - Field->getType().getCVRQualifiers()|CVRQualifiers, - attr); - return LV; + Qualifiers Quals = MakeQualifiers(Field->getType()); + Quals.addCVRQualifiers(CVRQualifiers); + // __weak attribute on a field is ignored. + if (Quals.getObjCGCAttr() == Qualifiers::Weak) + Quals.removeObjCGCAttr(); + + return LValue::MakeAddr(V, Quals); } LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){ @@ -1081,7 +1156,7 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){ llvm::Value *DeclPtr = CreateTempAlloca(LTy, ".compoundliteral"); const Expr* InitExpr = E->getInitializer(); - LValue Result = LValue::MakeAddr(DeclPtr, E->getType().getCVRQualifiers()); + LValue Result = LValue::MakeAddr(DeclPtr, MakeQualifiers(E->getType())); if (E->getType()->isComplexType()) { EmitComplexExprIntoAddr(InitExpr, DeclPtr, false); @@ -1094,22 +1169,51 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){ return Result; } -LValue CodeGenFunction::EmitConditionalOperator(const ConditionalOperator* E) { - // We don't handle vectors yet. - if (E->getType()->isVectorType()) - return EmitUnsupportedLValue(E, "conditional operator"); +LValue +CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) { + if (E->isLvalue(getContext()) == Expr::LV_Valid) { + llvm::BasicBlock *LHSBlock = createBasicBlock("cond.true"); + llvm::BasicBlock *RHSBlock = createBasicBlock("cond.false"); + llvm::BasicBlock *ContBlock = createBasicBlock("cond.end"); + + llvm::Value *Cond = EvaluateExprAsBool(E->getCond()); + Builder.CreateCondBr(Cond, LHSBlock, RHSBlock); + + EmitBlock(LHSBlock); + + LValue LHS = EmitLValue(E->getLHS()); + if (!LHS.isSimple()) + return EmitUnsupportedLValue(E, "conditional operator"); + + llvm::Value *Temp = CreateTempAlloca(LHS.getAddress()->getType(), + "condtmp"); + + Builder.CreateStore(LHS.getAddress(), Temp); + EmitBranch(ContBlock); + + EmitBlock(RHSBlock); + LValue RHS = EmitLValue(E->getRHS()); + if (!RHS.isSimple()) + return EmitUnsupportedLValue(E, "conditional operator"); + + Builder.CreateStore(RHS.getAddress(), Temp); + EmitBranch(ContBlock); + EmitBlock(ContBlock); + + Temp = Builder.CreateLoad(Temp, "lv"); + return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); + } + // ?: here should be an aggregate. - assert((hasAggregateLLVMType(E->getType()) && + assert((hasAggregateLLVMType(E->getType()) && !E->getType()->isAnyComplexType()) && "Unexpected conditional operator!"); llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType())); EmitAggExpr(E, Temp, false); - return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType())); - + return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); } /// EmitCastLValue - Casts are never lvalues. If a cast is needed by the code @@ -1118,21 +1222,47 @@ LValue CodeGenFunction::EmitConditionalOperator(const ConditionalOperator* E) { /// all the reasons that casts are permitted with aggregate result, including /// noop aggregate casts, and cast from scalar to union. LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { - // If this is an aggregate-to-aggregate cast, just use the input's address as - // the lvalue. - if (getContext().hasSameUnqualifiedType(E->getType(), - E->getSubExpr()->getType())) + switch (E->getCastKind()) { + default: + // If this is an lvalue cast, treat it as a no-op. + // FIXME: We shouldn't need to check for this explicitly! + if (const ImplicitCastExpr *ICE = dyn_cast(E)) + if (ICE->isLvalueCast()) + return EmitLValue(E->getSubExpr()); + + assert(0 && "Unhandled cast!"); + + case CastExpr::CK_NoOp: + case CastExpr::CK_ConstructorConversion: + case CastExpr::CK_UserDefinedConversion: return EmitLValue(E->getSubExpr()); - - // Otherwise, we must have a cast from scalar to union. - assert(E->getType()->isUnionType() && "Expected scalar-to-union cast"); - - // Casts are only lvalues when the source and destination types are the same. - llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType())); - EmitAnyExpr(E->getSubExpr(), Temp, false); - return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType())); + case CastExpr::CK_DerivedToBase: { + const RecordType *DerivedClassTy = + E->getSubExpr()->getType()->getAs(); + CXXRecordDecl *DerivedClassDecl = + cast(DerivedClassTy->getDecl()); + + const RecordType *BaseClassTy = E->getType()->getAs(); + CXXRecordDecl *BaseClassDecl = cast(BaseClassTy->getDecl()); + + LValue LV = EmitLValue(E->getSubExpr()); + + // Perform the derived-to-base conversion + llvm::Value *Base = + GetAddressCXXOfBaseClass(LV.getAddress(), DerivedClassDecl, + BaseClassDecl, /*NullCheckValue=*/false); + + 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())); + } + } } //===--------------------------------------------------------------------===// @@ -1147,13 +1277,13 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) { if (const CXXMemberCallExpr *CE = dyn_cast(E)) return EmitCXXMemberCallExpr(CE); - + const Decl *TargetDecl = 0; if (const ImplicitCastExpr *CE = dyn_cast(E->getCallee())) { if (const DeclRefExpr *DRE = dyn_cast(CE->getSubExpr())) { TargetDecl = DRE->getDecl(); if (const FunctionDecl *FD = dyn_cast(TargetDecl)) - if (unsigned builtinID = FD->getBuiltinID(getContext())) + if (unsigned builtinID = FD->getBuiltinID()) return EmitBuiltinExpr(FD, builtinID, E); } } @@ -1161,7 +1291,17 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) { if (const CXXOperatorCallExpr *CE = dyn_cast(E)) if (const CXXMethodDecl *MD = dyn_cast_or_null(TargetDecl)) return EmitCXXOperatorMemberCallExpr(CE, MD); - + + if (isa(E->getCallee())) { + // C++ [expr.pseudo]p1: + // The result shall only be used as the operand for the function call + // operator (), and the result of such a call has type void. The only + // effect is the evaluation of the postfix-expression before the dot or + // arrow. + EmitScalarExpr(E->getCallee()); + return RValue::get(0); + } + llvm::Value *Callee = EmitScalarExpr(E->getCallee()); return EmitCall(Callee, E->getCallee()->getType(), E->arg_begin(), E->arg_end(), TargetDecl); @@ -1173,7 +1313,7 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { EmitAnyExpr(E->getLHS()); return EmitLValue(E->getRHS()); } - + // Can only get l-value for binary operator expressions which are a // simple assignment of aggregate type. if (E->getOpcode() != BinaryOperator::Assign) @@ -1182,8 +1322,7 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType())); EmitAggExpr(E, Temp, false); // FIXME: Are these qualifiers correct? - return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType())); + return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); } LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) { @@ -1193,21 +1332,18 @@ LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) { assert(E->getCallReturnType()->isReferenceType() && "Can't have a scalar return unless the return type is a " "reference type!"); - - return LValue::MakeAddr(RV.getScalarVal(), E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType())); + + return LValue::MakeAddr(RV.getScalarVal(), MakeQualifiers(E->getType())); } - - return LValue::MakeAddr(RV.getAggregateAddr(), - E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType())); + + return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType())); } 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, E->getType().getCVRQualifiers()); + return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); } LValue @@ -1219,15 +1355,15 @@ CodeGenFunction::EmitCXXConditionDeclLValue(const CXXConditionDeclExpr *E) { LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) { llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(E->getType()), "tmp"); EmitCXXConstructExpr(Temp, E); - return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers()); + return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); } LValue CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) { LValue LV = EmitLValue(E->getSubExpr()); - + PushCXXTemporary(E->getTemporary(), LV.getAddress()); - + return LV; } @@ -1235,9 +1371,7 @@ LValue CodeGenFunction::EmitObjCMessageExprLValue(const ObjCMessageExpr *E) { // Can only get l-value for message expression returning aggregate type RValue RV = EmitObjCMessageExpr(E); // FIXME: can this be volatile? - return LValue::MakeAddr(RV.getAggregateAddr(), - E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType())); + return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType())); } llvm::Value *CodeGenFunction::EmitIvarOffset(const ObjCInterfaceDecl *Interface, @@ -1257,35 +1391,39 @@ LValue CodeGenFunction::EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E) { // FIXME: A lot of the code below could be shared with EmitMemberExpr. llvm::Value *BaseValue = 0; const Expr *BaseExpr = E->getBase(); - unsigned CVRQualifiers = 0; + Qualifiers BaseQuals; QualType ObjectTy; if (E->isArrow()) { BaseValue = EmitScalarExpr(BaseExpr); - const PointerType *PTy = BaseExpr->getType()->getAsPointerType(); - ObjectTy = PTy->getPointeeType(); - CVRQualifiers = ObjectTy.getCVRQualifiers(); + ObjectTy = BaseExpr->getType()->getPointeeType(); + BaseQuals = ObjectTy.getQualifiers(); } else { LValue BaseLV = EmitLValue(BaseExpr); // FIXME: this isn't right for bitfields. BaseValue = BaseLV.getAddress(); ObjectTy = BaseExpr->getType(); - CVRQualifiers = ObjectTy.getCVRQualifiers(); + BaseQuals = ObjectTy.getQualifiers(); } - return EmitLValueForIvar(ObjectTy, BaseValue, E->getDecl(), CVRQualifiers); + LValue LV = + EmitLValueForIvar(ObjectTy, BaseValue, E->getDecl(), + BaseQuals.getCVRQualifiers()); + setObjCGCLValueClass(getContext(), E, LV); + return LV; } -LValue +LValue CodeGenFunction::EmitObjCPropertyRefLValue(const ObjCPropertyRefExpr *E) { - // This is a special l-value that just issues sends when we load or - // store through it. + // This is a special l-value that just issues sends when we load or store + // through it. return LValue::MakePropertyRef(E, E->getType().getCVRQualifiers()); } -LValue -CodeGenFunction::EmitObjCKVCRefLValue(const ObjCKVCRefExpr *E) { - // This is a special l-value that just issues sends when we load or - // store through it. +LValue +CodeGenFunction::EmitObjCKVCRefLValue( + const ObjCImplicitSetterGetterRefExpr *E) { + // This is a special l-value that just issues sends when we load or store + // through it. return LValue::MakeKVCRef(E, E->getType().getCVRQualifiers()); } @@ -1295,31 +1433,36 @@ CodeGenFunction::EmitObjCSuperExprLValue(const ObjCSuperExpr *E) { } LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) { - + // Can only get l-value for message expression returning aggregate type RValue RV = EmitAnyExprToTemp(E); // FIXME: can this be volatile? - return LValue::MakeAddr(RV.getAggregateAddr(), - E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType())); + return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType())); } -RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType, +RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd, const Decl *TargetDecl) { - // Get the actual function type. The callee type will always be a - // pointer to function type or a block pointer type. - assert(CalleeType->isFunctionPointerType() && + // Get the actual function type. The callee type will always be a pointer to + // function type or a block pointer type. + assert(CalleeType->isFunctionPointerType() && "Call must have function pointer type!"); - QualType FnType = CalleeType->getAsPointerType()->getPointeeType(); - QualType ResultType = FnType->getAsFunctionType()->getResultType(); + QualType FnType = CalleeType->getAs()->getPointeeType(); + QualType ResultType = FnType->getAs()->getResultType(); CallArgList Args; - EmitCallArgs(Args, FnType->getAsFunctionProtoType(), ArgBeg, ArgEnd); - - return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), + EmitCallArgs(Args, FnType->getAs(), 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(Callee->stripPointerCasts())) + CallingConvention = F->getCallingConv(); + return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args, + CallingConvention), Callee, Args, TargetDecl); } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 412a06594f53..0866ff893c4e 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -13,6 +13,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "CGObjCRuntime.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/StmtVisitor.h" @@ -35,12 +36,14 @@ class VISIBILITY_HIDDEN AggExprEmitter : public StmtVisitor { llvm::Value *DestPtr; bool VolatileDest; bool IgnoreResult; - + bool IsInitializer; + bool RequiresGCollection; public: AggExprEmitter(CodeGenFunction &cgf, llvm::Value *destPtr, bool v, - bool ignore) + bool ignore, bool isinit, bool requiresGCollection) : CGF(cgf), Builder(CGF.Builder), - DestPtr(destPtr), VolatileDest(v), IgnoreResult(ignore) { + DestPtr(destPtr), VolatileDest(v), IgnoreResult(ignore), + IsInitializer(isinit), RequiresGCollection(requiresGCollection) { } //===--------------------------------------------------------------------===// @@ -59,7 +62,7 @@ public: //===--------------------------------------------------------------------===// // Visitor Methods //===--------------------------------------------------------------------===// - + void VisitStmt(Stmt *S) { CGF.ErrorUnsupported(S, "aggregate expression"); } @@ -72,35 +75,36 @@ public: void VisitUnaryDeref(UnaryOperator *E) { EmitAggLoadOfLValue(E); } void VisitStringLiteral(StringLiteral *E) { EmitAggLoadOfLValue(E); } void VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { - EmitAggLoadOfLValue(E); + EmitAggLoadOfLValue(E); } void VisitArraySubscriptExpr(ArraySubscriptExpr *E) { EmitAggLoadOfLValue(E); } void VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) { - EmitAggLoadOfLValue(E); + EmitAggLoadOfLValue(E); } void VisitPredefinedExpr(const PredefinedExpr *E) { - EmitAggLoadOfLValue(E); + EmitAggLoadOfLValue(E); } - + // Operators. - void VisitCStyleCastExpr(CStyleCastExpr *E); - void VisitImplicitCastExpr(ImplicitCastExpr *E); + void VisitCastExpr(CastExpr *E); void VisitCallExpr(const CallExpr *E); void VisitStmtExpr(const StmtExpr *E); void VisitBinaryOperator(const BinaryOperator *BO); void VisitBinAssign(const BinaryOperator *E); void VisitBinComma(const BinaryOperator *E); + void VisitUnaryAddrOf(const UnaryOperator *E); void VisitObjCMessageExpr(ObjCMessageExpr *E); void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { EmitAggLoadOfLValue(E); } void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E); - void VisitObjCKVCRefExpr(ObjCKVCRefExpr *E); - + void VisitObjCImplicitSetterGetterRefExpr(ObjCImplicitSetterGetterRefExpr *E); + void VisitConditionalOperator(const ConditionalOperator *CO); + void VisitChooseExpr(const ChooseExpr *CE); void VisitInitListExpr(InitListExpr *E); void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { Visit(DAE->getExpr()); @@ -143,6 +147,12 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) { DestPtr = CGF.CreateTempAlloca(CGF.ConvertType(E->getType()), "agg.tmp"); } + if (RequiresGCollection) { + CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, + DestPtr, Src.getAggregateAddr(), + E->getType()); + return; + } // If the result of the assignment is used, copy the LHS there also. // FIXME: Pass VolatileDest as well. I think we also need to merge volatile // from the source as well, as we can't eliminate it if either operand @@ -164,25 +174,80 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) { // Visitor Methods //===----------------------------------------------------------------------===// -void AggExprEmitter::VisitCStyleCastExpr(CStyleCastExpr *E) { - // GCC union extension - if (E->getSubExpr()->getType()->isScalarType()) { +void AggExprEmitter::VisitCastExpr(CastExpr *E) { + switch (E->getCastKind()) { + default: assert(0 && "Unhandled cast kind!"); + + case CastExpr::CK_ToUnion: { + // GCC union extension QualType PtrTy = - CGF.getContext().getPointerType(E->getSubExpr()->getType()); + CGF.getContext().getPointerType(E->getSubExpr()->getType()); llvm::Value *CastPtr = Builder.CreateBitCast(DestPtr, CGF.ConvertType(PtrTy)); - EmitInitializationToLValue(E->getSubExpr(), LValue::MakeAddr(CastPtr, 0)); - return; + EmitInitializationToLValue(E->getSubExpr(), + LValue::MakeAddr(CastPtr, Qualifiers())); + break; } - Visit(E->getSubExpr()); -} + // FIXME: Remove the CK_Unknown check here. + case CastExpr::CK_Unknown: + case CastExpr::CK_NoOp: + case CastExpr::CK_UserDefinedConversion: + case CastExpr::CK_ConstructorConversion: + assert(CGF.getContext().hasSameUnqualifiedType(E->getSubExpr()->getType(), + E->getType()) && + "Implicit cast types must be compatible"); + Visit(E->getSubExpr()); + break; + + case CastExpr::CK_NullToMemberPointer: { + const llvm::Type *PtrDiffTy = + CGF.ConvertType(CGF.getContext().getPointerDiffType()); -void AggExprEmitter::VisitImplicitCastExpr(ImplicitCastExpr *E) { - assert(CGF.getContext().hasSameUnqualifiedType(E->getSubExpr()->getType(), - E->getType()) && - "Implicit cast types must be compatible"); - Visit(E->getSubExpr()); + llvm::Value *NullValue = llvm::Constant::getNullValue(PtrDiffTy); + llvm::Value *Ptr = Builder.CreateStructGEP(DestPtr, 0, "ptr"); + Builder.CreateStore(NullValue, Ptr, VolatileDest); + + llvm::Value *Adj = Builder.CreateStructGEP(DestPtr, 1, "adj"); + Builder.CreateStore(NullValue, Adj, VolatileDest); + + break; + } + + case CastExpr::CK_BaseToDerivedMemberPointer: { + QualType SrcType = E->getSubExpr()->getType(); + + llvm::Value *Src = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(SrcType), + "tmp"); + CGF.EmitAggExpr(E->getSubExpr(), Src, SrcType.isVolatileQualified()); + + llvm::Value *SrcPtr = Builder.CreateStructGEP(Src, 0, "src.ptr"); + SrcPtr = Builder.CreateLoad(SrcPtr); + + llvm::Value *SrcAdj = Builder.CreateStructGEP(Src, 1, "src.adj"); + SrcAdj = Builder.CreateLoad(SrcAdj); + + llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "dst.ptr"); + Builder.CreateStore(SrcPtr, DstPtr, VolatileDest); + + llvm::Value *DstAdj = Builder.CreateStructGEP(DestPtr, 1, "dst.adj"); + + // Now See if we need to update the adjustment. + const CXXRecordDecl *SrcDecl = + cast(SrcType->getAs()-> + getClass()->getAs()->getDecl()); + const CXXRecordDecl *DstDecl = + cast(E->getType()->getAs()-> + getClass()->getAs()->getDecl()); + + llvm::Constant *Adj = CGF.CGM.GetCXXBaseClassOffset(DstDecl, SrcDecl); + if (Adj) + SrcAdj = Builder.CreateAdd(SrcAdj, Adj, "adj"); + + Builder.CreateStore(SrcAdj, DstAdj, VolatileDest); + break; + } + } } void AggExprEmitter::VisitCallExpr(const CallExpr *E) { @@ -190,7 +255,7 @@ void AggExprEmitter::VisitCallExpr(const CallExpr *E) { EmitAggLoadOfLValue(E); return; } - + RValue RV = CGF.EmitCallExpr(E); EmitFinalDestCopy(E, RV); } @@ -205,14 +270,49 @@ void AggExprEmitter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { EmitFinalDestCopy(E, RV); } -void AggExprEmitter::VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) { +void AggExprEmitter::VisitObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *E) { RValue RV = CGF.EmitObjCPropertyGet(E); EmitFinalDestCopy(E, RV); } void AggExprEmitter::VisitBinComma(const BinaryOperator *E) { CGF.EmitAnyExpr(E->getLHS(), 0, false, true); - CGF.EmitAggExpr(E->getRHS(), DestPtr, VolatileDest); + CGF.EmitAggExpr(E->getRHS(), DestPtr, VolatileDest, + /*IgnoreResult=*/false, IsInitializer); +} + +void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { + // We have a member function pointer. + const MemberPointerType *MPT = E->getType()->getAs(); + assert(MPT->getPointeeType()->isFunctionProtoType() && + "Unexpected member pointer type!"); + + const QualifiedDeclRefExpr *DRE = cast(E->getSubExpr()); + const CXXMethodDecl *MD = cast(DRE->getDecl()); + + const llvm::Type *PtrDiffTy = + CGF.ConvertType(CGF.getContext().getPointerDiffType()); + + llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "dst.ptr"); + llvm::Value *FuncPtr; + + if (MD->isVirtual()) { + int64_t Index = + CGF.CGM.getVtableInfo().getMethodVtableIndex(MD); + + FuncPtr = llvm::ConstantInt::get(PtrDiffTy, Index + 1); + } else { + FuncPtr = llvm::ConstantExpr::getPtrToInt(CGF.CGM.GetAddrOfFunction(MD), + PtrDiffTy); + } + Builder.CreateStore(FuncPtr, DstPtr, VolatileDest); + + llvm::Value *AdjPtr = Builder.CreateStructGEP(DestPtr, 1, "dst.adj"); + + // The adjustment will always be 0. + Builder.CreateStore(llvm::ConstantInt::get(PtrDiffTy, 0), AdjPtr, + VolatileDest); } void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) { @@ -238,19 +338,25 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { if (!AggLoc) AggLoc = CGF.CreateTempAlloca(CGF.ConvertType(E->getRHS()->getType())); CGF.EmitAggExpr(E->getRHS(), AggLoc, VolatileDest); - CGF.EmitObjCPropertySet(LHS.getPropertyRefExpr(), + CGF.EmitObjCPropertySet(LHS.getPropertyRefExpr(), RValue::getAggregate(AggLoc, VolatileDest)); - } - else if (LHS.isKVCRef()) { + } else if (LHS.isKVCRef()) { llvm::Value *AggLoc = DestPtr; if (!AggLoc) AggLoc = CGF.CreateTempAlloca(CGF.ConvertType(E->getRHS()->getType())); CGF.EmitAggExpr(E->getRHS(), AggLoc, VolatileDest); - CGF.EmitObjCPropertySet(LHS.getKVCRefExpr(), + CGF.EmitObjCPropertySet(LHS.getKVCRefExpr(), RValue::getAggregate(AggLoc, VolatileDest)); } else { + bool RequiresGCollection = false; + if (CGF.getContext().getLangOptions().NeXTRuntime) { + QualType LHSTy = E->getLHS()->getType(); + if (const RecordType *FDTTy = LHSTy.getTypePtr()->getAs()) + RequiresGCollection = FDTTy->getDecl()->hasObjectMember(); + } // Codegen the RHS so that it stores directly into the LHS. - CGF.EmitAggExpr(E->getRHS(), LHS.getAddress(), LHS.isVolatileQualified()); + CGF.EmitAggExpr(E->getRHS(), LHS.getAddress(), LHS.isVolatileQualified(), + false, false, RequiresGCollection); EmitFinalDestCopy(E, LHS, true); } } @@ -259,30 +365,34 @@ void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) { llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true"); llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false"); llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end"); - + llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond()); Builder.CreateCondBr(Cond, LHSBlock, RHSBlock); - + CGF.PushConditionalTempDestruction(); CGF.EmitBlock(LHSBlock); - + // Handle the GNU extension for missing LHS. assert(E->getLHS() && "Must have LHS for aggregate value"); Visit(E->getLHS()); CGF.PopConditionalTempDestruction(); CGF.EmitBranch(ContBlock); - + CGF.PushConditionalTempDestruction(); CGF.EmitBlock(RHSBlock); - + Visit(E->getRHS()); CGF.PopConditionalTempDestruction(); CGF.EmitBranch(ContBlock); - + CGF.EmitBlock(ContBlock); } +void AggExprEmitter::VisitChooseExpr(const ChooseExpr *CE) { + Visit(CE->getChosenSubExpr(CGF.getContext())); +} + void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { llvm::Value *ArgValue = CGF.EmitVAListRef(VE->getSubExpr()); llvm::Value *ArgPtr = CGF.EmitVAArg(ArgValue, VE->getType()); @@ -292,28 +402,30 @@ void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { return; } - EmitFinalDestCopy(VE, LValue::MakeAddr(ArgPtr, 0)); + EmitFinalDestCopy(VE, LValue::MakeAddr(ArgPtr, Qualifiers())); } void AggExprEmitter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { llvm::Value *Val = DestPtr; - + if (!Val) { // Create a temporary variable. Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp"); // FIXME: volatile CGF.EmitAggExpr(E->getSubExpr(), Val, false); - } else + } else Visit(E->getSubExpr()); - - CGF.PushCXXTemporary(E->getTemporary(), Val); + + // Don't make this a live temporary if we're emitting an initializer expr. + if (!IsInitializer) + CGF.PushCXXTemporary(E->getTemporary(), Val); } void AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) { llvm::Value *Val = DestPtr; - + if (!Val) { // Create a temporary variable. Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp"); @@ -323,7 +435,7 @@ AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) { } void AggExprEmitter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { - CGF.EmitCXXExprWithTemporaries(E, DestPtr, VolatileDest); + CGF.EmitCXXExprWithTemporaries(E, DestPtr, VolatileDest, IsInitializer); } void AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) { @@ -359,7 +471,7 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue LV, QualType T) { void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { #if 0 - // FIXME: Disabled while we figure out what to do about + // FIXME: Disabled while we figure out what to do about // test/CodeGen/bitfield.c // // If we can, prefer a copy from a global; this is a lot less code for long @@ -387,7 +499,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { cast(DestPtr->getType()); const llvm::ArrayType *AType = cast(APType->getElementType()); - + uint64_t NumInitElements = E->getNumInits(); if (E->getNumInits() > 0) { @@ -402,29 +514,30 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { uint64_t NumArrayElements = AType->getNumElements(); QualType ElementType = CGF.getContext().getCanonicalType(E->getType()); ElementType = CGF.getContext().getAsArrayType(ElementType)->getElementType(); - - unsigned CVRqualifier = ElementType.getCVRQualifiers(); + + // FIXME: were we intentionally ignoring address spaces and GC attributes? + Qualifiers Quals = CGF.MakeQualifiers(ElementType); for (uint64_t i = 0; i != NumArrayElements; ++i) { llvm::Value *NextVal = Builder.CreateStructGEP(DestPtr, i, ".array"); if (i < NumInitElements) EmitInitializationToLValue(E->getInit(i), - LValue::MakeAddr(NextVal, CVRqualifier)); + LValue::MakeAddr(NextVal, Quals)); else - EmitNullInitializationToLValue(LValue::MakeAddr(NextVal, CVRqualifier), + EmitNullInitializationToLValue(LValue::MakeAddr(NextVal, Quals), ElementType); } return; } - + assert(E->getType()->isRecordType() && "Only support structs/unions here!"); - + // Do struct initialization; this code just sets each individual member // to the approprate value. This makes bitfield support automatic; // the disadvantage is that the generated code is more difficult for // the optimizer, especially with bitfields. unsigned NumInitElements = E->getNumInits(); - RecordDecl *SD = E->getType()->getAsRecordType()->getDecl(); + RecordDecl *SD = E->getType()->getAs()->getDecl(); unsigned CurInitVal = 0; if (E->getType()->isUnionType()) { @@ -432,7 +545,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { // specified by the initializer list. if (!E->getInitializedFieldInUnion()) { // Empty union; we have nothing to do. - + #ifndef NDEBUG // Make sure that it's really an empty and not a failure of // semantic analysis. @@ -458,7 +571,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { return; } - + // Here we iterate over the fields; this makes it simpler to both // default-initialize fields and skip over unnamed fields. for (RecordDecl::field_iterator Field = SD->field_begin(), @@ -494,13 +607,16 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { /// the value of the aggregate expression is not needed. If VolatileDest is /// true, DestPtr cannot be 0. void CodeGenFunction::EmitAggExpr(const Expr *E, llvm::Value *DestPtr, - bool VolatileDest, bool IgnoreResult) { + bool VolatileDest, bool IgnoreResult, + bool IsInitializer, + bool RequiresGCollection) { assert(E && hasAggregateLLVMType(E->getType()) && "Invalid aggregate expression to emit"); assert ((DestPtr != 0 || VolatileDest == false) && "volatile aggregate can't be 0"); - - AggExprEmitter(*this, DestPtr, VolatileDest, IgnoreResult) + + AggExprEmitter(*this, DestPtr, VolatileDest, IgnoreResult, IsInitializer, + RequiresGCollection) .Visit(const_cast(E)); } @@ -514,7 +630,7 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, llvm::Value *SrcPtr, QualType Ty, bool isVolatile) { assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex"); - + // Aggregate assignment turns into llvm.memcpy. This is almost valid per // C99 6.5.16.1p3, which states "If the value being stored in an object is // read from another object that overlaps in anyway the storage of the first @@ -525,18 +641,19 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, // equal, but other compilers do this optimization, and almost every memcpy // implementation handles this case safely. If there is a libc that does not // safely handle this, we can add a target hook. - const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext); if (DestPtr->getType() != BP) DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp"); if (SrcPtr->getType() != BP) SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp"); - + // Get size and alignment info for this aggregate. std::pair TypeInfo = getContext().getTypeInfo(Ty); - + // FIXME: Handle variable sized types. - const llvm::Type *IntPtr = llvm::IntegerType::get(LLVMPointerWidth); - + const llvm::Type *IntPtr = + llvm::IntegerType::get(VMContext, LLVMPointerWidth); + // FIXME: If we have a volatile struct, the optimizer can remove what might // appear to be `extra' memory ops: // @@ -553,6 +670,6 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, DestPtr, SrcPtr, // TypeInfo.first describes size in bits. llvm::ConstantInt::get(IntPtr, TypeInfo.first/8), - llvm::ConstantInt::get(llvm::Type::Int32Ty, + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), TypeInfo.second/8)); } diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 3555c8c9b691..9e81e4fbeabe 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -46,7 +46,7 @@ public: IgnoreRealAssign(irn), IgnoreImagAssign(iin) { } - + //===--------------------------------------------------------------------===// // Utilities //===--------------------------------------------------------------------===// @@ -82,23 +82,23 @@ public: if (LV.isPropertyRef()) return CGF.EmitObjCPropertyGet(LV.getPropertyRefExpr()).getComplexVal(); - + assert(LV.isKVCRef() && "Unknown LValue type!"); return CGF.EmitObjCPropertyGet(LV.getKVCRefExpr()).getComplexVal(); } - + /// EmitLoadOfComplex - Given a pointer to a complex value, emit code to load /// the real and imaginary pieces. ComplexPairTy EmitLoadOfComplex(llvm::Value *SrcPtr, bool isVolatile); - + /// EmitStoreOfComplex - Store the specified real/imag parts into the /// specified value pointer. void EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *ResPtr, bool isVol); - + /// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType. ComplexPairTy EmitComplexToComplexCast(ComplexPairTy Val, QualType SrcType, QualType DestType); - + //===--------------------------------------------------------------------===// // Visitor Methods //===--------------------------------------------------------------------===// @@ -111,16 +111,17 @@ public: ComplexPairTy VisitExpr(Expr *S); ComplexPairTy VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr());} ComplexPairTy VisitImaginaryLiteral(const ImaginaryLiteral *IL); - + // l-values. ComplexPairTy VisitDeclRefExpr(const Expr *E) { return EmitLoadOfLValue(E); } - ComplexPairTy VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { + ComplexPairTy VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { return EmitLoadOfLValue(E); } ComplexPairTy VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { return EmitLoadOfLValue(E); } - ComplexPairTy VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) { + ComplexPairTy VisitObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *E) { return EmitLoadOfLValue(E); } ComplexPairTy VisitObjCMessageExpr(ObjCMessageExpr *E) { @@ -130,7 +131,7 @@ public: ComplexPairTy VisitMemberExpr(const Expr *E) { return EmitLoadOfLValue(E); } // FIXME: CompoundLiteralExpr - + ComplexPairTy EmitCast(Expr *Op, QualType DestTy); ComplexPairTy VisitImplicitCastExpr(ImplicitCastExpr *E) { // Unlike for scalars, we don't have to worry about function->ptr demotion @@ -180,23 +181,24 @@ public: } ComplexPairTy VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { assert(E->getType()->isAnyComplexType() && "Expected complex type!"); - QualType Elem = E->getType()->getAsComplexType()->getElementType(); + QualType Elem = E->getType()->getAs()->getElementType(); llvm::Constant *Null = llvm::Constant::getNullValue(CGF.ConvertType(Elem)); return ComplexPairTy(Null, Null); } ComplexPairTy VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { assert(E->getType()->isAnyComplexType() && "Expected complex type!"); - QualType Elem = E->getType()->getAsComplexType()->getElementType(); - llvm::Constant *Null = llvm::Constant::getNullValue(CGF.ConvertType(Elem)); + QualType Elem = E->getType()->getAs()->getElementType(); + llvm::Constant *Null = + llvm::Constant::getNullValue(CGF.ConvertType(Elem)); return ComplexPairTy(Null, Null); } - + struct BinOpInfo { ComplexPairTy LHS; ComplexPairTy RHS; QualType Ty; // Computation Type. - }; - + }; + BinOpInfo EmitBinOps(const BinaryOperator *E); ComplexPairTy EmitCompoundAssign(const CompoundAssignOperator *E, ComplexPairTy (ComplexExprEmitter::*Func) @@ -206,7 +208,7 @@ public: ComplexPairTy EmitBinSub(const BinOpInfo &Op); ComplexPairTy EmitBinMul(const BinOpInfo &Op); ComplexPairTy EmitBinDiv(const BinOpInfo &Op); - + ComplexPairTy VisitBinMul(const BinaryOperator *E) { return EmitBinMul(EmitBinOps(E)); } @@ -219,7 +221,7 @@ public: ComplexPairTy VisitBinDiv(const BinaryOperator *E) { return EmitBinDiv(EmitBinOps(E)); } - + // Compound assignments. ComplexPairTy VisitBinAddAssign(const CompoundAssignOperator *E) { return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinAdd); @@ -233,7 +235,7 @@ public: ComplexPairTy VisitBinDivAssign(const CompoundAssignOperator *E) { return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinDiv); } - + // GCC rejects rem/and/or/xor for integer complex. // Logical and/or always return int, never complex. @@ -241,7 +243,7 @@ public: ComplexPairTy VisitBinAssign (const BinaryOperator *E); ComplexPairTy VisitBinComma (const BinaryOperator *E); - + ComplexPairTy VisitConditionalOperator(const ConditionalOperator *CO); ComplexPairTy VisitChooseExpr(ChooseExpr *CE); @@ -259,27 +261,34 @@ public: /// load the real and imaginary pieces, returning them as Real/Imag. ComplexPairTy ComplexExprEmitter::EmitLoadOfComplex(llvm::Value *SrcPtr, bool isVolatile) { - llvm::SmallString<64> Name(SrcPtr->getNameStart(), - SrcPtr->getNameStart()+SrcPtr->getNameLen()); - + llvm::SmallString<64> Name(SrcPtr->getName().begin(), + SrcPtr->getName().end()); + llvm::Value *Real=0, *Imag=0; if (!IgnoreReal) { + // FIXME: Clean this up once builder takes Twine/StringRef. Name += ".realp"; - llvm::Value *RealPtr = Builder.CreateStructGEP(SrcPtr, 0, Name.c_str()); + llvm::Value *RealPtr = Builder.CreateStructGEP(SrcPtr, 0, + Name.str().str().c_str()); Name.pop_back(); // .realp -> .real - Real = Builder.CreateLoad(RealPtr, isVolatile, Name.c_str()); + // FIXME: Clean this up once builder takes Twine/StringRef. + Real = Builder.CreateLoad(RealPtr, isVolatile, + Name.str().str().c_str()); Name.resize(Name.size()-4); // .real -> .imagp } - + if (!IgnoreImag) { Name += "imagp"; - - llvm::Value *ImagPtr = Builder.CreateStructGEP(SrcPtr, 1, Name.c_str()); + + // FIXME: Clean this up once builder takes Twine/StringRef. + llvm::Value *ImagPtr = Builder.CreateStructGEP(SrcPtr, 1, + Name.str().str().c_str()); Name.pop_back(); // .imagp -> .imag - Imag = Builder.CreateLoad(ImagPtr, isVolatile, Name.c_str()); + // FIXME: Clean this up once builder takes Twine/StringRef. + Imag = Builder.CreateLoad(ImagPtr, isVolatile, Name.str().str().c_str()); } return ComplexPairTy(Real, Imag); } @@ -290,7 +299,7 @@ void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *Ptr, bool isVolatile) { llvm::Value *RealPtr = Builder.CreateStructGEP(Ptr, 0, "real"); llvm::Value *ImagPtr = Builder.CreateStructGEP(Ptr, 1, "imag"); - + Builder.CreateStore(Val.first, RealPtr, isVolatile); Builder.CreateStore(Val.second, ImagPtr, isVolatile); } @@ -303,8 +312,8 @@ void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *Ptr, ComplexPairTy ComplexExprEmitter::VisitExpr(Expr *E) { CGF.ErrorUnsupported(E, "complex expression"); - const llvm::Type *EltTy = - CGF.ConvertType(E->getType()->getAsComplexType()->getElementType()); + const llvm::Type *EltTy = + CGF.ConvertType(E->getType()->getAs()->getElementType()); llvm::Value *U = llvm::UndefValue::get(EltTy); return ComplexPairTy(U, U); } @@ -312,7 +321,8 @@ ComplexPairTy ComplexExprEmitter::VisitExpr(Expr *E) { ComplexPairTy ComplexExprEmitter:: VisitImaginaryLiteral(const ImaginaryLiteral *IL) { llvm::Value *Imag = CGF.EmitScalarExpr(IL->getSubExpr()); - return ComplexPairTy(llvm::Constant::getNullValue(Imag->getType()), Imag); + return + ComplexPairTy(llvm::Constant::getNullValue(Imag->getType()), Imag); } @@ -332,8 +342,8 @@ ComplexPairTy ComplexExprEmitter::EmitComplexToComplexCast(ComplexPairTy Val, QualType SrcType, QualType DestType) { // Get the src/dest element type. - SrcType = SrcType->getAsComplexType()->getElementType(); - DestType = DestType->getAsComplexType()->getElementType(); + SrcType = SrcType->getAs()->getElementType(); + DestType = DestType->getAs()->getElementType(); // C99 6.3.1.6: When a value of complex type is converted to another // complex type, both the real and imaginary parts follow the conversion @@ -347,7 +357,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(Expr *Op, QualType DestTy) { // Two cases here: cast from (complex to complex) and (scalar to complex). if (Op->getType()->isAnyComplexType()) return EmitComplexToComplexCast(Visit(Op), Op->getType(), DestTy); - + // C99 6.3.1.7: When a value of real type is converted to a complex type, the // real part of the complex result value is determined by the rules of // conversion to the corresponding real type and the imaginary part of the @@ -355,9 +365,9 @@ ComplexPairTy ComplexExprEmitter::EmitCast(Expr *Op, QualType DestTy) { llvm::Value *Elt = CGF.EmitScalarExpr(Op); // Convert the input element to the element type of the complex. - DestTy = DestTy->getAsComplexType()->getElementType(); + DestTy = DestTy->getAs()->getElementType(); Elt = CGF.EmitScalarConversion(Elt, Op->getType(), DestTy); - + // Return (realval, 0). return ComplexPairTy(Elt, llvm::Constant::getNullValue(Elt->getType())); } @@ -367,31 +377,30 @@ ComplexPairTy ComplexExprEmitter::VisitPrePostIncDec(const UnaryOperator *E, LValue LV = CGF.EmitLValue(E->getSubExpr()); ComplexPairTy InVal = EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified()); - + llvm::Value *NextVal; if (isa(InVal.first->getType())) { uint64_t AmountVal = isInc ? 1 : -1; NextVal = llvm::ConstantInt::get(InVal.first->getType(), AmountVal, true); - + // Add the inc/dec to the real part. NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec"); - } else { - QualType ElemTy = E->getType()->getAsComplexType()->getElementType(); + QualType ElemTy = E->getType()->getAs()->getElementType(); llvm::APFloat FVal(CGF.getContext().getFloatTypeSemantics(ElemTy), 1); if (!isInc) FVal.changeSign(); - NextVal = llvm::ConstantFP::get(FVal); - + NextVal = llvm::ConstantFP::get(CGF.getLLVMContext(), FVal); + // Add the inc/dec to the real part. NextVal = Builder.CreateFAdd(InVal.first, NextVal, isInc ? "inc" : "dec"); } - + ComplexPairTy IncVal(NextVal, InVal.second); - + // Store the updated result through the lvalue. EmitStoreOfComplex(IncVal, LV.getAddress(), LV.isVolatileQualified()); - + // If this is a postinc, return the value read from memory, otherwise use the // updated value. return isPre ? IncVal : InVal; @@ -403,7 +412,7 @@ ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) { TestAndClearIgnoreRealAssign(); TestAndClearIgnoreImagAssign(); ComplexPairTy Op = Visit(E->getSubExpr()); - + llvm::Value *ResR, *ResI; if (Op.first->getType()->isFloatingPoint()) { ResR = Builder.CreateFNeg(Op.first, "neg.r"); @@ -427,13 +436,13 @@ ComplexPairTy ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *E) { ResI = Builder.CreateFNeg(Op.second, "conj.i"); else ResI = Builder.CreateNeg(Op.second, "conj.i"); - + return ComplexPairTy(Op.first, ResI); } ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) { llvm::Value *ResR, *ResI; - + if (Op.LHS.first->getType()->isFloatingPoint()) { ResR = Builder.CreateFAdd(Op.LHS.first, Op.RHS.first, "add.r"); ResI = Builder.CreateFAdd(Op.LHS.second, Op.RHS.second, "add.i"); @@ -460,12 +469,12 @@ ComplexPairTy ComplexExprEmitter::EmitBinSub(const BinOpInfo &Op) { ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) { using llvm::Value; Value *ResR, *ResI; - + if (Op.LHS.first->getType()->isFloatingPoint()) { 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"); - + Value *ResIl = Builder.CreateFMul(Op.LHS.second, Op.RHS.first, "mul.il"); Value *ResIr = Builder.CreateFMul(Op.LHS.first, Op.RHS.second, "mul.ir"); ResI = Builder.CreateFAdd(ResIl, ResIr, "mul.i"); @@ -473,7 +482,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) { Value *ResRl = Builder.CreateMul(Op.LHS.first, Op.RHS.first, "mul.rl"); Value *ResRr = Builder.CreateMul(Op.LHS.second, Op.RHS.second,"mul.rr"); ResR = Builder.CreateSub(ResRl, ResRr, "mul.r"); - + Value *ResIl = Builder.CreateMul(Op.LHS.second, Op.RHS.first, "mul.il"); Value *ResIr = Builder.CreateMul(Op.LHS.first, Op.RHS.second, "mul.ir"); ResI = Builder.CreateAdd(ResIl, ResIr, "mul.i"); @@ -484,7 +493,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) { ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) { llvm::Value *LHSr = Op.LHS.first, *LHSi = Op.LHS.second; llvm::Value *RHSr = Op.RHS.first, *RHSi = Op.RHS.second; - + llvm::Value *DSTr, *DSTi; if (Op.LHS.first->getType()->isFloatingPoint()) { @@ -492,15 +501,15 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) { llvm::Value *Tmp1 = Builder.CreateFMul(LHSr, RHSr, "tmp"); // a*c llvm::Value *Tmp2 = Builder.CreateFMul(LHSi, RHSi, "tmp"); // b*d llvm::Value *Tmp3 = Builder.CreateFAdd(Tmp1, Tmp2, "tmp"); // ac+bd - + llvm::Value *Tmp4 = Builder.CreateFMul(RHSr, RHSr, "tmp"); // c*c llvm::Value *Tmp5 = Builder.CreateFMul(RHSi, RHSi, "tmp"); // d*d llvm::Value *Tmp6 = Builder.CreateFAdd(Tmp4, Tmp5, "tmp"); // cc+dd - + llvm::Value *Tmp7 = Builder.CreateFMul(LHSi, RHSr, "tmp"); // b*c llvm::Value *Tmp8 = Builder.CreateFMul(LHSr, RHSi, "tmp"); // a*d llvm::Value *Tmp9 = Builder.CreateFSub(Tmp7, Tmp8, "tmp"); // bc-ad - + DSTr = Builder.CreateFDiv(Tmp3, Tmp6, "tmp"); DSTi = Builder.CreateFDiv(Tmp9, Tmp6, "tmp"); } else { @@ -508,16 +517,16 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) { llvm::Value *Tmp1 = Builder.CreateMul(LHSr, RHSr, "tmp"); // a*c llvm::Value *Tmp2 = Builder.CreateMul(LHSi, RHSi, "tmp"); // b*d llvm::Value *Tmp3 = Builder.CreateAdd(Tmp1, Tmp2, "tmp"); // ac+bd - + llvm::Value *Tmp4 = Builder.CreateMul(RHSr, RHSr, "tmp"); // c*c llvm::Value *Tmp5 = Builder.CreateMul(RHSi, RHSi, "tmp"); // d*d llvm::Value *Tmp6 = Builder.CreateAdd(Tmp4, Tmp5, "tmp"); // cc+dd - + llvm::Value *Tmp7 = Builder.CreateMul(LHSi, RHSr, "tmp"); // b*c llvm::Value *Tmp8 = Builder.CreateMul(LHSr, RHSi, "tmp"); // a*d llvm::Value *Tmp9 = Builder.CreateSub(Tmp7, Tmp8, "tmp"); // bc-ad - - if (Op.Ty->getAsComplexType()->getElementType()->isUnsignedIntegerType()) { + + if (Op.Ty->getAs()->getElementType()->isUnsignedIntegerType()) { DSTr = Builder.CreateUDiv(Tmp3, Tmp6, "tmp"); DSTi = Builder.CreateUDiv(Tmp9, Tmp6, "tmp"); } else { @@ -525,11 +534,11 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) { DSTi = Builder.CreateSDiv(Tmp9, Tmp6, "tmp"); } } - + return ComplexPairTy(DSTr, DSTi); } -ComplexExprEmitter::BinOpInfo +ComplexExprEmitter::BinOpInfo ComplexExprEmitter::EmitBinOps(const BinaryOperator *E) { TestAndClearIgnoreReal(); TestAndClearIgnoreImag(); @@ -554,27 +563,27 @@ EmitCompoundAssign(const CompoundAssignOperator *E, QualType LHSTy = E->getLHS()->getType(), RHSTy = E->getRHS()->getType(); BinOpInfo OpInfo; - + // Load the RHS and LHS operands. // __block variables need to have the rhs evaluated first, plus this should // improve codegen a little. It is possible for the RHS to be complex or // scalar. OpInfo.Ty = E->getComputationResultType(); OpInfo.RHS = EmitCast(E->getRHS(), OpInfo.Ty); - + LValue LHSLV = CGF.EmitLValue(E->getLHS()); // We know the LHS is a complex lvalue. - OpInfo.LHS=EmitLoadOfComplex(LHSLV.getAddress(),LHSLV.isVolatileQualified()); + OpInfo.LHS=EmitLoadOfComplex(LHSLV.getAddress(), LHSLV.isVolatileQualified()); OpInfo.LHS=EmitComplexToComplexCast(OpInfo.LHS, LHSTy, OpInfo.Ty); - + // Expand the binary operator. ComplexPairTy Result = (this->*Func)(OpInfo); - + // Truncate the result back to the LHS type. Result = EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy); - + // Store the result value into the LHS lvalue. EmitStoreOfComplex(Result, LHSLV.getAddress(), LHSLV.isVolatileQualified()); // And now return the LHS @@ -598,7 +607,7 @@ ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) { // Compute the address to store into. LValue LHS = CGF.EmitLValue(E->getLHS()); - + // Store into it, if simple. if (LHS.isSimple()) { EmitStoreOfComplex(Val, LHS.getAddress(), LHS.isVolatileQualified()); @@ -610,7 +619,7 @@ ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) { IgnoreImagAssign = ignimag; return EmitLoadOfComplex(LHS.getAddress(), LHS.isVolatileQualified()); } - + // Otherwise we must have a property setter (no complex vector/bitfields). if (LHS.isPropertyRef()) CGF.EmitObjCPropertySet(LHS.getPropertyRefExpr(), RValue::getComplex(Val)); @@ -641,27 +650,27 @@ VisitConditionalOperator(const ConditionalOperator *E) { llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true"); llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false"); llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end"); - + llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond()); Builder.CreateCondBr(Cond, LHSBlock, RHSBlock); - + CGF.EmitBlock(LHSBlock); - + // Handle the GNU extension for missing LHS. assert(E->getLHS() && "Must have LHS for complex value"); ComplexPairTy LHS = Visit(E->getLHS()); LHSBlock = Builder.GetInsertBlock(); CGF.EmitBranch(ContBlock); - + CGF.EmitBlock(RHSBlock); - + ComplexPairTy RHS = Visit(E->getRHS()); RHSBlock = Builder.GetInsertBlock(); CGF.EmitBranch(ContBlock); - + CGF.EmitBlock(ContBlock); - + // Create a PHI node for the real part. llvm::PHINode *RealPN = Builder.CreatePHI(LHS.first->getType(), "cond.r"); RealPN->reserveOperandSpace(2); @@ -673,7 +682,7 @@ VisitConditionalOperator(const ConditionalOperator *E) { ImagPN->reserveOperandSpace(2); ImagPN->addIncoming(LHS.second, LHSBlock); ImagPN->addIncoming(RHS.second, RHSBlock); - + return ComplexPairTy(RealPN, ImagPN); } @@ -692,7 +701,7 @@ ComplexPairTy ComplexExprEmitter::VisitInitListExpr(InitListExpr *E) { return Visit(E->getInit(0)); // Empty init list intializes to null - QualType Ty = E->getType()->getAsComplexType()->getElementType(); + QualType Ty = E->getType()->getAs()->getElementType(); const llvm::Type* LTy = CGF.ConvertType(Ty); llvm::Value* zeroConstant = llvm::Constant::getNullValue(LTy); return ComplexPairTy(zeroConstant, zeroConstant); @@ -704,8 +713,8 @@ ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) { if (!ArgPtr) { CGF.ErrorUnsupported(E, "complex va_arg expression"); - const llvm::Type *EltTy = - CGF.ConvertType(E->getType()->getAsComplexType()->getElementType()); + const llvm::Type *EltTy = + CGF.ConvertType(E->getType()->getAs()->getElementType()); llvm::Value *U = llvm::UndefValue::get(EltTy); return ComplexPairTy(U, U); } @@ -724,7 +733,7 @@ ComplexPairTy CodeGenFunction::EmitComplexExpr(const Expr *E, bool IgnoreReal, bool IgnoreImag, bool IgnoreRealAssign, bool IgnoreImagAssign) { assert(E && E->getType()->isAnyComplexType() && "Invalid complex expression to emit"); - + return ComplexExprEmitter(*this, IgnoreReal, IgnoreImag, IgnoreRealAssign, IgnoreImagAssign) .Visit(const_cast(E)); @@ -750,7 +759,7 @@ void CodeGenFunction::StoreComplexToAddr(ComplexPairTy V, } /// LoadComplexFromAddr - Load a complex number from the specified address. -ComplexPairTy CodeGenFunction::LoadComplexFromAddr(llvm::Value *SrcAddr, +ComplexPairTy CodeGenFunction::LoadComplexFromAddr(llvm::Value *SrcAddr, bool SrcIsVolatile) { return ComplexExprEmitter(*this).EmitLoadOfComplex(SrcAddr, SrcIsVolatile); } diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 37c9c366fee6..7f540c3c0688 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -16,6 +16,7 @@ #include "CGObjCRuntime.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/Builtins.h" #include "llvm/Constants.h" @@ -27,45 +28,541 @@ using namespace clang; using namespace CodeGen; namespace { -class VISIBILITY_HIDDEN ConstExprEmitter : + +class VISIBILITY_HIDDEN ConstStructBuilder { + CodeGenModule &CGM; + CodeGenFunction *CGF; + + bool Packed; + + unsigned NextFieldOffsetInBytes; + + unsigned LLVMStructAlignment; + + std::vector Elements; + + ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF) + : CGM(CGM), CGF(CGF), Packed(false), NextFieldOffsetInBytes(0), + LLVMStructAlignment(1) { } + + bool AppendField(const FieldDecl *Field, uint64_t FieldOffset, + const Expr *InitExpr) { + uint64_t FieldOffsetInBytes = FieldOffset / 8; + + assert(NextFieldOffsetInBytes <= FieldOffsetInBytes + && "Field offset mismatch!"); + + // Emit the field. + llvm::Constant *C = CGM.EmitConstantExpr(InitExpr, Field->getType(), CGF); + if (!C) + return false; + + unsigned FieldAlignment = getAlignment(C); + + // Round up the field offset to the alignment of the field type. + uint64_t AlignedNextFieldOffsetInBytes = + llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment); + + if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) { + assert(!Packed && "Alignment is wrong even with a packed struct!"); + + // Convert the struct to a packed struct. + ConvertStructToPacked(); + + AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; + } + + if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) { + // We need to append padding. + AppendPadding(FieldOffsetInBytes - NextFieldOffsetInBytes); + + assert(NextFieldOffsetInBytes == FieldOffsetInBytes && + "Did not add enough padding!"); + + AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; + } + + // Add the field. + Elements.push_back(C); + NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + getSizeInBytes(C); + + if (Packed) + assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!"); + else + LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment); + + return true; + } + + bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, + const Expr *InitExpr) { + llvm::ConstantInt *CI = + cast_or_null(CGM.EmitConstantExpr(InitExpr, + Field->getType(), + CGF)); + // FIXME: Can this ever happen? + if (!CI) + return false; + + if (FieldOffset > NextFieldOffsetInBytes * 8) { + // We need to add padding. + uint64_t NumBytes = + llvm::RoundUpToAlignment(FieldOffset - + NextFieldOffsetInBytes * 8, 8) / 8; + + AppendPadding(NumBytes); + } + + uint64_t FieldSize = + Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue(); + + llvm::APInt FieldValue = CI->getValue(); + + // Promote the size of FieldValue if necessary + // FIXME: This should never occur, but currently it can because initializer + // constants are cast to bool, and because clang is not enforcing bitfield + // width limits. + if (FieldSize > FieldValue.getBitWidth()) + FieldValue.zext(FieldSize); + + // Truncate the size of FieldValue to the bit field size. + if (FieldSize < FieldValue.getBitWidth()) + FieldValue.trunc(FieldSize); + + if (FieldOffset < NextFieldOffsetInBytes * 8) { + // Either part of the field or the entire field can go into the previous + // byte. + assert(!Elements.empty() && "Elements can't be empty!"); + + unsigned BitsInPreviousByte = + NextFieldOffsetInBytes * 8 - FieldOffset; + + bool FitsCompletelyInPreviousByte = + BitsInPreviousByte >= FieldValue.getBitWidth(); + + llvm::APInt Tmp = FieldValue; + + if (!FitsCompletelyInPreviousByte) { + unsigned NewFieldWidth = FieldSize - BitsInPreviousByte; + + if (CGM.getTargetData().isBigEndian()) { + Tmp = Tmp.lshr(NewFieldWidth); + Tmp.trunc(BitsInPreviousByte); + + // We want the remaining high bits. + FieldValue.trunc(NewFieldWidth); + } else { + Tmp.trunc(BitsInPreviousByte); + + // We want the remaining low bits. + FieldValue = FieldValue.lshr(BitsInPreviousByte); + FieldValue.trunc(NewFieldWidth); + } + } + + Tmp.zext(8); + if (CGM.getTargetData().isBigEndian()) { + if (FitsCompletelyInPreviousByte) + Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth()); + } else { + Tmp = Tmp.shl(8 - BitsInPreviousByte); + } + + // Or in the bits that go into the previous byte. + Tmp |= cast(Elements.back())->getValue(); + Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp); + + if (FitsCompletelyInPreviousByte) + return true; + } + + while (FieldValue.getBitWidth() > 8) { + llvm::APInt Tmp; + + if (CGM.getTargetData().isBigEndian()) { + // We want the high bits. + Tmp = FieldValue; + Tmp = Tmp.lshr(Tmp.getBitWidth() - 8); + Tmp.trunc(8); + } else { + // We want the low bits. + Tmp = FieldValue; + Tmp.trunc(8); + + FieldValue = FieldValue.lshr(8); + } + + Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp)); + NextFieldOffsetInBytes++; + + FieldValue.trunc(FieldValue.getBitWidth() - 8); + } + + assert(FieldValue.getBitWidth() > 0 && + "Should have at least one bit left!"); + assert(FieldValue.getBitWidth() <= 8 && + "Should not have more than a byte left!"); + + if (FieldValue.getBitWidth() < 8) { + if (CGM.getTargetData().isBigEndian()) { + unsigned BitWidth = FieldValue.getBitWidth(); + + FieldValue.zext(8); + FieldValue = FieldValue << (8 - BitWidth); + } else + FieldValue.zext(8); + } + + // Append the last element. + Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), + FieldValue)); + NextFieldOffsetInBytes++; + return true; + } + + void AppendPadding(uint64_t NumBytes) { + if (!NumBytes) + return; + + const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); + if (NumBytes > 1) + Ty = llvm::ArrayType::get(Ty, NumBytes); + + llvm::Constant *C = llvm::Constant::getNullValue(Ty); + Elements.push_back(C); + assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!"); + + NextFieldOffsetInBytes += getSizeInBytes(C); + } + + void AppendTailPadding(uint64_t RecordSize) { + assert(RecordSize % 8 == 0 && "Invalid record size!"); + + uint64_t RecordSizeInBytes = RecordSize / 8; + assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!"); + + unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes; + AppendPadding(NumPadBytes); + } + + void ConvertStructToPacked() { + std::vector PackedElements; + uint64_t ElementOffsetInBytes = 0; + + for (unsigned i = 0, e = Elements.size(); i != e; ++i) { + llvm::Constant *C = Elements[i]; + + unsigned ElementAlign = + CGM.getTargetData().getABITypeAlignment(C->getType()); + uint64_t AlignedElementOffsetInBytes = + llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign); + + if (AlignedElementOffsetInBytes > ElementOffsetInBytes) { + // We need some padding. + uint64_t NumBytes = + AlignedElementOffsetInBytes - ElementOffsetInBytes; + + const llvm::Type *Ty = llvm::Type::getInt8Ty(CGF->getLLVMContext()); + if (NumBytes > 1) + Ty = llvm::ArrayType::get(Ty, NumBytes); + + llvm::Constant *Padding = llvm::Constant::getNullValue(Ty); + PackedElements.push_back(Padding); + ElementOffsetInBytes += getSizeInBytes(Padding); + } + + PackedElements.push_back(C); + ElementOffsetInBytes += getSizeInBytes(C); + } + + assert(ElementOffsetInBytes == NextFieldOffsetInBytes && + "Packing the struct changed its size!"); + + Elements = PackedElements; + LLVMStructAlignment = 1; + Packed = true; + } + + bool Build(InitListExpr *ILE) { + RecordDecl *RD = ILE->getType()->getAs()->getDecl(); + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + + unsigned FieldNo = 0; + unsigned ElementNo = 0; + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + ElementNo < ILE->getNumInits() && Field != FieldEnd; + ++Field, ++FieldNo) { + if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field) + continue; + + if (Field->isBitField()) { + if (!Field->getIdentifier()) + continue; + + if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo), + ILE->getInit(ElementNo))) + return false; + } else { + if (!AppendField(*Field, Layout.getFieldOffset(FieldNo), + ILE->getInit(ElementNo))) + return false; + } + + ElementNo++; + } + + uint64_t LayoutSizeInBytes = Layout.getSize() / 8; + + if (NextFieldOffsetInBytes > LayoutSizeInBytes) { + // If the struct is bigger than the size of the record type, + // we must have a flexible array member at the end. + assert(RD->hasFlexibleArrayMember() && + "Must have flexible array member if struct is bigger than type!"); + + // No tail padding is necessary. + return true; + } + + uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes, + LLVMStructAlignment); + + // Check if we need to convert the struct to a packed struct. + if (NextFieldOffsetInBytes <= LayoutSizeInBytes && + LLVMSizeInBytes > LayoutSizeInBytes) { + assert(!Packed && "Size mismatch!"); + + ConvertStructToPacked(); + assert(NextFieldOffsetInBytes == LayoutSizeInBytes && + "Converting to packed did not help!"); + } + + // Append tail padding if necessary. + AppendTailPadding(Layout.getSize()); + + assert(Layout.getSize() / 8 == NextFieldOffsetInBytes && + "Tail padding mismatch!"); + + return true; + } + + unsigned getAlignment(const llvm::Constant *C) const { + if (Packed) + return 1; + + return CGM.getTargetData().getABITypeAlignment(C->getType()); + } + + uint64_t getSizeInBytes(const llvm::Constant *C) const { + return CGM.getTargetData().getTypeAllocSize(C->getType()); + } + +public: + static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, + InitListExpr *ILE) { + ConstStructBuilder Builder(CGM, CGF); + + if (!Builder.Build(ILE)) + return 0; + + llvm::Constant *Result = + llvm::ConstantStruct::get(CGM.getLLVMContext(), + Builder.Elements, Builder.Packed); + + assert(llvm::RoundUpToAlignment(Builder.NextFieldOffsetInBytes, + Builder.getAlignment(Result)) == + Builder.getSizeInBytes(Result) && "Size mismatch!"); + + return Result; + } +}; + +class VISIBILITY_HIDDEN ConstExprEmitter : public StmtVisitor { CodeGenModule &CGM; CodeGenFunction *CGF; + llvm::LLVMContext &VMContext; public: ConstExprEmitter(CodeGenModule &cgm, CodeGenFunction *cgf) - : CGM(cgm), CGF(cgf) { + : CGM(cgm), CGF(cgf), VMContext(cgm.getLLVMContext()) { } - + //===--------------------------------------------------------------------===// // Visitor Methods //===--------------------------------------------------------------------===// - + llvm::Constant *VisitStmt(Stmt *S) { return 0; } - - llvm::Constant *VisitParenExpr(ParenExpr *PE) { - return Visit(PE->getSubExpr()); + + llvm::Constant *VisitParenExpr(ParenExpr *PE) { + return Visit(PE->getSubExpr()); } - + llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { return Visit(E->getInitializer()); } - + + llvm::Constant *EmitMemberFunctionPointer(CXXMethodDecl *MD) { + assert(MD->isInstance() && "Member function must not be static!"); + + const llvm::Type *PtrDiffTy = + CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); + + llvm::Constant *Values[2]; + + // Get the function pointer (or index if this is a virtual function). + if (MD->isVirtual()) { + int64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD); + + Values[0] = llvm::ConstantInt::get(PtrDiffTy, Index + 1); + } else { + llvm::Constant *FuncPtr = CGM.GetAddrOfFunction(MD); + + Values[0] = llvm::ConstantExpr::getPtrToInt(FuncPtr, PtrDiffTy); + } + + // The adjustment will always be 0. + Values[1] = llvm::ConstantInt::get(PtrDiffTy, 0); + + return llvm::ConstantStruct::get(CGM.getLLVMContext(), + Values, 2, /*Packed=*/false); + } + + llvm::Constant *VisitUnaryAddrOf(UnaryOperator *E) { + if (const MemberPointerType *MPT = + E->getType()->getAs()) { + QualType T = MPT->getPointeeType(); + if (T->isFunctionProtoType()) { + QualifiedDeclRefExpr *DRE = cast(E->getSubExpr()); + + return EmitMemberFunctionPointer(cast(DRE->getDecl())); + } + + // FIXME: Should we handle other member pointer types here too, + // or should they be handled by Expr::Evaluate? + } + + return 0; + } + + llvm::Constant *VisitBinSub(BinaryOperator *E) { + // This must be a pointer/pointer subtraction. This only happens for + // address of label. + if (!isa(E->getLHS()->IgnoreParenNoopCasts(CGM.getContext())) || + !isa(E->getRHS()->IgnoreParenNoopCasts(CGM.getContext()))) + return 0; + + llvm::Constant *LHS = CGM.EmitConstantExpr(E->getLHS(), + E->getLHS()->getType(), CGF); + llvm::Constant *RHS = CGM.EmitConstantExpr(E->getRHS(), + E->getRHS()->getType(), CGF); + + const llvm::Type *ResultType = ConvertType(E->getType()); + LHS = llvm::ConstantExpr::getPtrToInt(LHS, ResultType); + RHS = llvm::ConstantExpr::getPtrToInt(RHS, ResultType); + + // No need to divide by element size, since addr of label is always void*, + // which has size 1 in GNUish. + return llvm::ConstantExpr::getSub(LHS, RHS); + } + llvm::Constant *VisitCastExpr(CastExpr* E) { - // GCC cast to union extension - if (E->getType()->isUnionType()) { + switch (E->getCastKind()) { + case CastExpr::CK_ToUnion: { + // GCC cast to union extension + assert(E->getType()->isUnionType() && + "Destination type is not union type!"); const llvm::Type *Ty = ConvertType(E->getType()); Expr *SubExpr = E->getSubExpr(); - return EmitUnion(CGM.EmitConstantExpr(SubExpr, SubExpr->getType(), CGF), - Ty); + + llvm::Constant *C = + CGM.EmitConstantExpr(SubExpr, SubExpr->getType(), CGF); + if (!C) + return 0; + + // Build a struct with the union sub-element as the first member, + // and padded to the appropriate size + std::vector Elts; + std::vector Types; + Elts.push_back(C); + Types.push_back(C->getType()); + unsigned CurSize = CGM.getTargetData().getTypeAllocSize(C->getType()); + unsigned TotalSize = CGM.getTargetData().getTypeAllocSize(Ty); + + assert(CurSize <= TotalSize && "Union size mismatch!"); + if (unsigned NumPadBytes = TotalSize - CurSize) { + const llvm::Type *Ty = llvm::Type::getInt8Ty(VMContext); + if (NumPadBytes > 1) + Ty = llvm::ArrayType::get(Ty, NumPadBytes); + + Elts.push_back(llvm::Constant::getNullValue(Ty)); + Types.push_back(Ty); + } + + llvm::StructType* STy = + llvm::StructType::get(C->getType()->getContext(), Types, false); + return llvm::ConstantStruct::get(STy, Elts); + } + case CastExpr::CK_NullToMemberPointer: + return CGM.EmitNullConstant(E->getType()); + + case CastExpr::CK_BaseToDerivedMemberPointer: { + Expr *SubExpr = E->getSubExpr(); + + const MemberPointerType *SrcTy = + SubExpr->getType()->getAs(); + const MemberPointerType *DestTy = + E->getType()->getAs(); + + const CXXRecordDecl *BaseClass = + cast(cast(SrcTy->getClass())->getDecl()); + const CXXRecordDecl *DerivedClass = + cast(cast(DestTy->getClass())->getDecl()); + + if (SrcTy->getPointeeType()->isFunctionProtoType()) { + llvm::Constant *C = + CGM.EmitConstantExpr(SubExpr, SubExpr->getType(), CGF); + if (!C) + return 0; + + llvm::ConstantStruct *CS = cast(C); + + // Check if we need to update the adjustment. + if (llvm::Constant *Offset = CGM.GetCXXBaseClassOffset(DerivedClass, + BaseClass)) { + llvm::Constant *Values[2]; + + Values[0] = CS->getOperand(0); + Values[1] = llvm::ConstantExpr::getAdd(CS->getOperand(1), Offset); + return llvm::ConstantStruct::get(CGM.getLLVMContext(), Values, 2, + /*Packed=*/false); + } + + return CS; + } + } + + default: { + // FIXME: This should be handled by the CK_NoOp cast kind. + // Explicit and implicit no-op casts + QualType Ty = E->getType(), SubTy = E->getSubExpr()->getType(); + if (CGM.getContext().hasSameUnqualifiedType(Ty, SubTy)) + return Visit(E->getSubExpr()); + + // Handle integer->integer casts for address-of-label differences. + if (Ty->isIntegerType() && SubTy->isIntegerType() && + CGF) { + llvm::Value *Src = Visit(E->getSubExpr()); + if (Src == 0) return 0; + + // Use EmitScalarConversion to perform the conversion. + return cast(CGF->EmitScalarConversion(Src, SubTy, Ty)); + } + + return 0; } - // Explicit and implicit no-op casts - QualType Ty = E->getType(), SubTy = E->getSubExpr()->getType(); - if (CGM.getContext().hasSameUnqualifiedType(Ty, SubTy)) { - return Visit(E->getSubExpr()); } - return 0; } llvm::Constant *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { @@ -79,7 +576,7 @@ public: unsigned NumInitElements = ILE->getNumInits(); // FIXME: Check for wide strings // FIXME: Check for NumInitElements exactly equal to 1?? - if (NumInitElements > 0 && + if (NumInitElements > 0 && (isa(ILE->getInit(0)) || isa(ILE->getInit(0))) && ILE->getType()->getArrayElementTypeNoTypeQual()->isCharType()) @@ -87,7 +584,7 @@ public: const llvm::Type *ElemTy = AType->getElementType(); unsigned NumElements = AType->getNumElements(); - // Initialising an array requires us to automatically + // Initialising an array requires us to automatically // initialise any elements that have not been initialised explicitly unsigned NumInitableElts = std::min(NumInitElements, NumElements); @@ -113,184 +610,20 @@ public: std::vector Types; for (unsigned i = 0; i < Elts.size(); ++i) Types.push_back(Elts[i]->getType()); - const llvm::StructType *SType = llvm::StructType::get(Types, true); + const llvm::StructType *SType = llvm::StructType::get(AType->getContext(), + Types, true); return llvm::ConstantStruct::get(SType, Elts); } - return llvm::ConstantArray::get(AType, Elts); - } - - void InsertBitfieldIntoStruct(std::vector& Elts, - FieldDecl* Field, Expr* E) { - // Calculate the value to insert - llvm::Constant *C = CGM.EmitConstantExpr(E, Field->getType(), CGF); - if (!C) - return; - - llvm::ConstantInt *CI = dyn_cast(C); - if (!CI) { - CGM.ErrorUnsupported(E, "bitfield initialization"); - return; - } - llvm::APInt V = CI->getValue(); - - // Calculate information about the relevant field - const llvm::Type* Ty = CI->getType(); - const llvm::TargetData &TD = CGM.getTypes().getTargetData(); - unsigned size = TD.getTypeAllocSizeInBits(Ty); - unsigned fieldOffset = CGM.getTypes().getLLVMFieldNo(Field) * size; - CodeGenTypes::BitFieldInfo bitFieldInfo = - CGM.getTypes().getBitFieldInfo(Field); - fieldOffset += bitFieldInfo.Begin; - - // Find where to start the insertion - // FIXME: This is O(n^2) in the number of bit-fields! - // FIXME: This won't work if the struct isn't completely packed! - unsigned offset = 0, i = 0; - while (offset < (fieldOffset & -8)) - offset += TD.getTypeAllocSizeInBits(Elts[i++]->getType()); - - // Advance over 0 sized elements (must terminate in bounds since - // the bitfield must have a size). - while (TD.getTypeAllocSizeInBits(Elts[i]->getType()) == 0) - ++i; - - // Promote the size of V if necessary - // FIXME: This should never occur, but currently it can because initializer - // constants are cast to bool, and because clang is not enforcing bitfield - // width limits. - if (bitFieldInfo.Size > V.getBitWidth()) - V.zext(bitFieldInfo.Size); - - // Insert the bits into the struct - // FIXME: This algorthm is only correct on X86! - // FIXME: THis algorthm assumes bit-fields only have byte-size elements! - unsigned bitsToInsert = bitFieldInfo.Size; - unsigned curBits = std::min(8 - (fieldOffset & 7), bitsToInsert); - unsigned byte = V.getLoBits(curBits).getZExtValue() << (fieldOffset & 7); - do { - llvm::Constant* byteC = llvm::ConstantInt::get(llvm::Type::Int8Ty, byte); - Elts[i] = llvm::ConstantExpr::getOr(Elts[i], byteC); - ++i; - V = V.lshr(curBits); - bitsToInsert -= curBits; - - if (!bitsToInsert) - break; - - curBits = bitsToInsert > 8 ? 8 : bitsToInsert; - byte = V.getLoBits(curBits).getZExtValue(); - } while (true); + return llvm::ConstantArray::get(AType, Elts); } llvm::Constant *EmitStructInitialization(InitListExpr *ILE) { - const llvm::StructType *SType = - cast(ConvertType(ILE->getType())); - RecordDecl *RD = ILE->getType()->getAsRecordType()->getDecl(); - std::vector Elts; - - // Initialize the whole structure to zero. - // FIXME: This doesn't handle member pointers correctly! - for (unsigned i = 0; i < SType->getNumElements(); ++i) { - const llvm::Type *FieldTy = SType->getElementType(i); - Elts.push_back(llvm::Constant::getNullValue(FieldTy)); - } - - // Copy initializer elements. Skip padding fields. - unsigned EltNo = 0; // Element no in ILE - bool RewriteType = false; - for (RecordDecl::field_iterator Field = RD->field_begin(), - FieldEnd = RD->field_end(); - EltNo < ILE->getNumInits() && Field != FieldEnd; ++Field) { - if (Field->isBitField()) { - if (!Field->getIdentifier()) - continue; - InsertBitfieldIntoStruct(Elts, *Field, ILE->getInit(EltNo)); - } else { - unsigned FieldNo = CGM.getTypes().getLLVMFieldNo(*Field); - llvm::Constant *C = CGM.EmitConstantExpr(ILE->getInit(EltNo), - Field->getType(), CGF); - if (!C) return 0; - RewriteType |= (C->getType() != Elts[FieldNo]->getType()); - Elts[FieldNo] = C; - } - EltNo++; - } - - if (RewriteType) { - // FIXME: Make this work for non-packed structs - assert(SType->isPacked() && "Cannot recreate unpacked structs"); - std::vector Types; - for (unsigned i = 0; i < Elts.size(); ++i) - Types.push_back(Elts[i]->getType()); - SType = llvm::StructType::get(Types, true); - } - - return llvm::ConstantStruct::get(SType, Elts); - } - - llvm::Constant *EmitUnion(llvm::Constant *C, const llvm::Type *Ty) { - if (!C) - return 0; - - // Build a struct with the union sub-element as the first member, - // and padded to the appropriate size - std::vector Elts; - std::vector Types; - Elts.push_back(C); - Types.push_back(C->getType()); - unsigned CurSize = CGM.getTargetData().getTypeAllocSize(C->getType()); - unsigned TotalSize = CGM.getTargetData().getTypeAllocSize(Ty); - while (CurSize < TotalSize) { - Elts.push_back(llvm::Constant::getNullValue(llvm::Type::Int8Ty)); - Types.push_back(llvm::Type::Int8Ty); - CurSize++; - } - - // This always generates a packed struct - // FIXME: Try to generate an unpacked struct when we can - llvm::StructType* STy = llvm::StructType::get(Types, true); - return llvm::ConstantStruct::get(STy, Elts); + return ConstStructBuilder::BuildStruct(CGM, CGF, ILE); } llvm::Constant *EmitUnionInitialization(InitListExpr *ILE) { - const llvm::Type *Ty = ConvertType(ILE->getType()); - - FieldDecl* curField = ILE->getInitializedFieldInUnion(); - if (!curField) { - // There's no field to initialize, so value-initialize the union. -#ifndef NDEBUG - // Make sure that it's really an empty and not a failure of - // semantic analysis. - RecordDecl *RD = ILE->getType()->getAsRecordType()->getDecl(); - for (RecordDecl::field_iterator Field = RD->field_begin(), - FieldEnd = RD->field_end(); - Field != FieldEnd; ++Field) - assert(Field->isUnnamedBitfield() && "Only unnamed bitfields allowed"); -#endif - return llvm::Constant::getNullValue(Ty); - } - - if (curField->isBitField()) { - // Create a dummy struct for bit-field insertion - unsigned NumElts = CGM.getTargetData().getTypeAllocSize(Ty); - llvm::Constant* NV = llvm::Constant::getNullValue(llvm::Type::Int8Ty); - std::vector Elts(NumElts, NV); - - InsertBitfieldIntoStruct(Elts, curField, ILE->getInit(0)); - const llvm::ArrayType *RetTy = - llvm::ArrayType::get(NV->getType(), NumElts); - return llvm::ConstantArray::get(RetTy, Elts); - } - - llvm::Constant *InitElem; - if (ILE->getNumInits() > 0) { - Expr *Init = ILE->getInit(0); - InitElem = CGM.EmitConstantExpr(Init, Init->getType(), CGF); - } else { - InitElem = CGM.EmitNullConstant(curField->getType()); - } - return EmitUnion(InitElem, Ty); + return ConstStructBuilder::BuildStruct(CGM, CGF, ILE); } llvm::Constant *EmitVectorInitialization(InitListExpr *ILE) { @@ -316,13 +649,13 @@ public: for (; i < NumElements; ++i) Elts.push_back(llvm::Constant::getNullValue(ElemTy)); - return llvm::ConstantVector::get(VType, Elts); + return llvm::ConstantVector::get(VType, Elts); } - + llvm::Constant *VisitImplicitValueInitExpr(ImplicitValueInitExpr* E) { return CGM.EmitNullConstant(E->getType()); } - + llvm::Constant *VisitInitListExpr(InitListExpr *ILE) { if (ILE->getType()->isScalarType()) { // We have a scalar in braces. Just use the first element. @@ -332,7 +665,7 @@ public: } return CGM.EmitNullConstant(ILE->getType()); } - + if (ILE->getType()->isArrayType()) return EmitArrayInitialization(ILE); @@ -353,11 +686,12 @@ public: llvm::Constant *VisitStringLiteral(StringLiteral *E) { assert(!E->getType()->isPointerType() && "Strings are always arrays"); - + // This must be a string initializing an array in a static initializer. // Don't emit it as the address of the string, emit the string data itself // as an inline array. - return llvm::ConstantArray::get(CGM.GetStringForStringLiteral(E), false); + return llvm::ConstantArray::get(VMContext, + CGM.GetStringForStringLiteral(E), false); } llvm::Constant *VisitObjCEncodeExpr(ObjCEncodeExpr *E) { @@ -367,13 +701,13 @@ public: std::string Str; CGM.getContext().getObjCEncodingForType(E->getEncodedType(), Str); const ConstantArrayType *CAT = cast(E->getType()); - + // Resize the string to the right size, adding zeros at the end, or // truncating as needed. Str.resize(CAT->getSize().getZExtValue(), '\0'); - return llvm::ConstantArray::get(Str, false); + return llvm::ConstantArray::get(VMContext, Str, false); } - + llvm::Constant *VisitUnaryExtension(const UnaryOperator *E) { return Visit(E->getSubExpr()); } @@ -394,20 +728,21 @@ public: llvm::Constant* C = Visit(CLE->getInitializer()); // FIXME: "Leaked" on failure. if (C) - C = new llvm::GlobalVariable(C->getType(), - E->getType().isConstQualified(), + C = new llvm::GlobalVariable(CGM.getModule(), C->getType(), + E->getType().isConstant(CGM.getContext()), llvm::GlobalValue::InternalLinkage, - C, ".compoundliteral", &CGM.getModule()); + C, ".compoundliteral", 0, false, + E->getType().getAddressSpace()); return C; } - case Expr::DeclRefExprClass: + case Expr::DeclRefExprClass: case Expr::QualifiedDeclRefExprClass: { NamedDecl *Decl = cast(E)->getDecl(); if (const FunctionDecl *FD = dyn_cast(Decl)) - return CGM.GetAddrOfFunction(GlobalDecl(FD)); + return CGM.GetAddrOfFunction(FD); if (const VarDecl* VD = dyn_cast(Decl)) { // We can never refer to a variable with local storage. - if (!VD->hasLocalStorage()) { + if (!VD->hasLocalStorage()) { if (VD->isFileVarDecl() || VD->hasExternalStorage()) return CGM.GetAddrOfGlobalVar(VD); else if (VD->isBlockVarDecl()) { @@ -430,21 +765,23 @@ public: case Expr::PredefinedExprClass: { // __func__/__FUNCTION__ -> "". __PRETTY_FUNCTION__ -> "top level". std::string Str; - if (cast(E)->getIdentType() == + if (cast(E)->getIdentType() == PredefinedExpr::PrettyFunction) Str = "top level"; - + return CGM.GetAddrOfConstantCString(Str, ".tmp"); } case Expr::AddrLabelExprClass: { assert(CGF && "Invalid address of label expression outside function."); - unsigned id = CGF->GetIDForAddrOfLabel(cast(E)->getLabel()); - llvm::Constant *C = llvm::ConstantInt::get(llvm::Type::Int32Ty, id); + unsigned id = + CGF->GetIDForAddrOfLabel(cast(E)->getLabel()); + llvm::Constant *C = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), id); return llvm::ConstantExpr::getIntToPtr(C, ConvertType(E->getType())); } case Expr::CallExprClass: { CallExpr* CE = cast(E); - if (CE->isBuiltinCall(CGM.getContext()) != + if (CE->isBuiltinCall(CGM.getContext()) != Builtin::BI__builtin___CFStringMakeConstantString) break; const Expr *Arg = CE->getArg(0)->IgnoreParenCasts(); @@ -466,23 +803,23 @@ public: return 0; } }; - + } // end anonymous namespace. llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, QualType DestType, CodeGenFunction *CGF) { Expr::EvalResult Result; - + bool Success = false; - + if (DestType->isReferenceType()) Success = E->EvaluateAsLValue(Result, Context); - else + else Success = E->Evaluate(Result, Context); - + if (Success) { - assert(!Result.HasSideEffects && + assert(!Result.HasSideEffects && "Constant expr should not have any side effects!"); switch (Result.Val.getKind()) { case APValue::Uninitialized: @@ -490,18 +827,17 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, return 0; case APValue::LValue: { const llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType); - llvm::Constant *Offset = - llvm::ConstantInt::get(llvm::Type::Int64Ty, + llvm::Constant *Offset = + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), Result.Val.getLValueOffset()); - + llvm::Constant *C; if (const Expr *LVBase = Result.Val.getLValueBase()) { C = ConstExprEmitter(*this, CGF).EmitLValue(const_cast(LVBase)); // Apply offset if necessary. if (!Offset->isNullValue()) { - const llvm::Type *Type = - llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *Type = llvm::Type::getInt8PtrTy(VMContext); llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(C, Type); Casted = llvm::ConstantExpr::getGetElementPtr(Casted, &Offset, 1); C = llvm::ConstantExpr::getBitCast(Casted, C->getType()); @@ -529,9 +865,10 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, } } case APValue::Int: { - llvm::Constant *C = llvm::ConstantInt::get(Result.Val.getInt()); - - if (C->getType() == llvm::Type::Int1Ty) { + llvm::Constant *C = llvm::ConstantInt::get(VMContext, + Result.Val.getInt()); + + if (C->getType() == llvm::Type::getInt1Ty(VMContext)) { const llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType()); C = llvm::ConstantExpr::getZExt(C, BoolTy); } @@ -539,32 +876,38 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, } case APValue::ComplexInt: { llvm::Constant *Complex[2]; - - Complex[0] = llvm::ConstantInt::get(Result.Val.getComplexIntReal()); - Complex[1] = llvm::ConstantInt::get(Result.Val.getComplexIntImag()); - - return llvm::ConstantStruct::get(Complex, 2); + + Complex[0] = llvm::ConstantInt::get(VMContext, + Result.Val.getComplexIntReal()); + Complex[1] = llvm::ConstantInt::get(VMContext, + Result.Val.getComplexIntImag()); + + // FIXME: the target may want to specify that this is packed. + return llvm::ConstantStruct::get(VMContext, Complex, 2, false); } case APValue::Float: - return llvm::ConstantFP::get(Result.Val.getFloat()); + return llvm::ConstantFP::get(VMContext, Result.Val.getFloat()); case APValue::ComplexFloat: { llvm::Constant *Complex[2]; - - Complex[0] = llvm::ConstantFP::get(Result.Val.getComplexFloatReal()); - Complex[1] = llvm::ConstantFP::get(Result.Val.getComplexFloatImag()); - - return llvm::ConstantStruct::get(Complex, 2); + + Complex[0] = llvm::ConstantFP::get(VMContext, + Result.Val.getComplexFloatReal()); + Complex[1] = llvm::ConstantFP::get(VMContext, + Result.Val.getComplexFloatImag()); + + // FIXME: the target may want to specify that this is packed. + return llvm::ConstantStruct::get(VMContext, Complex, 2, false); } case APValue::Vector: { llvm::SmallVector Inits; unsigned NumElts = Result.Val.getVectorLength(); - + for (unsigned i = 0; i != NumElts; ++i) { APValue &Elt = Result.Val.getVectorElt(i); if (Elt.isInt()) - Inits.push_back(llvm::ConstantInt::get(Elt.getInt())); + Inits.push_back(llvm::ConstantInt::get(VMContext, Elt.getInt())); else - Inits.push_back(llvm::ConstantFP::get(Elt.getFloat())); + Inits.push_back(llvm::ConstantFP::get(VMContext, Elt.getFloat())); } return llvm::ConstantVector::get(&Inits[0], Inits.size()); } @@ -572,15 +915,58 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, } llvm::Constant* C = ConstExprEmitter(*this, CGF).Visit(const_cast(E)); - if (C && C->getType() == llvm::Type::Int1Ty) { + if (C && C->getType() == llvm::Type::getInt1Ty(VMContext)) { const llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType()); C = llvm::ConstantExpr::getZExt(C, BoolTy); } return C; } +static inline bool isDataMemberPointerType(QualType T) { + if (const MemberPointerType *MPT = T->getAs()) + return !MPT->getPointeeType()->isFunctionType(); + + return false; +} + llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { - // Always return an LLVM null constant for now; this will change when we - // get support for IRGen of member pointers. - return llvm::Constant::getNullValue(getTypes().ConvertType(T)); + // No need to check for member pointers when not compiling C++. + if (!getContext().getLangOptions().CPlusPlus) + 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 Array(NumElements); + for (uint64_t i = 0; i != NumElements; ++i) + Array[i] = Element; + + const llvm::ArrayType *ATy = + cast(getTypes().ConvertTypeForMem(T)); + return llvm::ConstantArray::get(ATy, Array); + } + } + + if (const RecordType *RT = T->getAs()) { + 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!"); + } + } + + // FIXME: Handle structs that contain member pointers. + if (isDataMemberPointerType(T)) + return llvm::Constant::getAllOnesValue(getTypes().ConvertTypeForMem(T)); + + return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T)); } diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 2af0639f5ce3..cc81256032af 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenFunction.h" +#include "CGObjCRuntime.h" #include "CodeGenModule.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -49,20 +50,23 @@ class VISIBILITY_HIDDEN ScalarExprEmitter CodeGenFunction &CGF; CGBuilderTy &Builder; bool IgnoreResultAssign; - + llvm::LLVMContext &VMContext; public: ScalarExprEmitter(CodeGenFunction &cgf, bool ira=false) - : CGF(cgf), Builder(CGF.Builder), IgnoreResultAssign(ira) { + : CGF(cgf), Builder(CGF.Builder), IgnoreResultAssign(ira), + VMContext(cgf.getLLVMContext()) { } - + //===--------------------------------------------------------------------===// // Utilities //===--------------------------------------------------------------------===// bool TestAndClearIgnoreResultAssign() { - bool I = IgnoreResultAssign; IgnoreResultAssign = false; - return I; } + bool I = IgnoreResultAssign; + IgnoreResultAssign = false; + return I; + } const llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); } LValue EmitLValue(const Expr *E) { return CGF.EmitLValue(E); } @@ -70,25 +74,25 @@ public: Value *EmitLoadOfLValue(LValue LV, QualType T) { return CGF.EmitLoadOfLValue(LV, T).getScalarVal(); } - + /// EmitLoadOfLValue - Given an expression with complex type that represents a /// value l-value, this method emits the address of the l-value, then loads /// and returns the result. Value *EmitLoadOfLValue(const Expr *E) { return EmitLoadOfLValue(EmitLValue(E), E->getType()); } - + /// EmitConversionToBool - Convert the specified expression value to a /// boolean (i1) truth value. This is equivalent to "Val != 0". Value *EmitConversionToBool(Value *Src, QualType DstTy); - + /// EmitScalarConversion - Emit a conversion from the specified type to the /// specified destination type, both of which are LLVM scalar types. Value *EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy); /// EmitComplexToScalarConversion - Emit a conversion from the specified - /// complex type to the specified destination type, where the destination - /// type is an LLVM scalar type. + /// complex type to the specified destination type, where the destination type + /// is an LLVM scalar type. Value *EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, QualType SrcTy, QualType DstTy); @@ -106,10 +110,10 @@ public: // Leaves. Value *VisitIntegerLiteral(const IntegerLiteral *E) { - return llvm::ConstantInt::get(E->getValue()); + return llvm::ConstantInt::get(VMContext, E->getValue()); } Value *VisitFloatingLiteral(const FloatingLiteral *E) { - return llvm::ConstantFP::get(E->getValue()); + return llvm::ConstantFP::get(VMContext, E->getValue()); } Value *VisitCharacterLiteral(const CharacterLiteral *E) { return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); @@ -130,32 +134,33 @@ public: } Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E); Value *VisitAddrLabelExpr(const AddrLabelExpr *E) { - llvm::Value *V = - llvm::ConstantInt::get(llvm::Type::Int32Ty, + llvm::Value *V = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), CGF.GetIDForAddrOfLabel(E->getLabel())); - + return Builder.CreateIntToPtr(V, ConvertType(E->getType())); } - + // l-values. Value *VisitDeclRefExpr(DeclRefExpr *E) { if (const EnumConstantDecl *EC = dyn_cast(E->getDecl())) - return llvm::ConstantInt::get(EC->getInitVal()); + return llvm::ConstantInt::get(VMContext, EC->getInitVal()); return EmitLoadOfLValue(E); } - Value *VisitObjCSelectorExpr(ObjCSelectorExpr *E) { - return CGF.EmitObjCSelectorExpr(E); + Value *VisitObjCSelectorExpr(ObjCSelectorExpr *E) { + return CGF.EmitObjCSelectorExpr(E); } - Value *VisitObjCProtocolExpr(ObjCProtocolExpr *E) { - return CGF.EmitObjCProtocolExpr(E); + Value *VisitObjCProtocolExpr(ObjCProtocolExpr *E) { + return CGF.EmitObjCProtocolExpr(E); } - Value *VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { + Value *VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { return EmitLoadOfLValue(E); } Value *VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { return EmitLoadOfLValue(E); } - Value *VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) { + Value *VisitObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *E) { return EmitLoadOfLValue(E); } Value *VisitObjCMessageExpr(ObjCMessageExpr *E) { @@ -173,7 +178,7 @@ public: Value *VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { return EmitLValue(E).getAddress(); } - + Value *VisitPredefinedExpr(Expr *E) { return EmitLValue(E).getAddress(); } Value *VisitInitListExpr(InitListExpr *E) { @@ -181,66 +186,67 @@ public: (void)Ignore; assert (Ignore == false && "init list ignored"); unsigned NumInitElements = E->getNumInits(); - + if (E->hadArrayRangeDesignator()) { CGF.ErrorUnsupported(E, "GNU array range designator extension"); } - const llvm::VectorType *VType = + const llvm::VectorType *VType = dyn_cast(ConvertType(E->getType())); - + // We have a scalar in braces. Just use the first element. - if (!VType) + if (!VType) return Visit(E->getInit(0)); - + unsigned NumVectorElements = VType->getNumElements(); const llvm::Type *ElementType = VType->getElementType(); // Emit individual vector element stores. llvm::Value *V = llvm::UndefValue::get(VType); - + // Emit initializers unsigned i; for (i = 0; i < NumInitElements; ++i) { Value *NewV = Visit(E->getInit(i)); - Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); + Value *Idx = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), i); V = Builder.CreateInsertElement(V, NewV, Idx); } - + // Emit remaining default initializers for (/* Do not initialize i*/; i < NumVectorElements; ++i) { - Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); + Value *Idx = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), i); llvm::Value *NewV = llvm::Constant::getNullValue(ElementType); V = Builder.CreateInsertElement(V, NewV, Idx); } - + return V; } - + Value *VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) { return llvm::Constant::getNullValue(ConvertType(E->getType())); } - Value *VisitImplicitCastExpr(const ImplicitCastExpr *E); Value *VisitCastExpr(const CastExpr *E) { // Make sure to evaluate VLA bounds now so that we have them for later. if (E->getType()->isVariablyModifiedType()) CGF.EmitVLASize(E->getType()); - return EmitCastExpr(E->getSubExpr(), E->getType()); + return EmitCastExpr(E); } - Value *EmitCastExpr(const Expr *E, QualType T); + Value *EmitCastExpr(const CastExpr *E); Value *VisitCallExpr(const CallExpr *E) { if (E->getCallReturnType()->isReferenceType()) return EmitLoadOfLValue(E); - + return CGF.EmitCallExpr(E).getScalarVal(); } Value *VisitStmtExpr(const StmtExpr *E); Value *VisitBlockDeclRefExpr(const BlockDeclRefExpr *E); - + // Unary Operators. Value *VisitPrePostIncDec(const UnaryOperator *E, bool isInc, bool isPre); Value *VisitUnaryPostDec(const UnaryOperator *E) { @@ -273,22 +279,40 @@ public: return Visit(E->getSubExpr()); } Value *VisitUnaryOffsetOf(const UnaryOperator *E); - + // C++ Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { return Visit(DAE->getExpr()); } Value *VisitCXXThisExpr(CXXThisExpr *TE) { return CGF.LoadCXXThis(); - } - + } + Value *VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { return CGF.EmitCXXExprWithTemporaries(E).getScalarVal(); } Value *VisitCXXNewExpr(const CXXNewExpr *E) { return CGF.EmitCXXNewExpr(E); } - + Value *VisitCXXDeleteExpr(const CXXDeleteExpr *E) { + CGF.EmitCXXDeleteExpr(E); + return 0; + } + + Value *VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E) { + // C++ [expr.pseudo]p1: + // The result shall only be used as the operand for the function call + // operator (), and the result of such a call has type void. The only + // effect is the evaluation of the postfix-expression before the dot or + // arrow. + CGF.EmitScalarExpr(E->getBase()); + return 0; + } + + Value *VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) { + return llvm::Constant::getNullValue(ConvertType(E->getType())); + } + // Binary Operators. Value *EmitMul(const BinOpInfo &Ops) { if (CGF.getContext().getLangOptions().OverflowChecking @@ -355,7 +379,7 @@ public: VISITCOMP(EQ, ICMP_EQ , ICMP_EQ , FCMP_OEQ); VISITCOMP(NE, ICMP_NE , ICMP_NE , FCMP_UNE); #undef VISITCOMP - + Value *VisitBinAssign (const BinaryOperator *E); Value *VisitBinLAnd (const BinaryOperator *E); @@ -381,21 +405,30 @@ public: /// boolean (i1) truth value. This is equivalent to "Val != 0". Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) { assert(SrcType->isCanonical() && "EmitScalarConversion strips typedefs"); - + if (SrcType->isRealFloatingType()) { // Compare against 0.0 for fp scalars. llvm::Value *Zero = llvm::Constant::getNullValue(Src->getType()); return Builder.CreateFCmpUNE(Src, Zero, "tobool"); } - + + 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"); + } + assert((SrcType->isIntegerType() || isa(Src->getType())) && "Unknown scalar type to convert"); - + // Because of the type rules of C, we often end up computing a logical value, // then zero extending it to int, then wanting it as a logical value again. // Optimize this common case. if (llvm::ZExtInst *ZI = dyn_cast(Src)) { - if (ZI->getOperand(0)->getType() == llvm::Type::Int1Ty) { + if (ZI->getOperand(0)->getType() == + llvm::Type::getInt1Ty(CGF.getLLVMContext())) { Value *Result = ZI->getOperand(0); // If there aren't any more uses, zap the instruction to save space. // Note that there can be more uses, for example if this @@ -405,7 +438,7 @@ Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) { return Result; } } - + // Compare against an integer or pointer null. llvm::Value *Zero = llvm::Constant::getNullValue(Src->getType()); return Builder.CreateICmpNE(Src, Zero, "tobool"); @@ -418,61 +451,66 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, SrcType = CGF.getContext().getCanonicalType(SrcType); DstType = CGF.getContext().getCanonicalType(DstType); if (SrcType == DstType) return Src; - + if (DstType->isVoidType()) return 0; + llvm::LLVMContext &VMContext = CGF.getLLVMContext(); + // Handle conversions to bool first, they are special: comparisons against 0. if (DstType->isBooleanType()) return EmitConversionToBool(Src, SrcType); - + const llvm::Type *DstTy = ConvertType(DstType); // Ignore conversions like int -> uint. if (Src->getType() == DstTy) return Src; - // Handle pointer conversions next: pointers can only be converted - // to/from other pointers and integers. Check for pointer types in - // terms of LLVM, as some native types (like Obj-C id) may map to a - // pointer type. + // Handle pointer conversions next: pointers can only be converted to/from + // other pointers and integers. Check for pointer types in terms of LLVM, as + // some native types (like Obj-C id) may map to a pointer type. if (isa(DstTy)) { // The source value may be an integer, or a pointer. if (isa(Src->getType())) return Builder.CreateBitCast(Src, DstTy, "conv"); + assert(SrcType->isIntegerType() && "Not ptr->ptr or int->ptr conversion?"); // First, convert to the correct width so that we control the kind of // extension. - const llvm::Type *MiddleTy = llvm::IntegerType::get(CGF.LLVMPointerWidth); + const llvm::Type *MiddleTy = + llvm::IntegerType::get(VMContext, CGF.LLVMPointerWidth); bool InputSigned = SrcType->isSignedIntegerType(); llvm::Value* IntResult = Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv"); // Then, cast to pointer. return Builder.CreateIntToPtr(IntResult, DstTy, "conv"); } - + if (isa(Src->getType())) { // Must be an ptr to int cast. assert(isa(DstTy) && "not ptr->int?"); return Builder.CreatePtrToInt(Src, DstTy, "conv"); } - + // A scalar can be splatted to an extended vector of the same element type - if (DstType->isExtVectorType() && !isa(SrcType)) { + if (DstType->isExtVectorType() && !SrcType->isVectorType()) { // Cast the scalar to element type - QualType EltTy = DstType->getAsExtVectorType()->getElementType(); + QualType EltTy = DstType->getAs()->getElementType(); llvm::Value *Elt = EmitScalarConversion(Src, SrcType, EltTy); // Insert the element in element zero of an undef vector llvm::Value *UnV = llvm::UndefValue::get(DstTy); - llvm::Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); + llvm::Value *Idx = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0); UnV = Builder.CreateInsertElement(UnV, Elt, Idx, "tmp"); // Splat the element across to all elements llvm::SmallVector Args; unsigned NumElements = cast(DstTy)->getNumElements(); for (unsigned i = 0; i < NumElements; i++) - Args.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, 0)); - + Args.push_back(llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), 0)); + llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], NumElements); llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat"); return Yay; @@ -482,7 +520,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, if (isa(Src->getType()) || isa(DstTy)) return Builder.CreateBitCast(Src, DstTy, "conv"); - + // Finally, we have the arithmetic types: real int/float. if (isa(Src->getType())) { bool InputSigned = SrcType->isSignedIntegerType(); @@ -493,7 +531,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, else return Builder.CreateUIToFP(Src, DstTy, "conv"); } - + assert(Src->getType()->isFloatingPoint() && "Unknown real conversion"); if (isa(DstTy)) { if (DstType->isSignedIntegerType()) @@ -509,15 +547,15 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, return Builder.CreateFPExt(Src, DstTy, "conv"); } -/// EmitComplexToScalarConversion - Emit a conversion from the specified -/// complex type to the specified destination type, where the destination -/// type is an LLVM scalar type. +/// EmitComplexToScalarConversion - Emit a conversion from the specified complex +/// type to the specified destination type, where the destination type is an +/// LLVM scalar type. Value *ScalarExprEmitter:: EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, QualType SrcTy, QualType DstTy) { // Get the source element type. - SrcTy = SrcTy->getAsComplexType()->getElementType(); - + SrcTy = SrcTy->getAs()->getElementType(); + // Handle conversions to bool first, they are special: comparisons against 0. if (DstTy->isBooleanType()) { // Complex != 0 -> (Real != 0) | (Imag != 0) @@ -525,11 +563,11 @@ EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, Src.second = EmitScalarConversion(Src.second, SrcTy, DstTy); return Builder.CreateOr(Src.first, Src.second, "tobool"); } - + // C99 6.3.1.7p2: "When a value of complex type is converted to a real type, // the imaginary part of the complex value is discarded and the value of the // real part is converted according to the conversion rules for the - // corresponding real type. + // corresponding real type. return EmitScalarConversion(Src.first, SrcTy, DstTy); } @@ -565,72 +603,122 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { // so we can't get it as an lvalue. if (!E->getBase()->getType()->isVectorType()) return EmitLoadOfLValue(E); - + // Handle the vector case. The base must be a vector, the index must be an // integer value. Value *Base = Visit(E->getBase()); Value *Idx = Visit(E->getIdx()); bool IdxSigned = E->getIdx()->getType()->isSignedIntegerType(); - Idx = Builder.CreateIntCast(Idx, llvm::Type::Int32Ty, IdxSigned, + Idx = Builder.CreateIntCast(Idx, + llvm::Type::getInt32Ty(CGF.getLLVMContext()), + IdxSigned, "vecidxcast"); return Builder.CreateExtractElement(Base, Idx, "vecext"); } -/// VisitImplicitCastExpr - Implicit casts are the same as normal casts, but -/// also handle things like function to pointer-to-function decay, and array to -/// pointer decay. -Value *ScalarExprEmitter::VisitImplicitCastExpr(const ImplicitCastExpr *E) { - const Expr *Op = E->getSubExpr(); +// VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts +// have to handle a more broad range of conversions than explicit casts, as they +// handle things like function to ptr-to-function decay etc. +Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) { + const Expr *E = CE->getSubExpr(); + QualType DestTy = CE->getType(); + CastExpr::CastKind Kind = CE->getCastKind(); - // If this is due to array->pointer conversion, emit the array expression as - // an l-value. - if (Op->getType()->isArrayType()) { - Value *V = EmitLValue(Op).getAddress(); // Bitfields can't be arrays. + if (!DestTy->isVoidType()) + TestAndClearIgnoreResultAssign(); + + switch (Kind) { + default: + // FIXME: Assert here. + // assert(0 && "Unhandled cast kind!"); + break; + case CastExpr::CK_Unknown: + // FIXME: We should really assert here - Unknown casts should never get + // as far as to codegen. + break; + case CastExpr::CK_BitCast: { + Value *Src = Visit(const_cast(E)); + return Builder.CreateBitCast(Src, ConvertType(DestTy)); + } + case CastExpr::CK_ArrayToPointerDecay: { + assert(E->getType()->isArrayType() && + "Array to pointer decay must have array source type!"); + + Value *V = EmitLValue(E).getAddress(); // Bitfields can't be arrays. // Note that VLA pointers are always decayed, so we don't need to do // anything here. - if (!Op->getType()->isVariableArrayType()) { + if (!E->getType()->isVariableArrayType()) { assert(isa(V->getType()) && "Expected pointer"); assert(isa(cast(V->getType()) ->getElementType()) && "Expected pointer to array"); V = Builder.CreateStructGEP(V, 0, "arraydecay"); } - + // The resultant pointer type can be implicitly casted to other pointer // types as well (e.g. void*) and can be implicitly converted to integer. - const llvm::Type *DestTy = ConvertType(E->getType()); - if (V->getType() != DestTy) { - if (isa(DestTy)) - V = Builder.CreateBitCast(V, DestTy, "ptrconv"); + const llvm::Type *DestLTy = ConvertType(DestTy); + if (V->getType() != DestLTy) { + if (isa(DestLTy)) + V = Builder.CreateBitCast(V, DestLTy, "ptrconv"); else { - assert(isa(DestTy) && "Unknown array decay"); - V = Builder.CreatePtrToInt(V, DestTy, "ptrconv"); + assert(isa(DestLTy) && "Unknown array decay"); + V = Builder.CreatePtrToInt(V, DestLTy, "ptrconv"); } } return V; } + case CastExpr::CK_NullToMemberPointer: + return CGF.CGM.EmitNullConstant(DestTy); + + case CastExpr::CK_DerivedToBase: { + const RecordType *DerivedClassTy = + E->getType()->getAs()->getPointeeType()->getAs(); + CXXRecordDecl *DerivedClassDecl = + cast(DerivedClassTy->getDecl()); + + const RecordType *BaseClassTy = + DestTy->getAs()->getPointeeType()->getAs(); + CXXRecordDecl *BaseClassDecl = cast(BaseClassTy->getDecl()); + + Value *Src = Visit(const_cast(E)); - return EmitCastExpr(Op, E->getType()); -} + bool NullCheckValue = true; + + if (isa(E)) { + // We always assume that 'this' is never null. + NullCheckValue = false; + } else if (const ImplicitCastExpr *ICE = dyn_cast(CE)) { + // And that lvalue casts are never null. + if (ICE->isLvalueCast()) + NullCheckValue = false; + } + return CGF.GetAddressCXXOfBaseClass(Src, DerivedClassDecl, BaseClassDecl, + NullCheckValue); + } + case CastExpr::CK_IntegralToPointer: { + Value *Src = Visit(const_cast(E)); + return Builder.CreateIntToPtr(Src, ConvertType(DestTy)); + } -// VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts -// have to handle a more broad range of conversions than explicit casts, as they -// handle things like function to ptr-to-function decay etc. -Value *ScalarExprEmitter::EmitCastExpr(const Expr *E, QualType DestTy) { - if (!DestTy->isVoidType()) - TestAndClearIgnoreResultAssign(); + case CastExpr::CK_PointerToIntegral: { + Value *Src = Visit(const_cast(E)); + return Builder.CreatePtrToInt(Src, ConvertType(DestTy)); + } + + } // Handle cases where the source is an non-complex type. - + if (!CGF.hasAggregateLLVMType(E->getType())) { Value *Src = Visit(const_cast(E)); // Use EmitScalarConversion to perform the conversion. return EmitScalarConversion(Src, E->getType(), DestTy); } - + if (E->getType()->isAnyComplexType()) { // Handle cases where the source is a complex type. bool IgnoreImag = true; @@ -661,7 +749,10 @@ Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) { } Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) { - return Builder.CreateLoad(CGF.GetAddrOfBlockDecl(E), false, "tmp"); + llvm::Value *V = CGF.GetAddrOfBlockDecl(E); + if (E->getType().isObjCGCWeak()) + return CGF.CGM.getObjCRuntime().EmitObjCWeakRead(CGF, V); + return Builder.CreateLoad(V, false, "tmp"); } //===----------------------------------------------------------------------===// @@ -673,55 +764,80 @@ Value *ScalarExprEmitter::VisitPrePostIncDec(const UnaryOperator *E, LValue LV = EmitLValue(E->getSubExpr()); QualType ValTy = E->getSubExpr()->getType(); Value *InVal = CGF.EmitLoadOfLValue(LV, ValTy).getScalarVal(); - + + llvm::LLVMContext &VMContext = CGF.getLLVMContext(); + int AmountVal = isInc ? 1 : -1; if (ValTy->isPointerType() && - ValTy->getAsPointerType()->isVariableArrayType()) { + ValTy->getAs()->isVariableArrayType()) { // The amount of the addition/subtraction needs to account for the VLA size CGF.ErrorUnsupported(E, "VLA pointer inc/dec"); } Value *NextVal; - if (const llvm::PointerType *PT = + if (const llvm::PointerType *PT = dyn_cast(InVal->getType())) { - llvm::Constant *Inc =llvm::ConstantInt::get(llvm::Type::Int32Ty, AmountVal); + llvm::Constant *Inc = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), AmountVal); if (!isa(PT->getElementType())) { - NextVal = Builder.CreateGEP(InVal, Inc, "ptrincdec"); + QualType PTEE = ValTy->getPointeeType(); + if (const ObjCInterfaceType *OIT = + dyn_cast(PTEE)) { + // Handle interface types, which are not represented with a concrete type. + int size = CGF.getContext().getTypeSize(OIT) / 8; + if (!isInc) + size = -size; + Inc = llvm::ConstantInt::get(Inc->getType(), size); + const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext); + InVal = Builder.CreateBitCast(InVal, i8Ty); + NextVal = Builder.CreateGEP(InVal, Inc, "add.ptr"); + llvm::Value *lhs = LV.getAddress(); + lhs = Builder.CreateBitCast(lhs, llvm::PointerType::getUnqual(i8Ty)); + LV = LValue::MakeAddr(lhs, CGF.MakeQualifiers(ValTy)); + } else + NextVal = Builder.CreateInBoundsGEP(InVal, Inc, "ptrincdec"); } else { - const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext); NextVal = Builder.CreateBitCast(InVal, i8Ty, "tmp"); NextVal = Builder.CreateGEP(NextVal, Inc, "ptrincdec"); NextVal = Builder.CreateBitCast(NextVal, InVal->getType()); } - } else if (InVal->getType() == llvm::Type::Int1Ty && isInc) { + } else if (InVal->getType() == llvm::Type::getInt1Ty(VMContext) && isInc) { // Bool++ is an interesting case, due to promotion rules, we get: // Bool++ -> Bool = Bool+1 -> Bool = (int)Bool+1 -> // Bool = ((int)Bool+1) != 0 // An interesting aspect of this is that increment is always true. // Decrement does not have this property. - NextVal = llvm::ConstantInt::getTrue(); + NextVal = llvm::ConstantInt::getTrue(VMContext); } else if (isa(InVal->getType())) { NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal); - NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec"); + + // Signed integer overflow is undefined behavior. + if (ValTy->isSignedIntegerType()) + NextVal = Builder.CreateNSWAdd(InVal, NextVal, isInc ? "inc" : "dec"); + else + NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec"); } else { // Add the inc/dec to the real part. - if (InVal->getType() == llvm::Type::FloatTy) - NextVal = - llvm::ConstantFP::get(llvm::APFloat(static_cast(AmountVal))); - else if (InVal->getType() == llvm::Type::DoubleTy) - NextVal = - llvm::ConstantFP::get(llvm::APFloat(static_cast(AmountVal))); + if (InVal->getType()->isFloatTy()) + NextVal = + llvm::ConstantFP::get(VMContext, + llvm::APFloat(static_cast(AmountVal))); + else if (InVal->getType()->isDoubleTy()) + NextVal = + llvm::ConstantFP::get(VMContext, + llvm::APFloat(static_cast(AmountVal))); else { llvm::APFloat F(static_cast(AmountVal)); bool ignored; F.convert(CGF.Target.getLongDoubleFormat(), llvm::APFloat::rmTowardZero, &ignored); - NextVal = llvm::ConstantFP::get(F); + NextVal = llvm::ConstantFP::get(VMContext, F); } NextVal = Builder.CreateFAdd(InVal, NextVal, isInc ? "inc" : "dec"); } - + // Store the updated result through the lvalue. if (LV.isBitfield()) CGF.EmitStoreThroughBitfieldLValue(RValue::get(NextVal), LV, ValTy, @@ -752,12 +868,12 @@ Value *ScalarExprEmitter::VisitUnaryNot(const UnaryOperator *E) { Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) { // Compare operand to zero. Value *BoolVal = CGF.EvaluateExprAsBool(E->getSubExpr()); - + // Invert value. // TODO: Could dynamically modify easy computations here. For example, if // the operand is an icmp ne, turn into icmp eq. BoolVal = Builder.CreateNot(BoolVal, "lnot"); - + // ZExt result to the expr type. return Builder.CreateZExt(BoolVal, ConvertType(E->getType()), "lnot.ext"); } @@ -768,7 +884,7 @@ Value * ScalarExprEmitter::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { QualType TypeToSize = E->getTypeOfArgument(); if (E->isSizeOf()) { - if (const VariableArrayType *VAT = + if (const VariableArrayType *VAT = CGF.getContext().getAsVariableArrayType(TypeToSize)) { if (E->isArgumentType()) { // sizeof(type) - make sure to emit the VLA size. @@ -778,16 +894,16 @@ ScalarExprEmitter::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { // VLA, it is evaluated. CGF.EmitAnyExpr(E->getArgumentExpr()); } - + return CGF.GetVLASize(VAT); } } - // If this isn't sizeof(vla), the result must be constant; use the - // constant folding logic so we don't have to duplicate it here. + // If this isn't sizeof(vla), the result must be constant; use the constant + // folding logic so we don't have to duplicate it here. Expr::EvalResult Result; E->Evaluate(Result, CGF.getContext()); - return llvm::ConstantInt::get(Result.Val.getInt()); + return llvm::ConstantInt::get(VMContext, Result.Val.getInt()); } Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E) { @@ -800,7 +916,7 @@ Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) { Expr *Op = E->getSubExpr(); if (Op->getType()->isAnyComplexType()) return CGF.EmitComplexExpr(Op, true, false, true, false).second; - + // __imag on a scalar returns zero. Emit the subexpr to ensure side // effects are evaluated, but not the actual value. if (E->isLvalue(CGF.getContext()) == Expr::LV_Valid) @@ -810,8 +926,7 @@ Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) { return llvm::Constant::getNullValue(ConvertType(E->getType())); } -Value *ScalarExprEmitter::VisitUnaryOffsetOf(const UnaryOperator *E) -{ +Value *ScalarExprEmitter::VisitUnaryOffsetOf(const UnaryOperator *E) { Value* ResultAsPtr = EmitLValue(E->getSubExpr()).getAddress(); const llvm::Type* ResultType = ConvertType(E->getType()); return Builder.CreatePtrToInt(ResultAsPtr, ResultType, "offsetof"); @@ -839,10 +954,10 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, BinOpInfo OpInfo; if (E->getComputationResultType()->isAnyComplexType()) { - // This needs to go through the complex expression emitter, but - // it's a tad complicated to do that... I'm leaving it out for now. - // (Note that we do actually need the imaginary part of the RHS for - // multiplication and division.) + // This needs to go through the complex expression emitter, but it's a tad + // complicated to do that... I'm leaving it out for now. (Note that we do + // actually need the imaginary part of the RHS for multiplication and + // division.) CGF.ErrorUnsupported(E, "complex compound assignment"); return llvm::UndefValue::get(CGF.ConvertType(E->getType())); } @@ -857,17 +972,17 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, OpInfo.LHS = EmitLoadOfLValue(LHSLV, LHSTy); OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy, E->getComputationLHSType()); - + // Expand the binary operator. Value *Result = (this->*Func)(OpInfo); - + // Convert the result back to the LHS type. Result = EmitScalarConversion(Result, E->getComputationResultType(), LHSTy); - // Store the result value into the LHS lvalue. Bit-fields are - // handled specially because the result is altered by the store, - // i.e., [C99 6.5.16p1] 'An assignment expression has the value of - // the left operand after the assignment...'. + // Store the result value into the LHS lvalue. Bit-fields are handled + // specially because the result is altered by the store, i.e., [C99 6.5.16p1] + // 'An assignment expression has the value of the left operand after the + // assignment...'. if (LHSLV.isBitfield()) { if (!LHSLV.isVolatileQualified()) { CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy, @@ -949,31 +1064,31 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { Builder.SetInsertPoint(overflowBB); // Handler is: - // long long *__overflow_handler)(long long a, long long b, char op, + // long long *__overflow_handler)(long long a, long long b, char op, // char width) std::vector handerArgTypes; - handerArgTypes.push_back(llvm::Type::Int64Ty); - handerArgTypes.push_back(llvm::Type::Int64Ty); - handerArgTypes.push_back(llvm::Type::Int8Ty); - handerArgTypes.push_back(llvm::Type::Int8Ty); - llvm::FunctionType *handlerTy = llvm::FunctionType::get(llvm::Type::Int64Ty, - handerArgTypes, false); + handerArgTypes.push_back(llvm::Type::getInt64Ty(VMContext)); + handerArgTypes.push_back(llvm::Type::getInt64Ty(VMContext)); + handerArgTypes.push_back(llvm::Type::getInt8Ty(VMContext)); + handerArgTypes.push_back(llvm::Type::getInt8Ty(VMContext)); + llvm::FunctionType *handlerTy = llvm::FunctionType::get( + llvm::Type::getInt64Ty(VMContext), handerArgTypes, false); llvm::Value *handlerFunction = CGF.CGM.getModule().getOrInsertGlobal("__overflow_handler", llvm::PointerType::getUnqual(handlerTy)); handlerFunction = Builder.CreateLoad(handlerFunction); llvm::Value *handlerResult = Builder.CreateCall4(handlerFunction, - Builder.CreateSExt(Ops.LHS, llvm::Type::Int64Ty), - Builder.CreateSExt(Ops.RHS, llvm::Type::Int64Ty), - llvm::ConstantInt::get(llvm::Type::Int8Ty, OpID), - llvm::ConstantInt::get(llvm::Type::Int8Ty, + Builder.CreateSExt(Ops.LHS, llvm::Type::getInt64Ty(VMContext)), + Builder.CreateSExt(Ops.RHS, llvm::Type::getInt64Ty(VMContext)), + llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), OpID), + llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), cast(opTy)->getBitWidth())); handlerResult = Builder.CreateTrunc(handlerResult, opTy); Builder.CreateBr(continueBB); - + // Set up the continuation Builder.SetInsertPoint(continueBB); // Get the correct result @@ -986,31 +1101,39 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { } Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { - if (!Ops.Ty->isPointerType()) { + if (!Ops.Ty->isAnyPointerType()) { if (CGF.getContext().getLangOptions().OverflowChecking && Ops.Ty->isSignedIntegerType()) return EmitOverflowCheckedBinOp(Ops); - + if (Ops.LHS->getType()->isFPOrFPVector()) return Builder.CreateFAdd(Ops.LHS, Ops.RHS, "add"); - + + // Signed integer overflow is undefined behavior. + if (Ops.Ty->isSignedIntegerType()) + return Builder.CreateNSWAdd(Ops.LHS, Ops.RHS, "add"); + return Builder.CreateAdd(Ops.LHS, Ops.RHS, "add"); } - if (Ops.Ty->getAsPointerType()->isVariableArrayType()) { + if (Ops.Ty->isPointerType() && + Ops.Ty->getAs()->isVariableArrayType()) { // The amount of the addition needs to account for the VLA size CGF.ErrorUnsupported(Ops.E, "VLA pointer addition"); } Value *Ptr, *Idx; Expr *IdxExp; - const PointerType *PT; - if ((PT = Ops.E->getLHS()->getType()->getAsPointerType())) { + const PointerType *PT = Ops.E->getLHS()->getType()->getAs(); + const ObjCObjectPointerType *OPT = + Ops.E->getLHS()->getType()->getAs(); + if (PT || OPT) { Ptr = Ops.LHS; Idx = Ops.RHS; IdxExp = Ops.E->getRHS(); - } else { // int + pointer - PT = Ops.E->getRHS()->getType()->getAsPointerType(); - assert(PT && "Invalid add expr"); + } else { // int + pointer + PT = Ops.E->getRHS()->getType()->getAs(); + OPT = Ops.E->getRHS()->getType()->getAs(); + assert((PT || OPT) && "Invalid add expr"); Ptr = Ops.RHS; Idx = Ops.LHS; IdxExp = Ops.E->getLHS(); @@ -1020,38 +1143,37 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { if (Width < CGF.LLVMPointerWidth) { // Zero or sign extend the pointer value based on whether the index is // signed or not. - const llvm::Type *IdxType = llvm::IntegerType::get(CGF.LLVMPointerWidth); + const llvm::Type *IdxType = + llvm::IntegerType::get(VMContext, CGF.LLVMPointerWidth); if (IdxExp->getType()->isSignedIntegerType()) Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext"); else Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext"); } - - const QualType ElementType = PT->getPointeeType(); - // Handle interface types, which are not represented with a concrete - // type. + const QualType ElementType = PT ? PT->getPointeeType() : OPT->getPointeeType(); + // Handle interface types, which are not represented with a concrete type. if (const ObjCInterfaceType *OIT = dyn_cast(ElementType)) { - llvm::Value *InterfaceSize = + llvm::Value *InterfaceSize = llvm::ConstantInt::get(Idx->getType(), CGF.getContext().getTypeSize(OIT) / 8); Idx = Builder.CreateMul(Idx, InterfaceSize); - const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext); Value *Casted = Builder.CreateBitCast(Ptr, i8Ty); Value *Res = Builder.CreateGEP(Casted, Idx, "add.ptr"); return Builder.CreateBitCast(Res, Ptr->getType()); - } + } - // Explicitly handle GNU void* and function pointer arithmetic - // extensions. The GNU void* casts amount to no-ops since our void* - // type is i8*, but this is future proof. + // Explicitly handle GNU void* and function pointer arithmetic extensions. The + // GNU void* casts amount to no-ops since our void* type is i8*, but this is + // future proof. if (ElementType->isVoidType() || ElementType->isFunctionType()) { - const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext); Value *Casted = Builder.CreateBitCast(Ptr, i8Ty); Value *Res = Builder.CreateGEP(Casted, Idx, "add.ptr"); return Builder.CreateBitCast(Res, Ptr->getType()); - } - - return Builder.CreateGEP(Ptr, Idx, "add.ptr"); + } + + return Builder.CreateInBoundsGEP(Ptr, Idx, "add.ptr"); } Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { @@ -1065,7 +1187,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub"); } - if (Ops.E->getLHS()->getType()->getAsPointerType()->isVariableArrayType()) { + if (Ops.E->getLHS()->getType()->isPointerType() && + Ops.E->getLHS()->getType()->getAs()->isVariableArrayType()) { // The amount of the addition needs to account for the VLA size for // ptr-int // The amount of the division needs to account for the VLA size for @@ -1074,7 +1197,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { } const QualType LHSType = Ops.E->getLHS()->getType(); - const QualType LHSElementType = LHSType->getAsPointerType()->getPointeeType(); + const QualType LHSElementType = LHSType->getPointeeType(); if (!isa(Ops.RHS->getType())) { // pointer - int Value *Idx = Ops.RHS; @@ -1082,7 +1205,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { if (Width < CGF.LLVMPointerWidth) { // Zero or sign extend the pointer value based on whether the index is // signed or not. - const llvm::Type *IdxType = llvm::IntegerType::get(CGF.LLVMPointerWidth); + const llvm::Type *IdxType = + llvm::IntegerType::get(VMContext, CGF.LLVMPointerWidth); if (Ops.E->getRHS()->getType()->isSignedIntegerType()) Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext"); else @@ -1090,36 +1214,35 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { } Idx = Builder.CreateNeg(Idx, "sub.ptr.neg"); - // Handle interface types, which are not represented with a concrete - // type. - if (const ObjCInterfaceType *OIT = + // Handle interface types, which are not represented with a concrete type. + if (const ObjCInterfaceType *OIT = dyn_cast(LHSElementType)) { - llvm::Value *InterfaceSize = + llvm::Value *InterfaceSize = llvm::ConstantInt::get(Idx->getType(), CGF.getContext().getTypeSize(OIT) / 8); Idx = Builder.CreateMul(Idx, InterfaceSize); - const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext); Value *LHSCasted = Builder.CreateBitCast(Ops.LHS, i8Ty); Value *Res = Builder.CreateGEP(LHSCasted, Idx, "add.ptr"); return Builder.CreateBitCast(Res, Ops.LHS->getType()); - } + } // Explicitly handle GNU void* and function pointer arithmetic - // extensions. The GNU void* casts amount to no-ops since our - // void* type is i8*, but this is future proof. + // extensions. The GNU void* casts amount to no-ops since our void* type is + // i8*, but this is future proof. if (LHSElementType->isVoidType() || LHSElementType->isFunctionType()) { - const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext); Value *LHSCasted = Builder.CreateBitCast(Ops.LHS, i8Ty); Value *Res = Builder.CreateGEP(LHSCasted, Idx, "sub.ptr"); return Builder.CreateBitCast(Res, Ops.LHS->getType()); - } - - return Builder.CreateGEP(Ops.LHS, Idx, "sub.ptr"); + } + + return Builder.CreateInBoundsGEP(Ops.LHS, Idx, "sub.ptr"); } else { // pointer - pointer Value *LHS = Ops.LHS; Value *RHS = Ops.RHS; - + uint64_t ElementSize; // Handle GCC extension for pointer arithmetic on void* and function pointer @@ -1129,28 +1252,21 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { } else { ElementSize = CGF.getContext().getTypeSize(LHSElementType) / 8; } - + const llvm::Type *ResultType = ConvertType(Ops.Ty); LHS = Builder.CreatePtrToInt(LHS, ResultType, "sub.ptr.lhs.cast"); RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast"); Value *BytesBetween = Builder.CreateSub(LHS, RHS, "sub.ptr.sub"); - + // Optimize out the shift for element size of 1. if (ElementSize == 1) return BytesBetween; - - // HACK: LLVM doesn't have an divide instruction that 'knows' there is no - // remainder. As such, we handle common power-of-two cases here to generate - // better code. See PR2247. - if (llvm::isPowerOf2_64(ElementSize)) { - Value *ShAmt = - llvm::ConstantInt::get(ResultType, llvm::Log2_64(ElementSize)); - return Builder.CreateAShr(BytesBetween, ShAmt, "sub.ptr.shr"); - } - - // Otherwise, do a full sdiv. + + // Otherwise, do a full sdiv. This uses the "exact" form of sdiv, since + // pointer difference in C is only defined in the case where both operands + // are pointing to elements of an array. Value *BytesPerElt = llvm::ConstantInt::get(ResultType, ElementSize); - return Builder.CreateSDiv(BytesBetween, BytesPerElt, "sub.ptr.div"); + return Builder.CreateExactSDiv(BytesBetween, BytesPerElt, "sub.ptr.div"); } } @@ -1160,7 +1276,7 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) { Value *RHS = Ops.RHS; if (Ops.LHS->getType() != RHS->getType()) RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); - + return Builder.CreateShl(Ops.LHS, RHS, "shl"); } @@ -1170,7 +1286,7 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) { Value *RHS = Ops.RHS; if (Ops.LHS->getType() != RHS->getType()) RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); - + if (Ops.Ty->isUnsignedIntegerType()) return Builder.CreateLShr(Ops.LHS, RHS, "shr"); return Builder.CreateAShr(Ops.LHS, RHS, "shr"); @@ -1181,11 +1297,11 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, TestAndClearIgnoreResultAssign(); Value *Result; QualType LHSTy = E->getLHS()->getType(); - if (!LHSTy->isAnyComplexType() && !LHSTy->isVectorType()) { + if (!LHSTy->isAnyComplexType()) { Value *LHS = Visit(E->getLHS()); Value *RHS = Visit(E->getRHS()); - - if (LHS->getType()->isFloatingPoint()) { + + if (LHS->getType()->isFPOrFPVector()) { Result = Builder.CreateFCmp((llvm::CmpInst::Predicate)FCmpOpc, LHS, RHS, "cmp"); } else if (LHSTy->isSignedIntegerType()) { @@ -1196,29 +1312,19 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, Result = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, LHS, RHS, "cmp"); } - } else if (LHSTy->isVectorType()) { - Value *LHS = Visit(E->getLHS()); - Value *RHS = Visit(E->getRHS()); - - if (LHS->getType()->isFPOrFPVector()) { - Result = Builder.CreateVFCmp((llvm::CmpInst::Predicate)FCmpOpc, - LHS, RHS, "cmp"); - } else if (LHSTy->isUnsignedIntegerType()) { - Result = Builder.CreateVICmp((llvm::CmpInst::Predicate)UICmpOpc, - LHS, RHS, "cmp"); - } else { - // Signed integers and pointers. - Result = Builder.CreateVICmp((llvm::CmpInst::Predicate)SICmpOpc, - LHS, RHS, "cmp"); - } - return Result; + + // If this is a vector comparison, sign extend the result to the appropriate + // vector integer type and return it (don't convert to bool). + if (LHSTy->isVectorType()) + return Builder.CreateSExt(Result, ConvertType(E->getType()), "sext"); + } else { // Complex Comparison: can only be an equality comparison. CodeGenFunction::ComplexPairTy LHS = CGF.EmitComplexExpr(E->getLHS()); CodeGenFunction::ComplexPairTy RHS = CGF.EmitComplexExpr(E->getRHS()); - - QualType CETy = LHSTy->getAsComplexType()->getElementType(); - + + QualType CETy = LHSTy->getAs()->getElementType(); + Value *ResultR, *ResultI; if (CETy->isRealFloatingType()) { ResultR = Builder.CreateFCmp((llvm::FCmpInst::Predicate)FCmpOpc, @@ -1233,7 +1339,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, ResultI = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, LHS.second, RHS.second, "cmp.i"); } - + if (E->getOpcode() == BinaryOperator::EQ) { Result = Builder.CreateAnd(ResultR, ResultI, "and.ri"); } else { @@ -1253,7 +1359,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { // improve codegen just a little. Value *RHS = Visit(E->getRHS()); LValue LHS = EmitLValue(E->getLHS()); - + // Store the value into the LHS. Bit-fields are handled specially // because the result is altered by the store, i.e., [C99 6.5.16p1] // 'An assignment expression has the value of the left operand after @@ -1281,12 +1387,12 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { // ZExt result to int. return Builder.CreateZExt(RHSCond, CGF.LLVMIntTy, "land.ext"); } - + // 0 && RHS: If it is safe, just elide the RHS, and return 0. if (!CGF.ContainsLabel(E->getRHS())) return llvm::Constant::getNullValue(CGF.LLVMIntTy); } - + llvm::BasicBlock *ContBlock = CGF.createBasicBlock("land.end"); llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("land.rhs"); @@ -1296,17 +1402,18 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { // Any edges into the ContBlock are now from an (indeterminate number of) // edges from this first condition. All of these values will be false. Start // setting up the PHI node in the Cont Block for this. - llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::Int1Ty, "", ContBlock); + llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::getInt1Ty(VMContext), + "", ContBlock); PN->reserveOperandSpace(2); // Normal case, two inputs. for (llvm::pred_iterator PI = pred_begin(ContBlock), PE = pred_end(ContBlock); PI != PE; ++PI) - PN->addIncoming(llvm::ConstantInt::getFalse(), *PI); - + PN->addIncoming(llvm::ConstantInt::getFalse(VMContext), *PI); + CGF.PushConditionalTempDestruction(); CGF.EmitBlock(RHSBlock); Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); CGF.PopConditionalTempDestruction(); - + // Reaquire the RHS block, as there may be subblocks inserted. RHSBlock = Builder.GetInsertBlock(); @@ -1314,7 +1421,7 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { // into the phi node for the edge with the value of RHSCond. CGF.EmitBlock(ContBlock); PN->addIncoming(RHSCond, RHSBlock); - + // ZExt result to int. return Builder.CreateZExt(PN, CGF.LLVMIntTy, "land.ext"); } @@ -1328,43 +1435,44 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) { // ZExt result to int. return Builder.CreateZExt(RHSCond, CGF.LLVMIntTy, "lor.ext"); } - + // 1 || RHS: If it is safe, just elide the RHS, and return 1. if (!CGF.ContainsLabel(E->getRHS())) return llvm::ConstantInt::get(CGF.LLVMIntTy, 1); } - + llvm::BasicBlock *ContBlock = CGF.createBasicBlock("lor.end"); llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("lor.rhs"); - + // Branch on the LHS first. If it is true, go to the success (cont) block. CGF.EmitBranchOnBoolExpr(E->getLHS(), ContBlock, RHSBlock); // Any edges into the ContBlock are now from an (indeterminate number of) // edges from this first condition. All of these values will be true. Start // setting up the PHI node in the Cont Block for this. - llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::Int1Ty, "", ContBlock); + llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::getInt1Ty(VMContext), + "", ContBlock); PN->reserveOperandSpace(2); // Normal case, two inputs. for (llvm::pred_iterator PI = pred_begin(ContBlock), PE = pred_end(ContBlock); PI != PE; ++PI) - PN->addIncoming(llvm::ConstantInt::getTrue(), *PI); + PN->addIncoming(llvm::ConstantInt::getTrue(VMContext), *PI); CGF.PushConditionalTempDestruction(); // Emit the RHS condition as a bool value. CGF.EmitBlock(RHSBlock); Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); - + CGF.PopConditionalTempDestruction(); - + // Reaquire the RHS block, as there may be subblocks inserted. RHSBlock = Builder.GetInsertBlock(); - + // Emit an unconditional branch from this block to ContBlock. Insert an entry // into the phi node for the edge with the value of RHSCond. CGF.EmitBlock(ContBlock); PN->addIncoming(RHSCond, RHSBlock); - + // ZExt result to int. return Builder.CreateZExt(PN, CGF.LLVMIntTy, "lor.ext"); } @@ -1386,19 +1494,19 @@ Value *ScalarExprEmitter::VisitBinComma(const BinaryOperator *E) { static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E) { if (const ParenExpr *PE = dyn_cast(E)) return isCheapEnoughToEvaluateUnconditionally(PE->getSubExpr()); - + // TODO: Allow anything we can constant fold to an integer or fp constant. if (isa(E) || isa(E) || isa(E)) return true; - + // Non-volatile automatic variables too, to get "cond ? X : Y" where // X and Y are local variables. if (const DeclRefExpr *DRE = dyn_cast(E)) if (const VarDecl *VD = dyn_cast(DRE->getDecl())) if (VD->hasLocalStorage() && !VD->getType().isVolatileQualified()) return true; - + return false; } @@ -1412,7 +1520,7 @@ VisitConditionalOperator(const ConditionalOperator *E) { Expr *Live = E->getLHS(), *Dead = E->getRHS(); if (Cond == -1) std::swap(Live, Dead); - + // If the dead side doesn't have labels we need, and if the Live side isn't // the gnu missing ?: extension (which we could handle, but don't bother // to), just emit the Live part. @@ -1420,8 +1528,8 @@ VisitConditionalOperator(const ConditionalOperator *E) { Live) // Live part isn't missing. return Visit(Live); } - - + + // If this is a really simple expression (like x ? 4 : 5), emit this as a // select instead of as control flow. We can only do this if it is cheap and // safe to evaluate the LHS and RHS unconditionally. @@ -1432,15 +1540,15 @@ VisitConditionalOperator(const ConditionalOperator *E) { llvm::Value *RHS = Visit(E->getRHS()); return Builder.CreateSelect(CondV, LHS, RHS, "cond"); } - - + + llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true"); llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false"); llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end"); Value *CondVal = 0; - // If we don't have the GNU missing condition extension, emit a branch on - // bool the normal way. + // If we don't have the GNU missing condition extension, emit a branch on bool + // the normal way. if (E->getLHS()) { // Otherwise, just use EmitBranchOnBoolExpr to get small and simple code for // the branch on bool. @@ -1450,7 +1558,7 @@ VisitConditionalOperator(const ConditionalOperator *E) { // convert it to bool the hard way. We do this explicitly because we need // the unconverted value for the missing middle value of the ?:. CondVal = CGF.EmitScalarExpr(E->getCond()); - + // In some cases, EmitScalarConversion will delete the "CondVal" expression // if there are no extra uses (an optimization). Inhibit this by making an // extra dead use, because we're going to add a use of CondVal later. We @@ -1458,7 +1566,7 @@ VisitConditionalOperator(const ConditionalOperator *E) { // away. This leaves dead code, but the ?: extension isn't common. new llvm::BitCastInst(CondVal, CondVal->getType(), "dummy?:holder", Builder.GetInsertBlock()); - + Value *CondBoolVal = CGF.EmitScalarConversion(CondVal, E->getCond()->getType(), CGF.getContext().BoolTy); @@ -1467,33 +1575,33 @@ VisitConditionalOperator(const ConditionalOperator *E) { CGF.PushConditionalTempDestruction(); CGF.EmitBlock(LHSBlock); - + // Handle the GNU extension for missing LHS. Value *LHS; if (E->getLHS()) LHS = Visit(E->getLHS()); else // Perform promotions, to handle cases like "short ?: int" LHS = EmitScalarConversion(CondVal, E->getCond()->getType(), E->getType()); - + CGF.PopConditionalTempDestruction(); LHSBlock = Builder.GetInsertBlock(); CGF.EmitBranch(ContBlock); - + CGF.PushConditionalTempDestruction(); CGF.EmitBlock(RHSBlock); - + Value *RHS = Visit(E->getRHS()); CGF.PopConditionalTempDestruction(); RHSBlock = Builder.GetInsertBlock(); CGF.EmitBranch(ContBlock); - + CGF.EmitBlock(ContBlock); - + if (!LHS || !RHS) { assert(E->getType()->isVoidType() && "Non-void value should have a value"); return 0; } - + // Create a PHI node for the real part. llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), "cond"); PN->reserveOperandSpace(2); @@ -1511,7 +1619,7 @@ Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { llvm::Value *ArgPtr = CGF.EmitVAArg(ArgValue, VE->getType()); // If EmitVAArg fails, we fall back to the LLVM instruction. - if (!ArgPtr) + if (!ArgPtr) return Builder.CreateVAArg(ArgValue, ConvertType(VE->getType())); // FIXME Volatility. @@ -1526,12 +1634,12 @@ Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *BE) { // Entry Point into this File //===----------------------------------------------------------------------===// -/// EmitScalarExpr - Emit the computation of the specified expression of -/// scalar type, ignoring the result. +/// EmitScalarExpr - Emit the computation of the specified expression of scalar +/// type, ignoring the result. Value *CodeGenFunction::EmitScalarExpr(const Expr *E, bool IgnoreResultAssign) { assert(E && !hasAggregateLLVMType(E->getType()) && "Invalid scalar expression to emit"); - + return ScalarExprEmitter(*this, IgnoreResultAssign) .Visit(const_cast(E)); } @@ -1545,9 +1653,9 @@ Value *CodeGenFunction::EmitScalarConversion(Value *Src, QualType SrcTy, return ScalarExprEmitter(*this).EmitScalarConversion(Src, SrcTy, DstTy); } -/// EmitComplexToScalarConversion - Emit a conversion from the specified -/// complex type to the specified destination type, where the destination -/// type is an LLVM scalar type. +/// EmitComplexToScalarConversion - Emit a conversion from the specified complex +/// type to the specified destination type, where the destination type is an +/// LLVM scalar type. Value *CodeGenFunction::EmitComplexToScalarConversion(ComplexPairTy Src, QualType SrcTy, QualType DstTy) { @@ -1560,38 +1668,40 @@ Value *CodeGenFunction::EmitComplexToScalarConversion(ComplexPairTy Src, Value *CodeGenFunction::EmitShuffleVector(Value* V1, Value *V2, ...) { assert(V1->getType() == V2->getType() && "Vector operands must be of the same type"); - unsigned NumElements = + unsigned NumElements = cast(V1->getType())->getNumElements(); - + va_list va; va_start(va, V2); - + llvm::SmallVector Args; for (unsigned i = 0; i < NumElements; i++) { int n = va_arg(va, int); - assert(n >= 0 && n < (int)NumElements * 2 && + assert(n >= 0 && n < (int)NumElements * 2 && "Vector shuffle index out of bounds!"); - Args.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, n)); + Args.push_back(llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), n)); } - + const char *Name = va_arg(va, const char *); va_end(va); - + llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], NumElements); - + return Builder.CreateShuffleVector(V1, V2, Mask, Name); } -llvm::Value *CodeGenFunction::EmitVector(llvm::Value * const *Vals, +llvm::Value *CodeGenFunction::EmitVector(llvm::Value * const *Vals, unsigned NumVals, bool isSplat) { llvm::Value *Vec = llvm::UndefValue::get(llvm::VectorType::get(Vals[0]->getType(), NumVals)); - + for (unsigned i = 0, e = NumVals; i != e; ++i) { llvm::Value *Val = isSplat ? Vals[0] : Vals[i]; - llvm::Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); + llvm::Value *Idx = llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), i); Vec = Builder.CreateInsertElement(Vec, Val, Idx, "tmp"); } - - return Vec; + + return Vec; } diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 33cb5bca3869..cadba328bf12 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -24,7 +24,7 @@ using namespace clang; using namespace CodeGen; /// Emits an instance of NSConstantString representing the object. -llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E) +llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E) { llvm::Constant *C = CGM.getObjCRuntime().GenerateConstantString(E); // FIXME: This bitcast should just be made an invariant on the Runtime. @@ -50,7 +50,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { // Only the lookup mechanism and first two arguments of the method // implementation vary between runtimes. We can get the receiver and // arguments in generic code. - + CGObjCRuntime &Runtime = CGM.getObjCRuntime(); const Expr *ReceiverExpr = E->getReceiver(); bool isSuperMessage = false; @@ -70,7 +70,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { } else { Receiver = Runtime.GetClass(Builder, OID); } - + isClassMessage = true; } else if (isa(E->getReceiver())) { isSuperMessage = true; @@ -81,7 +81,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { CallArgList Args; EmitCallArgs(Args, E->getMethodDecl(), E->arg_begin(), E->arg_end()); - + if (isSuperMessage) { // super is only valid in an Objective-C method const ObjCMethodDecl *OMD = cast(CurFuncDecl); @@ -92,9 +92,11 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { isCategoryImpl, Receiver, isClassMessage, - Args); + Args, + E->getMethodDecl()); } - return Runtime.GenerateMessageSend(*this, E->getType(), E->getSelector(), + + return Runtime.GenerateMessageSend(*this, E->getType(), E->getSelector(), Receiver, isClassMessage, Args, E->getMethodDecl()); } @@ -110,7 +112,7 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD, const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(OMD); CGM.SetInternalFunctionAttributes(OMD, Fn, FI); - Args.push_back(std::make_pair(OMD->getSelfDecl(), + Args.push_back(std::make_pair(OMD->getSelfDecl(), OMD->getSelfDecl()->getType())); Args.push_back(std::make_pair(OMD->getCmdDecl(), OMD->getCmdDecl()->getType())); @@ -123,10 +125,10 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD, } /// Generate an Objective-C method. An Objective-C method is a C function with -/// its pointer, name, and types registered in the class struture. +/// its pointer, name, and types registered in the class struture. void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) { // Check if we should generate debug info for this method. - if (CGM.getDebugInfo() && !OMD->hasAttr()) + if (CGM.getDebugInfo() && !OMD->hasAttr()) DebugInfo = CGM.getDebugInfo(); StartObjCMethod(OMD, OMD->getClassInterface()); EmitStmt(OMD->getBody()); @@ -159,9 +161,9 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) && (PD->getSetterKind() == ObjCPropertyDecl::Copy || PD->getSetterKind() == ObjCPropertyDecl::Retain)) { - llvm::Value *GetPropertyFn = + llvm::Value *GetPropertyFn = CGM.getObjCRuntime().GetPropertyGetFunction(); - + if (!GetPropertyFn) { CGM.ErrorUnsupported(PID, "Obj-C getter requiring atomic copy"); FinishFunction(); @@ -175,7 +177,7 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, ValueDecl *Cmd = OMD->getCmdDecl(); llvm::Value *CmdVal = Builder.CreateLoad(LocalDeclMap[Cmd], "cmd"); QualType IdTy = getContext().getObjCIdType(); - llvm::Value *SelfAsId = + llvm::Value *SelfAsId = Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy)); llvm::Value *Offset = EmitIvarOffset(IMP->getClassInterface(), Ivar); llvm::Value *True = @@ -187,24 +189,23 @@ 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), GetPropertyFn, 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 // aggregates. - RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(), + RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(), Types.ConvertType(PD->getType()))); EmitReturnOfRValue(RV, PD->getType()); } else { LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0); if (hasAggregateLLVMType(Ivar->getType())) { EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType()); - } - else { + } else { CodeGenTypes &Types = CGM.getTypes(); RValue RV = EmitLoadOfLValue(LV, Ivar->getType()); RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(), - Types.ConvertType(PD->getType()))); + Types.ConvertType(PD->getType()))); EmitReturnOfRValue(RV, PD->getType()); } } @@ -227,7 +228,7 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, StartObjCMethod(OMD, IMP->getClassInterface()); bool IsCopy = PD->getSetterKind() == ObjCPropertyDecl::Copy; - bool IsAtomic = + bool IsAtomic = !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic); // Determine if we should use an objc_setProperty call for @@ -237,16 +238,16 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, if (IsCopy || (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly && PD->getSetterKind() == ObjCPropertyDecl::Retain)) { - llvm::Value *SetPropertyFn = + llvm::Value *SetPropertyFn = CGM.getObjCRuntime().GetPropertySetFunction(); - + if (!SetPropertyFn) { CGM.ErrorUnsupported(PID, "Obj-C getter requiring atomic copy"); FinishFunction(); return; } - - // Emit objc_setProperty((id) self, _cmd, offset, arg, + + // Emit objc_setProperty((id) self, _cmd, offset, arg, // , ). // FIXME: Can't this be simpler? This might even be worse than the // corresponding gcc code. @@ -254,11 +255,11 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, ValueDecl *Cmd = OMD->getCmdDecl(); llvm::Value *CmdVal = Builder.CreateLoad(LocalDeclMap[Cmd], "cmd"); QualType IdTy = getContext().getObjCIdType(); - llvm::Value *SelfAsId = + llvm::Value *SelfAsId = Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy)); llvm::Value *Offset = EmitIvarOffset(IMP->getClassInterface(), Ivar); llvm::Value *Arg = LocalDeclMap[*OMD->param_begin()]; - llvm::Value *ArgAsId = + llvm::Value *ArgAsId = Builder.CreateBitCast(Builder.CreateLoad(Arg, "arg"), Types.ConvertType(IdTy)); llvm::Value *True = @@ -270,13 +271,13 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, Args.push_back(std::make_pair(RValue::get(CmdVal), Cmd->getType())); Args.push_back(std::make_pair(RValue::get(Offset), getContext().LongTy)); Args.push_back(std::make_pair(RValue::get(ArgAsId), IdTy)); - Args.push_back(std::make_pair(RValue::get(IsAtomic ? True : False), + Args.push_back(std::make_pair(RValue::get(IsAtomic ? True : False), getContext().BoolTy)); - Args.push_back(std::make_pair(RValue::get(IsCopy ? True : False), + Args.push_back(std::make_pair(RValue::get(IsCopy ? True : False), 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), + EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args), SetPropertyFn, Args); } else { SourceLocation Loc = PD->getLocation(); @@ -305,18 +306,18 @@ llvm::Value *CodeGenFunction::LoadObjCSelf() { QualType CodeGenFunction::TypeOfSelfObject() { const ObjCMethodDecl *OMD = cast(CurFuncDecl); ImplicitParamDecl *selfDecl = OMD->getSelfDecl(); - const PointerType *PTy = - cast(getContext().getCanonicalType(selfDecl->getType())); + const ObjCObjectPointerType *PTy = cast( + getContext().getCanonicalType(selfDecl->getType())); return PTy->getPointeeType(); } -RValue CodeGenFunction::EmitObjCSuperPropertyGet(const Expr *Exp, +RValue CodeGenFunction::EmitObjCSuperPropertyGet(const Expr *Exp, const Selector &S) { llvm::Value *Receiver = LoadObjCSelf(); const ObjCMethodDecl *OMD = cast(CurFuncDecl); bool isClassMessage = OMD->isClassMethod(); bool isCategoryImpl = isa(OMD->getDeclContext()); - return CGM.getObjCRuntime().GenerateMessageSendSuper(*this, + return CGM.getObjCRuntime().GenerateMessageSendSuper(*this, Exp->getType(), S, OMD->getClassInterface(), @@ -324,36 +325,36 @@ RValue CodeGenFunction::EmitObjCSuperPropertyGet(const Expr *Exp, Receiver, isClassMessage, CallArgList()); - + } RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) { + Exp = Exp->IgnoreParens(); // FIXME: Split it into two separate routines. if (const ObjCPropertyRefExpr *E = dyn_cast(Exp)) { Selector S = E->getProperty()->getGetterName(); if (isa(E->getBase())) return EmitObjCSuperPropertyGet(E, S); return CGM.getObjCRuntime(). - GenerateMessageSend(*this, Exp->getType(), S, - EmitScalarExpr(E->getBase()), + GenerateMessageSend(*this, Exp->getType(), S, + EmitScalarExpr(E->getBase()), false, CallArgList()); - } - else { - const ObjCKVCRefExpr *KE = cast(Exp); + } else { + const ObjCImplicitSetterGetterRefExpr *KE = + cast(Exp); Selector S = KE->getGetterMethod()->getSelector(); llvm::Value *Receiver; - if (KE->getClassProp()) { - const ObjCInterfaceDecl *OID = KE->getClassProp(); + if (KE->getInterfaceDecl()) { + const ObjCInterfaceDecl *OID = KE->getInterfaceDecl(); Receiver = CGM.getObjCRuntime().GetClass(Builder, OID); - } - else if (isa(KE->getBase())) + } else if (isa(KE->getBase())) return EmitObjCSuperPropertyGet(KE, S); - else + else Receiver = EmitScalarExpr(KE->getBase()); return CGM.getObjCRuntime(). - GenerateMessageSend(*this, Exp->getType(), S, - Receiver, - KE->getClassProp() != 0, CallArgList()); + GenerateMessageSend(*this, Exp->getType(), S, + Receiver, + KE->getInterfaceDecl() != 0, CallArgList()); } } @@ -366,7 +367,7 @@ void CodeGenFunction::EmitObjCSuperPropertySet(const Expr *Exp, bool isClassMessage = OMD->isClassMethod(); bool isCategoryImpl = isa(OMD->getDeclContext()); Args.push_back(std::make_pair(Src, Exp->getType())); - CGM.getObjCRuntime().GenerateMessageSendSuper(*this, + CGM.getObjCRuntime().GenerateMessageSendSuper(*this, Exp->getType(), S, OMD->getClassInterface(), @@ -385,42 +386,39 @@ void CodeGenFunction::EmitObjCPropertySet(const Expr *Exp, if (isa(E->getBase())) { EmitObjCSuperPropertySet(E, S, Src); return; - } + } CallArgList Args; Args.push_back(std::make_pair(Src, E->getType())); - CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S, - EmitScalarExpr(E->getBase()), + CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S, + EmitScalarExpr(E->getBase()), false, Args); - } - else if (const ObjCKVCRefExpr *E = dyn_cast(Exp)) { + } else if (const ObjCImplicitSetterGetterRefExpr *E = + dyn_cast(Exp)) { Selector S = E->getSetterMethod()->getSelector(); CallArgList Args; llvm::Value *Receiver; - if (E->getClassProp()) { - const ObjCInterfaceDecl *OID = E->getClassProp(); + if (E->getInterfaceDecl()) { + const ObjCInterfaceDecl *OID = E->getInterfaceDecl(); Receiver = CGM.getObjCRuntime().GetClass(Builder, OID); - } - else if (isa(E->getBase())) { + } else if (isa(E->getBase())) { EmitObjCSuperPropertySet(E, S, Src); return; - } - else + } else Receiver = EmitScalarExpr(E->getBase()); Args.push_back(std::make_pair(Src, E->getType())); - CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S, - Receiver, - E->getClassProp() != 0, Args); - } - else + CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S, + Receiver, + E->getInterfaceDecl() != 0, Args); + } else assert (0 && "bad expression node in EmitObjCPropertySet"); } void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ - llvm::Constant *EnumerationMutationFn = + llvm::Constant *EnumerationMutationFn = CGM.getObjCRuntime().EnumerationMutationFunction(); llvm::Value *DeclAddress; QualType ElementTy; - + if (!EnumerationMutationFn) { CGM.ErrorUnsupported(&S, "Obj-C fast enumeration for this runtime"); return; @@ -431,62 +429,62 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ assert(HaveInsertPoint() && "DeclStmt destroyed insert point!"); const Decl* D = SD->getSingleDecl(); ElementTy = cast(D)->getType(); - DeclAddress = LocalDeclMap[D]; + DeclAddress = LocalDeclMap[D]; } else { ElementTy = cast(S.getElement())->getType(); DeclAddress = 0; } - + // Fast enumeration state. QualType StateTy = getContext().getObjCFastEnumerationStateType(); - llvm::AllocaInst *StatePtr = CreateTempAlloca(ConvertType(StateTy), + llvm::AllocaInst *StatePtr = CreateTempAlloca(ConvertType(StateTy), "state.ptr"); - StatePtr->setAlignment(getContext().getTypeAlign(StateTy) >> 3); + StatePtr->setAlignment(getContext().getTypeAlign(StateTy) >> 3); EmitMemSetToZero(StatePtr, StateTy); - + // Number of elements in the items array. static const unsigned NumItems = 16; - + // Get selector llvm::SmallVector II; II.push_back(&CGM.getContext().Idents.get("countByEnumeratingWithState")); II.push_back(&CGM.getContext().Idents.get("objects")); II.push_back(&CGM.getContext().Idents.get("count")); - Selector FastEnumSel = CGM.getContext().Selectors.getSelector(II.size(), + Selector FastEnumSel = CGM.getContext().Selectors.getSelector(II.size(), &II[0]); QualType ItemsTy = getContext().getConstantArrayType(getContext().getObjCIdType(), - llvm::APInt(32, NumItems), + llvm::APInt(32, NumItems), ArrayType::Normal, 0); llvm::Value *ItemsPtr = CreateTempAlloca(ConvertType(ItemsTy), "items.ptr"); - + llvm::Value *Collection = EmitScalarExpr(S.getCollection()); - + CallArgList Args; - Args.push_back(std::make_pair(RValue::get(StatePtr), + Args.push_back(std::make_pair(RValue::get(StatePtr), getContext().getPointerType(StateTy))); - - Args.push_back(std::make_pair(RValue::get(ItemsPtr), + + Args.push_back(std::make_pair(RValue::get(ItemsPtr), getContext().getPointerType(ItemsTy))); - + const llvm::Type *UnsignedLongLTy = ConvertType(getContext().UnsignedLongTy); llvm::Constant *Count = llvm::ConstantInt::get(UnsignedLongLTy, NumItems); - Args.push_back(std::make_pair(RValue::get(Count), + Args.push_back(std::make_pair(RValue::get(Count), getContext().UnsignedLongTy)); - - RValue CountRV = - CGM.getObjCRuntime().GenerateMessageSend(*this, + + RValue CountRV = + CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().UnsignedLongTy, FastEnumSel, Collection, false, Args); llvm::Value *LimitPtr = CreateTempAlloca(UnsignedLongLTy, "limit.ptr"); Builder.CreateStore(CountRV.getScalarVal(), LimitPtr); - + llvm::BasicBlock *NoElements = createBasicBlock("noelements"); llvm::BasicBlock *SetStartMutations = createBasicBlock("setstartmutations"); - + llvm::Value *Limit = Builder.CreateLoad(LimitPtr); llvm::Value *Zero = llvm::Constant::getNullValue(UnsignedLongLTy); @@ -494,60 +492,60 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ Builder.CreateCondBr(IsZero, NoElements, SetStartMutations); EmitBlock(SetStartMutations); - - llvm::Value *StartMutationsPtr = + + llvm::Value *StartMutationsPtr = CreateTempAlloca(UnsignedLongLTy); - - llvm::Value *StateMutationsPtrPtr = + + llvm::Value *StateMutationsPtrPtr = Builder.CreateStructGEP(StatePtr, 2, "mutationsptr.ptr"); - llvm::Value *StateMutationsPtr = Builder.CreateLoad(StateMutationsPtrPtr, + llvm::Value *StateMutationsPtr = Builder.CreateLoad(StateMutationsPtrPtr, "mutationsptr"); - - llvm::Value *StateMutations = Builder.CreateLoad(StateMutationsPtr, + + llvm::Value *StateMutations = Builder.CreateLoad(StateMutationsPtr, "mutations"); - + Builder.CreateStore(StateMutations, StartMutationsPtr); - + llvm::BasicBlock *LoopStart = createBasicBlock("loopstart"); EmitBlock(LoopStart); llvm::Value *CounterPtr = CreateTempAlloca(UnsignedLongLTy, "counter.ptr"); Builder.CreateStore(Zero, CounterPtr); - - llvm::BasicBlock *LoopBody = createBasicBlock("loopbody"); + + llvm::BasicBlock *LoopBody = createBasicBlock("loopbody"); EmitBlock(LoopBody); StateMutationsPtr = Builder.CreateLoad(StateMutationsPtrPtr, "mutationsptr"); StateMutations = Builder.CreateLoad(StateMutationsPtr, "statemutations"); - llvm::Value *StartMutations = Builder.CreateLoad(StartMutationsPtr, + llvm::Value *StartMutations = Builder.CreateLoad(StartMutationsPtr, "mutations"); - llvm::Value *MutationsEqual = Builder.CreateICmpEQ(StateMutations, + llvm::Value *MutationsEqual = Builder.CreateICmpEQ(StateMutations, StartMutations, "tobool"); - - + + llvm::BasicBlock *WasMutated = createBasicBlock("wasmutated"); llvm::BasicBlock *WasNotMutated = createBasicBlock("wasnotmutated"); - + Builder.CreateCondBr(MutationsEqual, WasNotMutated, WasMutated); - + EmitBlock(WasMutated); llvm::Value *V = - Builder.CreateBitCast(Collection, + Builder.CreateBitCast(Collection, ConvertType(getContext().getObjCIdType()), "tmp"); CallArgList Args2; - Args2.push_back(std::make_pair(RValue::get(V), + Args2.push_back(std::make_pair(RValue::get(V), 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), EnumerationMutationFn, Args2); - + EmitBlock(WasNotMutated); - - llvm::Value *StateItemsPtr = + + llvm::Value *StateItemsPtr = Builder.CreateStructGEP(StatePtr, 1, "stateitems.ptr"); llvm::Value *Counter = Builder.CreateLoad(CounterPtr, "counter"); @@ -555,39 +553,39 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ llvm::Value *EnumStateItems = Builder.CreateLoad(StateItemsPtr, "stateitems"); - llvm::Value *CurrentItemPtr = + llvm::Value *CurrentItemPtr = Builder.CreateGEP(EnumStateItems, Counter, "currentitem.ptr"); - + llvm::Value *CurrentItem = Builder.CreateLoad(CurrentItemPtr, "currentitem"); - + // Cast the item to the right type. CurrentItem = Builder.CreateBitCast(CurrentItem, ConvertType(ElementTy), "tmp"); - + if (!DeclAddress) { LValue LV = EmitLValue(cast(S.getElement())); - + // Set the value to null. Builder.CreateStore(CurrentItem, LV.getAddress()); } else Builder.CreateStore(CurrentItem, DeclAddress); - + // Increment the counter. - Counter = Builder.CreateAdd(Counter, + Counter = Builder.CreateAdd(Counter, llvm::ConstantInt::get(UnsignedLongLTy, 1)); Builder.CreateStore(Counter, CounterPtr); - + llvm::BasicBlock *LoopEnd = createBasicBlock("loopend"); llvm::BasicBlock *AfterBody = createBasicBlock("afterbody"); - + BreakContinueStack.push_back(BreakContinue(LoopEnd, AfterBody)); EmitStmt(S.getBody()); - + BreakContinueStack.pop_back(); - + EmitBlock(AfterBody); - + llvm::BasicBlock *FetchMore = createBasicBlock("fetchmore"); Counter = Builder.CreateLoad(CounterPtr); @@ -597,18 +595,18 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ // Fetch more elements. EmitBlock(FetchMore); - - CountRV = - CGM.getObjCRuntime().GenerateMessageSend(*this, + + CountRV = + CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().UnsignedLongTy, - FastEnumSel, + FastEnumSel, Collection, false, Args); Builder.CreateStore(CountRV.getScalarVal(), LimitPtr); Limit = Builder.CreateLoad(LimitPtr); - + IsZero = Builder.CreateICmpEQ(Limit, Zero, "iszero"); Builder.CreateCondBr(IsZero, NoElements, LoopStart); - + // No more elements. EmitBlock(NoElements); @@ -616,7 +614,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ // If the element was not a declaration, set it to be null. LValue LV = EmitLValue(cast(S.getElement())); - + // Set the value to null. Builder.CreateStore(llvm::Constant::getNullValue(ConvertType(ElementTy)), LV.getAddress()); @@ -625,19 +623,16 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ EmitBlock(LoopEnd); } -void CodeGenFunction::EmitObjCAtTryStmt(const ObjCAtTryStmt &S) -{ +void CodeGenFunction::EmitObjCAtTryStmt(const ObjCAtTryStmt &S) { CGM.getObjCRuntime().EmitTryOrSynchronizedStmt(*this, S); } -void CodeGenFunction::EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S) -{ +void CodeGenFunction::EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S) { CGM.getObjCRuntime().EmitThrowStmt(*this, S); } void CodeGenFunction::EmitObjCAtSynchronizedStmt( - const ObjCAtSynchronizedStmt &S) -{ + const ObjCAtSynchronizedStmt &S) { CGM.getObjCRuntime().EmitTryOrSynchronizedStmt(*this, S); } diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 6554da9cf98c..f348bfffcb86 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -43,6 +43,7 @@ using llvm::dyn_cast; static const int RuntimeVersion = 8; static const int NonFragileRuntimeVersion = 9; static const int ProtocolVersion = 2; +static const int NonFragileProtocolVersion = 3; namespace { class CGObjCGNU : public CodeGen::CGObjCRuntime { @@ -50,9 +51,11 @@ private: CodeGen::CodeGenModule &CGM; llvm::Module &TheModule; const llvm::PointerType *SelectorTy; + const llvm::IntegerType *Int8Ty; const llvm::PointerType *PtrToInt8Ty; const llvm::FunctionType *IMPTy; const llvm::PointerType *IdTy; + QualType ASTIdTy; const llvm::IntegerType *IntTy; const llvm::PointerType *PtrTy; const llvm::IntegerType *LongTy; @@ -70,6 +73,7 @@ private: // Some zeros used for GEPs in lots of places. llvm::Constant *Zeros[2]; llvm::Constant *NULLPtr; + llvm::LLVMContext &VMContext; private: llvm::Constant *GenerateIvarList( const llvm::SmallVectorImpl &IvarNames, @@ -77,12 +81,19 @@ private: const llvm::SmallVectorImpl &IvarOffsets); llvm::Constant *GenerateMethodList(const std::string &ClassName, const std::string &CategoryName, - const llvm::SmallVectorImpl &MethodSels, - const llvm::SmallVectorImpl &MethodTypes, + const llvm::SmallVectorImpl &MethodSels, + const llvm::SmallVectorImpl &MethodTypes, bool isClassMethodList); llvm::Constant *GenerateEmptyProtocol(const std::string &ProtocolName); + llvm::Constant *GeneratePropertyList(const ObjCImplementationDecl *OID, + llvm::SmallVectorImpl &InstanceMethodSels, + llvm::SmallVectorImpl &InstanceMethodTypes); llvm::Constant *GenerateProtocolList( const llvm::SmallVectorImpl &Protocols); + // To ensure that all protocols are seen by the runtime, we add a category on + // a class defined in the runtime, declaring no methods, but adopting the + // protocols. + void GenerateProtocolHolderCategory(void); llvm::Constant *GenerateClassStructure( llvm::Constant *MetaClass, llvm::Constant *SuperClass, @@ -92,12 +103,16 @@ private: llvm::Constant *InstanceSize, llvm::Constant *IVars, llvm::Constant *Methods, - llvm::Constant *Protocols); + llvm::Constant *Protocols, + llvm::Constant *IvarOffsets, + llvm::Constant *Properties); llvm::Constant *GenerateProtocolMethodList( const llvm::SmallVectorImpl &MethodNames, const llvm::SmallVectorImpl &MethodTypes); llvm::Constant *MakeConstantString(const std::string &Str, const std::string &Name=""); + llvm::Constant *ExportUniqueString(const std::string &Str, const std::string + prefix); llvm::Constant *MakeGlobal(const llvm::StructType *Ty, std::vector &V, const std::string &Name=""); llvm::Constant *MakeGlobal(const llvm::ArrayType *Ty, @@ -108,7 +123,7 @@ private: public: CGObjCGNU(CodeGen::CodeGenModule &cgm); virtual llvm::Constant *GenerateConstantString(const ObjCStringLiteral *); - virtual CodeGen::RValue + virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, @@ -116,7 +131,7 @@ public: bool IsClassMessage, const CallArgList &CallArgs, const ObjCMethodDecl *Method); - virtual CodeGen::RValue + virtual CodeGen::RValue GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, @@ -124,14 +139,15 @@ public: bool isCategoryImpl, llvm::Value *Receiver, bool IsClassMessage, - const CallArgList &CallArgs); + const CallArgList &CallArgs, + const ObjCMethodDecl *Method); virtual llvm::Value *GetClass(CGBuilderTy &Builder, const ObjCInterfaceDecl *OID); virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel); virtual llvm::Value *GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl *Method); - - virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, + + virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD); virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD); virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl); @@ -139,11 +155,10 @@ public: const ObjCProtocolDecl *PD); virtual void GenerateProtocol(const ObjCProtocolDecl *PD); virtual llvm::Function *ModuleInitFunction(); - virtual void MergeMetadataGlobals(std::vector &UsedArray); virtual llvm::Function *GetPropertyGetFunction(); virtual llvm::Function *GetPropertySetFunction(); - virtual llvm::Function *EnumerationMutationFunction(); - + virtual llvm::Constant *EnumerationMutationFunction(); + virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, const Stmt &S); virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, @@ -155,9 +170,14 @@ public: virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest); virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dest); + llvm::Value *src, llvm::Value *dest, + llvm::Value *ivarOffset); virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest); + virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, + llvm::Value *DestPtr, + llvm::Value *SrcPtr, + QualType Ty); virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, QualType ObjectTy, llvm::Value *BaseValue, @@ -173,18 +193,19 @@ public: /// Emits a reference to a dummy variable which is emitted with each class. /// This ensures that a linker error will be generated when trying to link /// together modules where a referenced class is not defined. -void CGObjCGNU::EmitClassRef(const std::string &className){ +void CGObjCGNU::EmitClassRef(const std::string &className) { std::string symbolRef = "__objc_class_ref_" + className; // Don't emit two copies of the same symbol - if (TheModule.getGlobalVariable(symbolRef)) return; + if (TheModule.getGlobalVariable(symbolRef)) + return; std::string symbolName = "__objc_class_name_" + className; llvm::GlobalVariable *ClassSymbol = TheModule.getGlobalVariable(symbolName); if (!ClassSymbol) { - ClassSymbol = new llvm::GlobalVariable(LongTy, false, - llvm::GlobalValue::ExternalLinkage, 0, symbolName, &TheModule); + ClassSymbol = new llvm::GlobalVariable(TheModule, LongTy, false, + llvm::GlobalValue::ExternalLinkage, 0, symbolName); } - new llvm::GlobalVariable(ClassSymbol->getType(), true, - llvm::GlobalValue::CommonLinkage, ClassSymbol, symbolRef, &TheModule); + new llvm::GlobalVariable(TheModule, ClassSymbol->getType(), true, + llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef); } static std::string SymbolNameForClass(const std::string &ClassName) { @@ -200,36 +221,37 @@ static std::string SymbolNameForMethod(const std::string &ClassName, const CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm) : CGM(cgm), TheModule(CGM.getModule()), ClassPtrAlias(0), - MetaClassPtrAlias(0) { + MetaClassPtrAlias(0), VMContext(cgm.getLLVMContext()) { IntTy = cast( CGM.getTypes().ConvertType(CGM.getContext().IntTy)); LongTy = cast( CGM.getTypes().ConvertType(CGM.getContext().LongTy)); - + + Int8Ty = llvm::Type::getInt8Ty(VMContext); + // C string type. Used in lots of places. + PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); + Zeros[0] = llvm::ConstantInt::get(LongTy, 0); Zeros[1] = Zeros[0]; - NULLPtr = llvm::ConstantPointerNull::get( - llvm::PointerType::getUnqual(llvm::Type::Int8Ty)); - // C string type. Used in lots of places. - PtrToInt8Ty = - llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + NULLPtr = llvm::ConstantPointerNull::get(PtrToInt8Ty); // Get the selector Type. SelectorTy = cast( CGM.getTypes().ConvertType(CGM.getContext().getObjCSelType())); PtrToIntTy = llvm::PointerType::getUnqual(IntTy); PtrTy = PtrToInt8Ty; - + // Object type - IdTy = cast( - CGM.getTypes().ConvertType(CGM.getContext().getObjCIdType())); - + ASTIdTy = CGM.getContext().getObjCIdType(); + IdTy = cast(CGM.getTypes().ConvertType(ASTIdTy)); + // IMP type std::vector IMPArgs; IMPArgs.push_back(IdTy); IMPArgs.push_back(SelectorTy); IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true); } + // This has to perform the lookup every time, since posing and related // techniques can modify the name -> class mapping. llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder, @@ -251,10 +273,10 @@ llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel) { llvm::GlobalAlias *&US = UntypedSelectors[Sel.getAsString()]; if (US == 0) US = new llvm::GlobalAlias(llvm::PointerType::getUnqual(SelectorTy), - llvm::GlobalValue::InternalLinkage, - ".objc_untyped_selector_alias", + llvm::GlobalValue::PrivateLinkage, + ".objc_untyped_selector_alias"+Sel.getAsString(), NULL, &TheModule); - + return Builder.CreateLoad(US); } @@ -269,15 +291,14 @@ llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl SelTypes); // If it's already cached, return it. - if (TypedSelectors[Selector]) - { - return Builder.CreateLoad(TypedSelectors[Selector]); + if (TypedSelectors[Selector]) { + return Builder.CreateLoad(TypedSelectors[Selector]); } // If it isn't, cache it. llvm::GlobalAlias *Sel = new llvm::GlobalAlias( llvm::PointerType::getUnqual(SelectorTy), - llvm::GlobalValue::InternalLinkage, SelName, + llvm::GlobalValue::PrivateLinkage, ".objc_selector_alias" + SelName, NULL, &TheModule); TypedSelectors[Selector] = Sel; @@ -286,23 +307,33 @@ llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl llvm::Constant *CGObjCGNU::MakeConstantString(const std::string &Str, const std::string &Name) { - llvm::Constant * ConstStr = llvm::ConstantArray::get(Str); - ConstStr = new llvm::GlobalVariable(ConstStr->getType(), true, - llvm::GlobalValue::InternalLinkage, - ConstStr, Name, &TheModule); + llvm::Constant *ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str()); return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2); } +llvm::Constant *CGObjCGNU::ExportUniqueString(const std::string &Str, + const std::string prefix) { + std::string name = prefix + Str; + llvm::Constant *ConstStr = TheModule.getGlobalVariable(name); + if (!ConstStr) { + llvm::Constant *value = llvm::ConstantArray::get(VMContext, Str, true); + ConstStr = new llvm::GlobalVariable(TheModule, value->getType(), true, + llvm::GlobalValue::LinkOnceODRLinkage, value, prefix + Str); + } + return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2); +} + llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::StructType *Ty, std::vector &V, const std::string &Name) { llvm::Constant *C = llvm::ConstantStruct::get(Ty, V); - return new llvm::GlobalVariable(Ty, false, - llvm::GlobalValue::InternalLinkage, C, Name, &TheModule); + return new llvm::GlobalVariable(TheModule, Ty, false, + llvm::GlobalValue::InternalLinkage, C, Name); } + llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty, std::vector &V, const std::string &Name) { llvm::Constant *C = llvm::ConstantArray::get(Ty, V); - return new llvm::GlobalVariable(Ty, false, - llvm::GlobalValue::InternalLinkage, C, Name, &TheModule); + return new llvm::GlobalVariable(TheModule, Ty, false, + llvm::GlobalValue::InternalLinkage, C, Name); } /// Generate an NSConstantString object. @@ -310,14 +341,14 @@ llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty, //an OpenStep implementation, this should let them select their own class for //constant strings. llvm::Constant *CGObjCGNU::GenerateConstantString(const ObjCStringLiteral *SL) { - std::string Str(SL->getString()->getStrData(), + std::string Str(SL->getString()->getStrData(), SL->getString()->getByteLength()); std::vector Ivars; Ivars.push_back(NULLPtr); Ivars.push_back(MakeConstantString(Str)); Ivars.push_back(llvm::ConstantInt::get(IntTy, Str.size())); llvm::Constant *ObjCStr = MakeGlobal( - llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, IntTy, NULL), + llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty, IntTy, NULL), Ivars, ".objc_str"); ConstantStrings.push_back( llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty)); @@ -335,21 +366,23 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, bool isCategoryImpl, llvm::Value *Receiver, bool IsClassMessage, - const CallArgList &CallArgs) { + const CallArgList &CallArgs, + const ObjCMethodDecl *Method) { llvm::Value *cmd = GetSelector(CGF.Builder, Sel); CallArgList ActualArgs; ActualArgs.push_back( - std::make_pair(RValue::get(CGF.Builder.CreateBitCast(Receiver, IdTy)), - CGF.getContext().getObjCIdType())); + std::make_pair(RValue::get(CGF.Builder.CreateBitCast(Receiver, IdTy)), + ASTIdTy)); ActualArgs.push_back(std::make_pair(RValue::get(cmd), CGF.getContext().getObjCSelType())); ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); CodeGenTypes &Types = CGM.getTypes(); const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs); - const llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, false); + const llvm::FunctionType *impType = + Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); llvm::Value *ReceiverClass = 0; if (isCategoryImpl) { @@ -368,8 +401,8 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, } else { // Set up global aliases for the metaclass or class pointer if they do not // already exist. These will are forward-references which will be set to - // pointers to the class and metaclass structure created for the runtime load - // function. To send a message to super, we look up the value of the + // pointers to the class and metaclass structure created for the runtime + // load function. To send a message to super, we look up the value of the // super_class pointer from either the class or metaclass structure. if (IsClassMessage) { if (!MetaClassPtrAlias) { @@ -388,15 +421,16 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, } } // Cast the pointer to a simplified version of the class structure - ReceiverClass = CGF.Builder.CreateBitCast(ReceiverClass, - llvm::PointerType::getUnqual(llvm::StructType::get(IdTy, IdTy, NULL))); + ReceiverClass = CGF.Builder.CreateBitCast(ReceiverClass, + llvm::PointerType::getUnqual( + llvm::StructType::get(VMContext, IdTy, IdTy, NULL))); // Get the superclass pointer ReceiverClass = CGF.Builder.CreateStructGEP(ReceiverClass, 1); // Load the superclass pointer ReceiverClass = CGF.Builder.CreateLoad(ReceiverClass); // Construct the structure used to look up the IMP - llvm::StructType *ObjCSuperTy = llvm::StructType::get(Receiver->getType(), - IdTy, NULL); + llvm::StructType *ObjCSuperTy = llvm::StructType::get(VMContext, + Receiver->getType(), IdTy, NULL); llvm::Value *ObjCSuper = CGF.Builder.CreateAlloca(ObjCSuperTy); CGF.Builder.CreateStore(Receiver, CGF.Builder.CreateStructGEP(ObjCSuper, 0)); @@ -407,7 +441,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, std::vector Params; Params.push_back(llvm::PointerType::getUnqual(ObjCSuperTy)); Params.push_back(SelectorTy); - llvm::Constant *lookupFunction = + llvm::Constant *lookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( llvm::PointerType::getUnqual(impType), Params, true), "objc_msg_lookup_super"); @@ -419,7 +453,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, return CGF.EmitCall(FnInfo, imp, ActualArgs); } -/// Generate code for a message send expression. +/// Generate code for a message send expression. CodeGen::RValue CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, @@ -428,32 +462,38 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, bool IsClassMessage, const CallArgList &CallArgs, const ObjCMethodDecl *Method) { + CGBuilderTy &Builder = CGF.Builder; + IdTy = cast(CGM.getTypes().ConvertType(ASTIdTy)); llvm::Value *cmd; if (Method) - cmd = GetSelector(CGF.Builder, Method); + cmd = GetSelector(Builder, Method); else - cmd = GetSelector(CGF.Builder, Sel); + cmd = GetSelector(Builder, Sel); CallArgList ActualArgs; + Receiver = Builder.CreateBitCast(Receiver, IdTy); ActualArgs.push_back( - std::make_pair(RValue::get(CGF.Builder.CreateBitCast(Receiver, IdTy)), - CGF.getContext().getObjCIdType())); + std::make_pair(RValue::get(Receiver), ASTIdTy)); ActualArgs.push_back(std::make_pair(RValue::get(cmd), CGF.getContext().getObjCSelType())); ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); CodeGenTypes &Types = CGM.getTypes(); const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs); - const llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, false); + const llvm::FunctionType *impType = + Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); llvm::Value *imp; - std::vector Params; - Params.push_back(Receiver->getType()); - Params.push_back(SelectorTy); // For sender-aware dispatch, we pass the sender as the third argument to a // lookup function. When sending messages from C code, the sender is nil. - // objc_msg_lookup_sender(id receiver, SEL selector, id sender); - if (CGM.getContext().getLangOptions().ObjCSenderDispatch) { + // objc_msg_lookup_sender(id *receiver, SEL selector, id sender); + if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { + + std::vector Params; + llvm::Value *ReceiverPtr = CGF.CreateTempAlloca(Receiver->getType()); + Builder.CreateStore(Receiver, ReceiverPtr); + Params.push_back(ReceiverPtr->getType()); + Params.push_back(SelectorTy); llvm::Value *self; if (isa(CGF.CurFuncDecl)) { @@ -461,34 +501,55 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, } else { self = llvm::ConstantPointerNull::get(IdTy); } + Params.push_back(self->getType()); - llvm::Constant *lookupFunction = + + // The lookup function returns a slot, which can be safely cached. + llvm::Type *SlotTy = llvm::StructType::get(VMContext, PtrTy, PtrTy, PtrTy, + IntTy, llvm::PointerType::getUnqual(impType), NULL); + llvm::Constant *lookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( - llvm::PointerType::getUnqual(impType), Params, true), + llvm::PointerType::getUnqual(SlotTy), Params, true), "objc_msg_lookup_sender"); - imp = CGF.Builder.CreateCall3(lookupFunction, Receiver, cmd, self); + // The lookup function is guaranteed not to capture the receiver pointer. + if (llvm::Function *LookupFn = dyn_cast(lookupFunction)) { + LookupFn->setDoesNotCapture(1); + } + + llvm::Value *slot = + Builder.CreateCall3(lookupFunction, ReceiverPtr, cmd, self); + imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4)); + // The lookup function may have changed the receiver, so make sure we use + // the new one. + ActualArgs[0] = + std::make_pair(RValue::get(Builder.CreateLoad(ReceiverPtr)), ASTIdTy); } else { - llvm::Constant *lookupFunction = + std::vector Params; + Params.push_back(Receiver->getType()); + Params.push_back(SelectorTy); + llvm::Constant *lookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( llvm::PointerType::getUnqual(impType), Params, true), "objc_msg_lookup"); - imp = CGF.Builder.CreateCall2(lookupFunction, Receiver, cmd); + imp = Builder.CreateCall2(lookupFunction, Receiver, cmd); } return CGF.EmitCall(FnInfo, imp, ActualArgs); } -/// Generates a MethodList. Used in construction of a objc_class and +/// Generates a MethodList. Used in construction of a objc_class and /// objc_category structures. llvm::Constant *CGObjCGNU::GenerateMethodList(const std::string &ClassName, - const std::string &CategoryName, - const llvm::SmallVectorImpl &MethodSels, - const llvm::SmallVectorImpl &MethodTypes, + const std::string &CategoryName, + const llvm::SmallVectorImpl &MethodSels, + const llvm::SmallVectorImpl &MethodTypes, bool isClassMethodList) { - // Get the method structure type. - llvm::StructType *ObjCMethodTy = llvm::StructType::get( + if (MethodSels.empty()) + return NULLPtr; + // Get the method structure type. + llvm::StructType *ObjCMethodTy = llvm::StructType::get(VMContext, PtrToInt8Ty, // Really a selector, but the runtime creates it us. PtrToInt8Ty, // Method types llvm::PointerType::getUnqual(IMPTy), //Method pointer @@ -501,11 +562,9 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const std::string &ClassName, TheModule.getFunction(SymbolNameForMethod(ClassName, CategoryName, MethodSels[i].getAsString(), isClassMethodList))) { - llvm::Constant *C = - CGM.GetAddrOfConstantCString(MethodSels[i].getAsString()); - Elements.push_back(llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2)); - Elements.push_back( - llvm::ConstantExpr::getGetElementPtr(MethodTypes[i], Zeros, 2)); + llvm::Constant *C = MakeConstantString(MethodSels[i].getAsString()); + Elements.push_back(C); + Elements.push_back(MethodTypes[i]); Method = llvm::ConstantExpr::getBitCast(Method, llvm::PointerType::getUnqual(IMPTy)); Elements.push_back(Method); @@ -521,10 +580,11 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const std::string &ClassName, // Structure containing list pointer, array and array count llvm::SmallVector ObjCMethodListFields; - llvm::PATypeHolder OpaqueNextTy = llvm::OpaqueType::get(); + llvm::PATypeHolder OpaqueNextTy = llvm::OpaqueType::get(VMContext); llvm::Type *NextPtrTy = llvm::PointerType::getUnqual(OpaqueNextTy); - llvm::StructType *ObjCMethodListTy = llvm::StructType::get(NextPtrTy, - IntTy, + llvm::StructType *ObjCMethodListTy = llvm::StructType::get(VMContext, + NextPtrTy, + IntTy, ObjCMethodArrayTy, NULL); // Refine next pointer type to concrete type @@ -535,10 +595,10 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const std::string &ClassName, Methods.clear(); Methods.push_back(llvm::ConstantPointerNull::get( llvm::PointerType::getUnqual(ObjCMethodListTy))); - Methods.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, + Methods.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), MethodTypes.size())); Methods.push_back(MethodArray); - + // Create an instance of the structure return MakeGlobal(ObjCMethodListTy, Methods, ".objc_method_list"); } @@ -548,8 +608,8 @@ llvm::Constant *CGObjCGNU::GenerateIvarList( const llvm::SmallVectorImpl &IvarNames, const llvm::SmallVectorImpl &IvarTypes, const llvm::SmallVectorImpl &IvarOffsets) { - // Get the method structure type. - llvm::StructType *ObjCIvarTy = llvm::StructType::get( + // Get the method structure type. + llvm::StructType *ObjCIvarTy = llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty, IntTy, @@ -558,10 +618,8 @@ llvm::Constant *CGObjCGNU::GenerateIvarList( std::vector Elements; for (unsigned int i = 0, e = IvarNames.size() ; i < e ; i++) { Elements.clear(); - Elements.push_back( llvm::ConstantExpr::getGetElementPtr(IvarNames[i], - Zeros, 2)); - Elements.push_back( llvm::ConstantExpr::getGetElementPtr(IvarTypes[i], - Zeros, 2)); + Elements.push_back(IvarNames[i]); + Elements.push_back(IvarTypes[i]); Elements.push_back(IvarOffsets[i]); Ivars.push_back(llvm::ConstantStruct::get(ObjCIvarTy, Elements)); } @@ -570,12 +628,12 @@ llvm::Constant *CGObjCGNU::GenerateIvarList( llvm::ArrayType *ObjCIvarArrayTy = llvm::ArrayType::get(ObjCIvarTy, IvarNames.size()); - + Elements.clear(); Elements.push_back(llvm::ConstantInt::get(IntTy, (int)IvarNames.size())); Elements.push_back(llvm::ConstantArray::get(ObjCIvarArrayTy, Ivars)); // Structure containing array and array count - llvm::StructType *ObjCIvarListTy = llvm::StructType::get(IntTy, + llvm::StructType *ObjCIvarListTy = llvm::StructType::get(VMContext, IntTy, ObjCIvarArrayTy, NULL); @@ -593,11 +651,17 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( llvm::Constant *InstanceSize, llvm::Constant *IVars, llvm::Constant *Methods, - llvm::Constant *Protocols) { + llvm::Constant *Protocols, + llvm::Constant *IvarOffsets, + llvm::Constant *Properties) { // Set up the class structure // Note: Several of these are char*s when they should be ids. This is // because the runtime performs this translation on load. - llvm::StructType *ClassTy = llvm::StructType::get( + // + // Fields marked New ABI are part of the GNUstep runtime. We emit them + // anyway; the classes will still work with the GNU runtime, they will just + // be ignored. + llvm::StructType *ClassTy = llvm::StructType::get(VMContext, PtrToInt8Ty, // class_pointer PtrToInt8Ty, // super_class PtrToInt8Ty, // name @@ -606,16 +670,18 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( LongTy, // instance_size IVars->getType(), // ivars Methods->getType(), // methods - // These are all filled in by the runtime, so we pretend + // These are all filled in by the runtime, so we pretend PtrTy, // dtable PtrTy, // subclass_list PtrTy, // sibling_class PtrTy, // protocols PtrTy, // gc_object_type + // New ABI: + LongTy, // abi_version + IvarOffsets->getType(), // ivar_offsets + Properties->getType(), // properties NULL); llvm::Constant *Zero = llvm::ConstantInt::get(LongTy, 0); - llvm::Constant *NullP = - llvm::ConstantPointerNull::get(PtrTy); // Fill in the structure std::vector Elements; Elements.push_back(llvm::ConstantExpr::getBitCast(MetaClass, PtrToInt8Ty)); @@ -626,11 +692,14 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( Elements.push_back(InstanceSize); Elements.push_back(IVars); Elements.push_back(Methods); - Elements.push_back(NullP); - Elements.push_back(NullP); - Elements.push_back(NullP); + Elements.push_back(NULLPtr); + Elements.push_back(NULLPtr); + Elements.push_back(NULLPtr); Elements.push_back(llvm::ConstantExpr::getBitCast(Protocols, PtrTy)); - Elements.push_back(NullP); + Elements.push_back(NULLPtr); + Elements.push_back(Zero); + Elements.push_back(IvarOffsets); + Elements.push_back(Properties); // Create an instance of the structure return MakeGlobal(ClassTy, Elements, SymbolNameForClass(Name)); } @@ -638,8 +707,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( llvm::Constant *CGObjCGNU::GenerateProtocolMethodList( const llvm::SmallVectorImpl &MethodNames, const llvm::SmallVectorImpl &MethodTypes) { - // Get the method structure type. - llvm::StructType *ObjCMethodDescTy = llvm::StructType::get( + // Get the method structure type. + llvm::StructType *ObjCMethodDescTy = llvm::StructType::get(VMContext, PtrToInt8Ty, // Really a selector, but the runtime does the casting for us. PtrToInt8Ty, NULL); @@ -647,40 +716,40 @@ llvm::Constant *CGObjCGNU::GenerateProtocolMethodList( std::vector Elements; for (unsigned int i = 0, e = MethodTypes.size() ; i < e ; i++) { Elements.clear(); - Elements.push_back( llvm::ConstantExpr::getGetElementPtr(MethodNames[i], - Zeros, 2)); - Elements.push_back( - llvm::ConstantExpr::getGetElementPtr(MethodTypes[i], Zeros, 2)); + Elements.push_back(MethodNames[i]); + Elements.push_back(MethodTypes[i]); Methods.push_back(llvm::ConstantStruct::get(ObjCMethodDescTy, Elements)); } llvm::ArrayType *ObjCMethodArrayTy = llvm::ArrayType::get(ObjCMethodDescTy, MethodNames.size()); - llvm::Constant *Array = llvm::ConstantArray::get(ObjCMethodArrayTy, Methods); - llvm::StructType *ObjCMethodDescListTy = llvm::StructType::get( + llvm::Constant *Array = llvm::ConstantArray::get(ObjCMethodArrayTy, + Methods); + llvm::StructType *ObjCMethodDescListTy = llvm::StructType::get(VMContext, IntTy, ObjCMethodArrayTy, NULL); Methods.clear(); Methods.push_back(llvm::ConstantInt::get(IntTy, MethodNames.size())); Methods.push_back(Array); return MakeGlobal(ObjCMethodDescListTy, Methods, ".objc_method_list"); } + // Create the protocol list structure used in classes, categories and so on llvm::Constant *CGObjCGNU::GenerateProtocolList( const llvm::SmallVectorImpl &Protocols) { llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(PtrToInt8Ty, Protocols.size()); - llvm::StructType *ProtocolListTy = llvm::StructType::get( + llvm::StructType *ProtocolListTy = llvm::StructType::get(VMContext, PtrTy, //Should be a recurisve pointer, but it's always NULL here. LongTy,//FIXME: Should be size_t ProtocolArrayTy, NULL); - std::vector Elements; + std::vector Elements; for (const std::string *iter = Protocols.begin(), *endIter = Protocols.end(); iter != endIter ; iter++) { llvm::Constant *protocol = ExistingProtocols[*iter]; if (!protocol) protocol = GenerateEmptyProtocol(*iter); - llvm::Constant *Ptr = - llvm::ConstantExpr::getBitCast(protocol, PtrToInt8Ty); + llvm::Constant *Ptr = llvm::ConstantExpr::getBitCast(protocol, + PtrToInt8Ty); Elements.push_back(Ptr); } llvm::Constant * ProtocolArray = llvm::ConstantArray::get(ProtocolArrayTy, @@ -692,10 +761,10 @@ llvm::Constant *CGObjCGNU::GenerateProtocolList( return MakeGlobal(ProtocolListTy, Elements, ".objc_protocol_list"); } -llvm::Value *CGObjCGNU::GenerateProtocolRef(CGBuilderTy &Builder, +llvm::Value *CGObjCGNU::GenerateProtocolRef(CGBuilderTy &Builder, const ObjCProtocolDecl *PD) { llvm::Value *protocol = ExistingProtocols[PD->getNameAsString()]; - const llvm::Type *T = + const llvm::Type *T = CGM.getTypes().ConvertType(CGM.getContext().getObjCProtoType()); return Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T)); } @@ -706,27 +775,31 @@ llvm::Constant *CGObjCGNU::GenerateEmptyProtocol( llvm::SmallVector EmptyConstantVector; llvm::Constant *ProtocolList = GenerateProtocolList(EmptyStringVector); - llvm::Constant *InstanceMethodList = - GenerateProtocolMethodList(EmptyConstantVector, EmptyConstantVector); - llvm::Constant *ClassMethodList = + llvm::Constant *MethodList = GenerateProtocolMethodList(EmptyConstantVector, EmptyConstantVector); // Protocols are objects containing lists of the methods implemented and // protocols adopted. - llvm::StructType *ProtocolTy = llvm::StructType::get(IdTy, + llvm::StructType *ProtocolTy = llvm::StructType::get(VMContext, IdTy, PtrToInt8Ty, ProtocolList->getType(), - InstanceMethodList->getType(), - ClassMethodList->getType(), + MethodList->getType(), + MethodList->getType(), + MethodList->getType(), + MethodList->getType(), NULL); - std::vector Elements; + std::vector Elements; // The isa pointer must be set to a magic number so the runtime knows it's // the correct layout. + int Version = CGM.getContext().getLangOptions().ObjCNonFragileABI ? + NonFragileProtocolVersion : ProtocolVersion; Elements.push_back(llvm::ConstantExpr::getIntToPtr( - llvm::ConstantInt::get(llvm::Type::Int32Ty, ProtocolVersion), IdTy)); + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Version), IdTy)); Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name")); Elements.push_back(ProtocolList); - Elements.push_back(InstanceMethodList); - Elements.push_back(ClassMethodList); + Elements.push_back(MethodList); + Elements.push_back(MethodList); + Elements.push_back(MethodList); + Elements.push_back(MethodList); return MakeGlobal(ProtocolTy, Elements, ".objc_protocol"); } @@ -739,25 +812,41 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) { Protocols.push_back((*PI)->getNameAsString()); llvm::SmallVector InstanceMethodNames; llvm::SmallVector InstanceMethodTypes; + llvm::SmallVector OptionalInstanceMethodNames; + llvm::SmallVector OptionalInstanceMethodTypes; for (ObjCProtocolDecl::instmeth_iterator iter = PD->instmeth_begin(), E = PD->instmeth_end(); iter != E; iter++) { std::string TypeStr; Context.getObjCEncodingForMethodDecl(*iter, TypeStr); - InstanceMethodNames.push_back( - CGM.GetAddrOfConstantCString((*iter)->getSelector().getAsString())); - InstanceMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr)); + if ((*iter)->getImplementationControl() == ObjCMethodDecl::Optional) { + InstanceMethodNames.push_back( + MakeConstantString((*iter)->getSelector().getAsString())); + InstanceMethodTypes.push_back(MakeConstantString(TypeStr)); + } else { + OptionalInstanceMethodNames.push_back( + MakeConstantString((*iter)->getSelector().getAsString())); + OptionalInstanceMethodTypes.push_back(MakeConstantString(TypeStr)); + } } // Collect information about class methods: llvm::SmallVector ClassMethodNames; llvm::SmallVector ClassMethodTypes; - for (ObjCProtocolDecl::classmeth_iterator + llvm::SmallVector OptionalClassMethodNames; + llvm::SmallVector OptionalClassMethodTypes; + for (ObjCProtocolDecl::classmeth_iterator iter = PD->classmeth_begin(), endIter = PD->classmeth_end(); iter != endIter ; iter++) { std::string TypeStr; Context.getObjCEncodingForMethodDecl((*iter),TypeStr); - ClassMethodNames.push_back( - CGM.GetAddrOfConstantCString((*iter)->getSelector().getAsString())); - ClassMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr)); + if ((*iter)->getImplementationControl() == ObjCMethodDecl::Optional) { + ClassMethodNames.push_back( + MakeConstantString((*iter)->getSelector().getAsString())); + ClassMethodTypes.push_back(MakeConstantString(TypeStr)); + } else { + OptionalClassMethodNames.push_back( + MakeConstantString((*iter)->getSelector().getAsString())); + OptionalClassMethodTypes.push_back(MakeConstantString(TypeStr)); + } } llvm::Constant *ProtocolList = GenerateProtocolList(Protocols); @@ -765,27 +854,165 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) { GenerateProtocolMethodList(InstanceMethodNames, InstanceMethodTypes); llvm::Constant *ClassMethodList = GenerateProtocolMethodList(ClassMethodNames, ClassMethodTypes); + llvm::Constant *OptionalInstanceMethodList = + GenerateProtocolMethodList(OptionalInstanceMethodNames, + OptionalInstanceMethodTypes); + llvm::Constant *OptionalClassMethodList = + GenerateProtocolMethodList(OptionalClassMethodNames, + OptionalClassMethodTypes); + + // Property metadata: name, attributes, isSynthesized, setter name, setter + // types, getter name, getter types. + // The isSynthesized value is always set to 0 in a protocol. It exists to + // simplify the runtime library by allowing it to use the same data + // structures for protocol metadata everywhere. + llvm::StructType *PropertyMetadataTy = llvm::StructType::get(VMContext, + PtrToInt8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, + PtrToInt8Ty, NULL); + std::vector Properties; + std::vector OptionalProperties; + + // Add all of the property methods need adding to the method list and to the + // property metadata list. + for (ObjCContainerDecl::prop_iterator + iter = PD->prop_begin(), endIter = PD->prop_end(); + iter != endIter ; iter++) { + std::vector Fields; + ObjCPropertyDecl *property = (*iter); + + Fields.push_back(MakeConstantString(property->getNameAsString())); + Fields.push_back(llvm::ConstantInt::get(Int8Ty, + property->getPropertyAttributes())); + Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0)); + if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) { + std::string TypeStr; + Context.getObjCEncodingForMethodDecl(getter,TypeStr); + llvm::Constant *TypeEncoding = MakeConstantString(TypeStr); + InstanceMethodTypes.push_back(TypeEncoding); + Fields.push_back(MakeConstantString(getter->getSelector().getAsString())); + Fields.push_back(TypeEncoding); + } else { + Fields.push_back(NULLPtr); + Fields.push_back(NULLPtr); + } + if (ObjCMethodDecl *setter = property->getSetterMethodDecl()) { + std::string TypeStr; + Context.getObjCEncodingForMethodDecl(setter,TypeStr); + llvm::Constant *TypeEncoding = MakeConstantString(TypeStr); + InstanceMethodTypes.push_back(TypeEncoding); + Fields.push_back(MakeConstantString(setter->getSelector().getAsString())); + Fields.push_back(TypeEncoding); + } else { + Fields.push_back(NULLPtr); + Fields.push_back(NULLPtr); + } + if (property->getPropertyImplementation() == ObjCPropertyDecl::Optional) { + OptionalProperties.push_back(llvm::ConstantStruct::get(PropertyMetadataTy, Fields)); + } else { + Properties.push_back(llvm::ConstantStruct::get(PropertyMetadataTy, Fields)); + } + } + llvm::Constant *PropertyArray = llvm::ConstantArray::get( + llvm::ArrayType::get(PropertyMetadataTy, Properties.size()), Properties); + llvm::Constant* PropertyListInitFields[] = + {llvm::ConstantInt::get(IntTy, Properties.size()), NULLPtr, PropertyArray}; + + llvm::Constant *PropertyListInit = + llvm::ConstantStruct::get(VMContext, PropertyListInitFields, 3, false); + llvm::Constant *PropertyList = new llvm::GlobalVariable(TheModule, + PropertyListInit->getType(), false, llvm::GlobalValue::InternalLinkage, + PropertyListInit, ".objc_property_list"); + + llvm::Constant *OptionalPropertyArray = + llvm::ConstantArray::get(llvm::ArrayType::get(PropertyMetadataTy, + OptionalProperties.size()) , OptionalProperties); + llvm::Constant* OptionalPropertyListInitFields[] = { + llvm::ConstantInt::get(IntTy, OptionalProperties.size()), NULLPtr, + OptionalPropertyArray }; + + llvm::Constant *OptionalPropertyListInit = + llvm::ConstantStruct::get(VMContext, OptionalPropertyListInitFields, 3, false); + llvm::Constant *OptionalPropertyList = new llvm::GlobalVariable(TheModule, + OptionalPropertyListInit->getType(), false, + llvm::GlobalValue::InternalLinkage, OptionalPropertyListInit, + ".objc_property_list"); + // Protocols are objects containing lists of the methods implemented and // protocols adopted. - llvm::StructType *ProtocolTy = llvm::StructType::get(IdTy, + llvm::StructType *ProtocolTy = llvm::StructType::get(VMContext, IdTy, PtrToInt8Ty, ProtocolList->getType(), InstanceMethodList->getType(), ClassMethodList->getType(), + OptionalInstanceMethodList->getType(), + OptionalClassMethodList->getType(), + PropertyList->getType(), + OptionalPropertyList->getType(), NULL); - std::vector Elements; + std::vector Elements; // The isa pointer must be set to a magic number so the runtime knows it's // the correct layout. + int Version = CGM.getContext().getLangOptions().ObjCNonFragileABI ? + NonFragileProtocolVersion : ProtocolVersion; Elements.push_back(llvm::ConstantExpr::getIntToPtr( - llvm::ConstantInt::get(llvm::Type::Int32Ty, ProtocolVersion), IdTy)); + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Version), IdTy)); Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name")); Elements.push_back(ProtocolList); Elements.push_back(InstanceMethodList); Elements.push_back(ClassMethodList); - ExistingProtocols[ProtocolName] = + Elements.push_back(OptionalInstanceMethodList); + Elements.push_back(OptionalClassMethodList); + Elements.push_back(PropertyList); + Elements.push_back(OptionalPropertyList); + ExistingProtocols[ProtocolName] = llvm::ConstantExpr::getBitCast(MakeGlobal(ProtocolTy, Elements, ".objc_protocol"), IdTy); } +void CGObjCGNU::GenerateProtocolHolderCategory(void) { + // Collect information about instance methods + llvm::SmallVector MethodSels; + llvm::SmallVector MethodTypes; + + std::vector Elements; + const std::string ClassName = "__ObjC_Protocol_Holder_Ugly_Hack"; + const std::string CategoryName = "AnotherHack"; + Elements.push_back(MakeConstantString(CategoryName)); + Elements.push_back(MakeConstantString(ClassName)); + // Instance method list + Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList( + ClassName, CategoryName, MethodSels, MethodTypes, false), PtrTy)); + // Class method list + Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList( + ClassName, CategoryName, MethodSels, MethodTypes, true), PtrTy)); + // Protocol list + llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(PtrTy, + ExistingProtocols.size()); + llvm::StructType *ProtocolListTy = llvm::StructType::get(VMContext, + PtrTy, //Should be a recurisve pointer, but it's always NULL here. + LongTy,//FIXME: Should be size_t + ProtocolArrayTy, + NULL); + std::vector ProtocolElements; + for (llvm::StringMapIterator iter = + ExistingProtocols.begin(), endIter = ExistingProtocols.end(); + iter != endIter ; iter++) { + llvm::Constant *Ptr = llvm::ConstantExpr::getBitCast(iter->getValue(), + PtrTy); + ProtocolElements.push_back(Ptr); + } + llvm::Constant * ProtocolArray = llvm::ConstantArray::get(ProtocolArrayTy, + ProtocolElements); + ProtocolElements.clear(); + ProtocolElements.push_back(NULLPtr); + ProtocolElements.push_back(llvm::ConstantInt::get(LongTy, + ExistingProtocols.size())); + ProtocolElements.push_back(ProtocolArray); + Elements.push_back(llvm::ConstantExpr::getBitCast(MakeGlobal(ProtocolListTy, + ProtocolElements, ".objc_protocol_list"), PtrTy)); + Categories.push_back(llvm::ConstantExpr::getBitCast( + MakeGlobal(llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty, + PtrTy, PtrTy, PtrTy, NULL), Elements), PtrTy)); +} void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) { std::string ClassName = OCD->getClassInterface()->getNameAsString(); @@ -799,19 +1026,19 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) { InstanceMethodSels.push_back((*iter)->getSelector()); std::string TypeStr; CGM.getContext().getObjCEncodingForMethodDecl(*iter,TypeStr); - InstanceMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr)); + InstanceMethodTypes.push_back(MakeConstantString(TypeStr)); } // Collect information about class methods llvm::SmallVector ClassMethodSels; llvm::SmallVector ClassMethodTypes; - for (ObjCCategoryImplDecl::classmeth_iterator + for (ObjCCategoryImplDecl::classmeth_iterator iter = OCD->classmeth_begin(), endIter = OCD->classmeth_end(); iter != endIter ; iter++) { ClassMethodSels.push_back((*iter)->getSelector()); std::string TypeStr; CGM.getContext().getObjCEncodingForMethodDecl(*iter,TypeStr); - ClassMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr)); + ClassMethodTypes.push_back(MakeConstantString(TypeStr)); } // Collect the names of referenced protocols @@ -825,7 +1052,7 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) { std::vector Elements; Elements.push_back(MakeConstantString(CategoryName)); Elements.push_back(MakeConstantString(ClassName)); - // Instance method list + // Instance method list Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList( ClassName, CategoryName, InstanceMethodSels, InstanceMethodTypes, false), PtrTy)); @@ -837,15 +1064,82 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) { Elements.push_back(llvm::ConstantExpr::getBitCast( GenerateProtocolList(Protocols), PtrTy)); Categories.push_back(llvm::ConstantExpr::getBitCast( - MakeGlobal(llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, PtrTy, - PtrTy, PtrTy, NULL), Elements), PtrTy)); + MakeGlobal(llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty, + PtrTy, PtrTy, PtrTy, NULL), Elements), PtrTy)); +} + +llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OID, + llvm::SmallVectorImpl &InstanceMethodSels, + llvm::SmallVectorImpl &InstanceMethodTypes) { + ASTContext &Context = CGM.getContext(); + // + // Property metadata: name, attributes, isSynthesized, setter name, setter + // types, getter name, getter types. + llvm::StructType *PropertyMetadataTy = llvm::StructType::get(VMContext, + PtrToInt8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, + PtrToInt8Ty, NULL); + std::vector Properties; + + + // Add all of the property methods need adding to the method list and to the + // property metadata list. + for (ObjCImplDecl::propimpl_iterator + iter = OID->propimpl_begin(), endIter = OID->propimpl_end(); + iter != endIter ; iter++) { + std::vector Fields; + ObjCPropertyDecl *property = (*iter)->getPropertyDecl(); + + Fields.push_back(MakeConstantString(property->getNameAsString())); + Fields.push_back(llvm::ConstantInt::get(Int8Ty, + property->getPropertyAttributes())); + Fields.push_back(llvm::ConstantInt::get(Int8Ty, + (*iter)->getPropertyImplementation() == + ObjCPropertyImplDecl::Synthesize)); + if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) { + InstanceMethodSels.push_back(getter->getSelector()); + std::string TypeStr; + Context.getObjCEncodingForMethodDecl(getter,TypeStr); + llvm::Constant *TypeEncoding = MakeConstantString(TypeStr); + InstanceMethodTypes.push_back(TypeEncoding); + Fields.push_back(MakeConstantString(getter->getSelector().getAsString())); + Fields.push_back(TypeEncoding); + } else { + Fields.push_back(NULLPtr); + Fields.push_back(NULLPtr); + } + if (ObjCMethodDecl *setter = property->getSetterMethodDecl()) { + InstanceMethodSels.push_back(setter->getSelector()); + std::string TypeStr; + Context.getObjCEncodingForMethodDecl(setter,TypeStr); + llvm::Constant *TypeEncoding = MakeConstantString(TypeStr); + InstanceMethodTypes.push_back(TypeEncoding); + Fields.push_back(MakeConstantString(setter->getSelector().getAsString())); + Fields.push_back(TypeEncoding); + } else { + Fields.push_back(NULLPtr); + Fields.push_back(NULLPtr); + } + Properties.push_back(llvm::ConstantStruct::get(PropertyMetadataTy, Fields)); + } + llvm::ArrayType *PropertyArrayTy = + llvm::ArrayType::get(PropertyMetadataTy, Properties.size()); + llvm::Constant *PropertyArray = llvm::ConstantArray::get(PropertyArrayTy, + Properties); + llvm::Constant* PropertyListInitFields[] = + {llvm::ConstantInt::get(IntTy, Properties.size()), NULLPtr, PropertyArray}; + + llvm::Constant *PropertyListInit = + llvm::ConstantStruct::get(VMContext, PropertyListInitFields, 3, false); + return new llvm::GlobalVariable(TheModule, PropertyListInit->getType(), false, + llvm::GlobalValue::InternalLinkage, PropertyListInit, + ".objc_property_list"); } void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { ASTContext &Context = CGM.getContext(); // Get the superclass name. - const ObjCInterfaceDecl * SuperClassDecl = + const ObjCInterfaceDecl * SuperClassDecl = OID->getClassInterface()->getSuperClass(); std::string SuperClassName; if (SuperClassDecl) { @@ -860,14 +1154,15 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { // Emit the symbol that is used to generate linker errors if this class is // referenced in other modules but not declared. std::string classSymbolName = "__objc_class_name_" + ClassName; - if (llvm::GlobalVariable *symbol = + if (llvm::GlobalVariable *symbol = TheModule.getGlobalVariable(classSymbolName)) { symbol->setInitializer(llvm::ConstantInt::get(LongTy, 0)); } else { - new llvm::GlobalVariable(LongTy, false, llvm::GlobalValue::ExternalLinkage, - llvm::ConstantInt::get(LongTy, 0), classSymbolName, &TheModule); + new llvm::GlobalVariable(TheModule, LongTy, false, + llvm::GlobalValue::ExternalLinkage, llvm::ConstantInt::get(LongTy, 0), + classSymbolName); } - + // Get the size of instances. int instanceSize = Context.getASTObjCImplementationLayout(OID).getSize() / 8; @@ -875,8 +1170,10 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { llvm::SmallVector IvarNames; llvm::SmallVector IvarTypes; llvm::SmallVector IvarOffsets; - - int superInstanceSize = !SuperClassDecl ? 0 : + + std::vector IvarOffsetValues; + + int superInstanceSize = !SuperClassDecl ? 0 : Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize() / 8; // For non-fragile ivars, set the instance size to 0 - {the size of just this // class}. The runtime will then set this to the correct value on load. @@ -886,54 +1183,49 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { for (ObjCInterfaceDecl::ivar_iterator iter = ClassDecl->ivar_begin(), endIter = ClassDecl->ivar_end() ; iter != endIter ; iter++) { // Store the name - IvarNames.push_back(CGM.GetAddrOfConstantCString((*iter) - ->getNameAsString())); + IvarNames.push_back(MakeConstantString((*iter)->getNameAsString())); // Get the type encoding for this ivar std::string TypeStr; Context.getObjCEncodingForType((*iter)->getType(), TypeStr); - IvarTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr)); + IvarTypes.push_back(MakeConstantString(TypeStr)); // Get the offset - uint64_t Offset; + uint64_t Offset = 0; + uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter); if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { - Offset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter) - - superInstanceSize; - ObjCIvarOffsetVariable(ClassDecl, *iter); - } else { - Offset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter); + Offset = BaseOffset - superInstanceSize; } IvarOffsets.push_back( - llvm::ConstantInt::get(llvm::Type::Int32Ty, Offset)); + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Offset)); + IvarOffsetValues.push_back(new llvm::GlobalVariable(TheModule, IntTy, + false, llvm::GlobalValue::ExternalLinkage, + llvm::ConstantInt::get(IntTy, BaseOffset), + "__objc_ivar_offset_value_" + ClassName +"." + + (*iter)->getNameAsString())); } + llvm::Constant *IvarOffsetArrayInit = + llvm::ConstantArray::get(llvm::ArrayType::get(PtrToIntTy, + IvarOffsetValues.size()), IvarOffsetValues); + llvm::GlobalVariable *IvarOffsetArray = new llvm::GlobalVariable(TheModule, + IvarOffsetArrayInit->getType(), false, + llvm::GlobalValue::InternalLinkage, IvarOffsetArrayInit, + ".ivar.offsets"); // Collect information about instance methods llvm::SmallVector InstanceMethodSels; llvm::SmallVector InstanceMethodTypes; - for (ObjCImplementationDecl::instmeth_iterator + for (ObjCImplementationDecl::instmeth_iterator iter = OID->instmeth_begin(), endIter = OID->instmeth_end(); iter != endIter ; iter++) { InstanceMethodSels.push_back((*iter)->getSelector()); std::string TypeStr; Context.getObjCEncodingForMethodDecl((*iter),TypeStr); - InstanceMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr)); - } - for (ObjCImplDecl::propimpl_iterator - iter = OID->propimpl_begin(), endIter = OID->propimpl_end(); - iter != endIter ; iter++) { - ObjCPropertyDecl *property = (*iter)->getPropertyDecl(); - if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) { - InstanceMethodSels.push_back(getter->getSelector()); - std::string TypeStr; - Context.getObjCEncodingForMethodDecl(getter,TypeStr); - InstanceMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr)); - } - if (ObjCMethodDecl *setter = property->getSetterMethodDecl()) { - InstanceMethodSels.push_back(setter->getSelector()); - std::string TypeStr; - Context.getObjCEncodingForMethodDecl(setter,TypeStr); - InstanceMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr)); - } + InstanceMethodTypes.push_back(MakeConstantString(TypeStr)); } + llvm::Constant *Properties = GeneratePropertyList(OID, InstanceMethodSels, + InstanceMethodTypes); + + // Collect information about class methods llvm::SmallVector ClassMethodSels; llvm::SmallVector ClassMethodTypes; @@ -943,7 +1235,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { ClassMethodSels.push_back((*iter)->getSelector()); std::string TypeStr; Context.getObjCEncodingForMethodDecl((*iter),TypeStr); - ClassMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr)); + ClassMethodTypes.push_back(MakeConstantString(TypeStr)); } // Collect the names of referenced protocols llvm::SmallVector Protocols; @@ -970,17 +1262,55 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { ClassMethodSels, ClassMethodTypes, true); llvm::Constant *IvarList = GenerateIvarList(IvarNames, IvarTypes, IvarOffsets); + // Irrespective of whether we are compiling for a fragile or non-fragile ABI, + // we emit a symbol containing the offset for each ivar in the class. This + // allows code compiled for the non-Fragile ABI to inherit from code compiled + // for the legacy ABI, without causing problems. The converse is also + // possible, but causes all ivar accesses to be fragile. + int i = 0; + // Offset pointer for getting at the correct field in the ivar list when + // setting up the alias. These are: The base address for the global, the + // ivar array (second field), the ivar in this list (set for each ivar), and + // the offset (third field in ivar structure) + const llvm::Type *IndexTy = llvm::Type::getInt32Ty(VMContext); + llvm::Constant *offsetPointerIndexes[] = {Zeros[0], + llvm::ConstantInt::get(IndexTy, 1), 0, + llvm::ConstantInt::get(IndexTy, 2) }; + + for (ObjCInterfaceDecl::ivar_iterator iter = ClassDecl->ivar_begin(), + endIter = ClassDecl->ivar_end() ; iter != endIter ; iter++) { + const std::string Name = "__objc_ivar_offset_" + ClassName + '.' + +(*iter)->getNameAsString(); + offsetPointerIndexes[2] = llvm::ConstantInt::get(IndexTy, i++); + // Get the correct ivar field + llvm::Constant *offsetValue = llvm::ConstantExpr::getGetElementPtr( + IvarList, offsetPointerIndexes, 4); + // Get the existing alias, if one exists. + llvm::GlobalVariable *offset = TheModule.getNamedGlobal(Name); + if (offset) { + offset->setInitializer(offsetValue); + // If this is the real definition, change its linkage type so that + // different modules will use this one, rather than their private + // copy. + offset->setLinkage(llvm::GlobalValue::ExternalLinkage); + } else { + // Add a new alias if there isn't one already. + offset = new llvm::GlobalVariable(TheModule, offsetValue->getType(), + false, llvm::GlobalValue::ExternalLinkage, offsetValue, Name); + } + } //Generate metaclass for class methods llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr, - NULLPtr, 0x2L, /*name*/"", 0, Zeros[0], GenerateIvarList( - empty, empty, empty), ClassMethodList, NULLPtr); + NULLPtr, 0x12L, /*name*/"", 0, Zeros[0], GenerateIvarList( + empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr); // Generate the class structure llvm::Constant *ClassStruct = - GenerateClassStructure(MetaClassStruct, SuperClass, 0x1L, + GenerateClassStructure(MetaClassStruct, SuperClass, 0x11L, ClassName.c_str(), 0, llvm::ConstantInt::get(LongTy, instanceSize), IvarList, - MethodList, GenerateProtocolList(Protocols)); + MethodList, GenerateProtocolList(Protocols), IvarOffsetArray, + Properties); // Resolve the class aliases, if they exist. if (ClassPtrAlias) { @@ -999,23 +1329,24 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { Classes.push_back(ClassStruct); } -void CGObjCGNU::MergeMetadataGlobals( - std::vector &UsedArray) { -} -llvm::Function *CGObjCGNU::ModuleInitFunction() { +llvm::Function *CGObjCGNU::ModuleInitFunction() { // Only emit an ObjC load function if no Objective-C stuff has been called if (Classes.empty() && Categories.empty() && ConstantStrings.empty() && ExistingProtocols.empty() && TypedSelectors.empty() && UntypedSelectors.empty()) return NULL; + // Add all referenced protocols to a category. + GenerateProtocolHolderCategory(); + const llvm::StructType *SelStructTy = dyn_cast( SelectorTy->getElementType()); const llvm::Type *SelStructPtrTy = SelectorTy; bool isSelOpaque = false; if (SelStructTy == 0) { - SelStructTy = llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, NULL); + SelStructTy = llvm::StructType::get(VMContext, PtrToInt8Ty, + PtrToInt8Ty, NULL); SelStructPtrTy = llvm::PointerType::getUnqual(SelStructTy); isSelOpaque = true; } @@ -1032,13 +1363,17 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { llvm::ArrayType *StaticsArrayTy = llvm::ArrayType::get(PtrToInt8Ty, ConstantStrings.size() + 1); ConstantStrings.push_back(NULLPtr); - Elements.push_back(MakeConstantString("NSConstantString", - ".objc_static_class_name")); + + const char *StringClass = CGM.getLangOptions().ObjCConstantStringClass; + if (!StringClass) StringClass = "NXConstantString"; + Elements.push_back(MakeConstantString(StringClass, + ".objc_static_class_name")); Elements.push_back(llvm::ConstantArray::get(StaticsArrayTy, ConstantStrings)); - llvm::StructType *StaticsListTy = - llvm::StructType::get(PtrToInt8Ty, StaticsArrayTy, NULL); - llvm::Type *StaticsListPtrTy = llvm::PointerType::getUnqual(StaticsListTy); + llvm::StructType *StaticsListTy = + llvm::StructType::get(VMContext, PtrToInt8Ty, StaticsArrayTy, NULL); + llvm::Type *StaticsListPtrTy = + llvm::PointerType::getUnqual(StaticsListTy); Statics = MakeGlobal(StaticsListTy, Elements, ".objc_statics"); llvm::ArrayType *StaticsListArrayTy = llvm::ArrayType::get(StaticsListPtrTy, 2); @@ -1051,9 +1386,10 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { // Array of classes, categories, and constant objects llvm::ArrayType *ClassListTy = llvm::ArrayType::get(PtrToInt8Ty, Classes.size() + Categories.size() + 2); - llvm::StructType *SymTabTy = llvm::StructType::get(LongTy, SelStructPtrTy, - llvm::Type::Int16Ty, - llvm::Type::Int16Ty, + llvm::StructType *SymTabTy = llvm::StructType::get(VMContext, + LongTy, SelStructPtrTy, + llvm::Type::getInt16Ty(VMContext), + llvm::Type::getInt16Ty(VMContext), ClassListTy, NULL); Elements.clear(); @@ -1062,7 +1398,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { for (std::map::iterator iter = TypedSelectors.begin(), iterEnd = TypedSelectors.end(); iter != iterEnd ; ++iter) { - Elements.push_back(MakeConstantString(iter->first.first, ".objc_sel_name")); + Elements.push_back(ExportUniqueString(iter->first.first, ".objc_sel_name")); Elements.push_back(MakeConstantString(iter->first.second, ".objc_sel_types")); Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements)); @@ -1072,7 +1408,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { iter = UntypedSelectors.begin(), iterEnd = UntypedSelectors.end(); iter != iterEnd; ++iter) { Elements.push_back( - MakeConstantString(iter->getKeyData(), ".objc_sel_name")); + ExportUniqueString(iter->getKeyData(), ".objc_sel_name")); Elements.push_back(NULLPtr); Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements)); Elements.clear(); @@ -1086,7 +1422,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { llvm::Constant *SelectorList = MakeGlobal( llvm::ArrayType::get(SelStructTy, Selectors.size()), Selectors, ".objc_selector_list"); - Elements.push_back(llvm::ConstantExpr::getBitCast(SelectorList, + Elements.push_back(llvm::ConstantExpr::getBitCast(SelectorList, SelStructPtrTy)); // Now that all of the static selectors exist, create pointers to them. @@ -1095,11 +1431,11 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { iter=TypedSelectors.begin(), iterEnd =TypedSelectors.end(); iter != iterEnd; ++iter) { llvm::Constant *Idxs[] = {Zeros[0], - llvm::ConstantInt::get(llvm::Type::Int32Ty, index++), Zeros[0]}; - llvm::Constant *SelPtr = new llvm::GlobalVariable(SelStructPtrTy, + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), index++), Zeros[0]}; + llvm::Constant *SelPtr = new llvm::GlobalVariable(TheModule, SelStructPtrTy, true, llvm::GlobalValue::InternalLinkage, llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2), - ".objc_sel_ptr", &TheModule); + ".objc_sel_ptr"); // If selectors are defined as an opaque type, cast the pointer to this // type. if (isSelOpaque) { @@ -1112,11 +1448,12 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { iter=UntypedSelectors.begin(), iterEnd = UntypedSelectors.end(); iter != iterEnd; iter++) { llvm::Constant *Idxs[] = {Zeros[0], - llvm::ConstantInt::get(llvm::Type::Int32Ty, index++), Zeros[0]}; - llvm::Constant *SelPtr = new llvm::GlobalVariable(SelStructPtrTy, true, - llvm::GlobalValue::InternalLinkage, - llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2), - ".objc_sel_ptr", &TheModule); + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), index++), Zeros[0]}; + llvm::Constant *SelPtr = new llvm::GlobalVariable + (TheModule, SelStructPtrTy, + true, llvm::GlobalValue::InternalLinkage, + llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2), + ".objc_sel_ptr"); // If selectors are defined as an opaque type, cast the pointer to this // type. if (isSelOpaque) { @@ -1126,10 +1463,10 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { (*iter).second->setAliasee(SelPtr); } // Number of classes defined. - Elements.push_back(llvm::ConstantInt::get(llvm::Type::Int16Ty, + Elements.push_back(llvm::ConstantInt::get(llvm::Type::getInt16Ty(VMContext), Classes.size())); // Number of categories defined - Elements.push_back(llvm::ConstantInt::get(llvm::Type::Int16Ty, + Elements.push_back(llvm::ConstantInt::get(llvm::Type::getInt16Ty(VMContext), Categories.size())); // Create an array of classes, then categories, then static object instances Classes.insert(Classes.end(), Categories.begin(), Categories.end()); @@ -1138,24 +1475,25 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { Classes.push_back(NULLPtr); llvm::Constant *ClassList = llvm::ConstantArray::get(ClassListTy, Classes); Elements.push_back(ClassList); - // Construct the symbol table + // Construct the symbol table llvm::Constant *SymTab= MakeGlobal(SymTabTy, Elements); // The symbol table is contained in a module which has some version-checking // constants - llvm::StructType * ModuleTy = llvm::StructType::get(LongTy, LongTy, + llvm::StructType * ModuleTy = llvm::StructType::get(VMContext, LongTy, LongTy, PtrToInt8Ty, llvm::PointerType::getUnqual(SymTabTy), NULL); Elements.clear(); // Runtime version used for compatibility checking. if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { - Elements.push_back(llvm::ConstantInt::get(LongTy, + Elements.push_back(llvm::ConstantInt::get(LongTy, NonFragileRuntimeVersion)); } else { Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion)); } // sizeof(ModuleTy) llvm::TargetData td = llvm::TargetData::TargetData(&TheModule); - Elements.push_back(llvm::ConstantInt::get(LongTy, td.getTypeSizeInBits(ModuleTy)/8)); + Elements.push_back(llvm::ConstantInt::get(LongTy, + td.getTypeSizeInBits(ModuleTy)/8)); //FIXME: Should be the path to the file where this module was declared Elements.push_back(NULLPtr); Elements.push_back(SymTab); @@ -1164,17 +1502,18 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { // Create the load function calling the runtime entry point with the module // structure llvm::Function * LoadFunction = llvm::Function::Create( - llvm::FunctionType::get(llvm::Type::VoidTy, false), + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false), llvm::GlobalValue::InternalLinkage, ".objc_load_function", &TheModule); - llvm::BasicBlock *EntryBB = llvm::BasicBlock::Create("entry", LoadFunction); - CGBuilderTy Builder; + llvm::BasicBlock *EntryBB = + llvm::BasicBlock::Create(VMContext, "entry", LoadFunction); + CGBuilderTy Builder(VMContext); Builder.SetInsertPoint(EntryBB); std::vector Params(1, llvm::PointerType::getUnqual(ModuleTy)); llvm::Value *Register = CGM.CreateRuntimeFunction(llvm::FunctionType::get( - llvm::Type::VoidTy, Params, true), "__objc_exec_class"); + llvm::Type::getVoidTy(VMContext), Params, true), "__objc_exec_class"); Builder.CreateCall(Register, Module); Builder.CreateRetVoid(); @@ -1182,8 +1521,8 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { } llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD, - const ObjCContainerDecl *CD) { - const ObjCCategoryImplDecl *OCD = + const ObjCContainerDecl *CD) { + const ObjCCategoryImplDecl *OCD = dyn_cast(OMD->getDeclContext()); std::string CategoryName = OCD ? OCD->getNameAsString() : ""; std::string ClassName = OMD->getClassInterface()->getNameAsString(); @@ -1191,71 +1530,76 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD, bool isClassMethod = !OMD->isInstanceMethod(); CodeGenTypes &Types = CGM.getTypes(); - const llvm::FunctionType *MethodTy = + const llvm::FunctionType *MethodTy = Types.GetFunctionType(Types.getFunctionInfo(OMD), OMD->isVariadic()); std::string FunctionName = SymbolNameForMethod(ClassName, CategoryName, MethodName, isClassMethod); - llvm::Function *Method = llvm::Function::Create(MethodTy, - llvm::GlobalValue::InternalLinkage, - FunctionName, - &TheModule); + llvm::Function *Method + = llvm::Function::Create(MethodTy, + llvm::GlobalValue::InternalLinkage, + FunctionName, + &TheModule); return Method; } llvm::Function *CGObjCGNU::GetPropertyGetFunction() { - std::vector Params; - const llvm::Type *BoolTy = - CGM.getTypes().ConvertType(CGM.getContext().BoolTy); - Params.push_back(IdTy); - Params.push_back(SelectorTy); - // FIXME: Using LongTy for ptrdiff_t is probably broken on Win64 - Params.push_back(LongTy); - Params.push_back(BoolTy); - // void objc_getProperty (id, SEL, ptrdiff_t, bool) - const llvm::FunctionType *FTy = - llvm::FunctionType::get(IdTy, Params, false); - return cast(CGM.CreateRuntimeFunction(FTy, - "objc_getProperty")); + std::vector Params; + const llvm::Type *BoolTy = + CGM.getTypes().ConvertType(CGM.getContext().BoolTy); + Params.push_back(IdTy); + Params.push_back(SelectorTy); + // FIXME: Using LongTy for ptrdiff_t is probably broken on Win64 + Params.push_back(LongTy); + Params.push_back(BoolTy); + // void objc_getProperty (id, SEL, ptrdiff_t, bool) + const llvm::FunctionType *FTy = + llvm::FunctionType::get(IdTy, Params, false); + return cast(CGM.CreateRuntimeFunction(FTy, + "objc_getProperty")); } llvm::Function *CGObjCGNU::GetPropertySetFunction() { - std::vector Params; - const llvm::Type *BoolTy = - CGM.getTypes().ConvertType(CGM.getContext().BoolTy); - Params.push_back(IdTy); - Params.push_back(SelectorTy); - // FIXME: Using LongTy for ptrdiff_t is probably broken on Win64 - Params.push_back(LongTy); - Params.push_back(IdTy); - Params.push_back(BoolTy); - Params.push_back(BoolTy); - // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool) - const llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::VoidTy, Params, false); - return cast(CGM.CreateRuntimeFunction(FTy, - "objc_setProperty")); + std::vector Params; + const llvm::Type *BoolTy = + CGM.getTypes().ConvertType(CGM.getContext().BoolTy); + Params.push_back(IdTy); + Params.push_back(SelectorTy); + // FIXME: Using LongTy for ptrdiff_t is probably broken on Win64 + Params.push_back(LongTy); + Params.push_back(IdTy); + Params.push_back(BoolTy); + Params.push_back(BoolTy); + // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool) + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false); + return cast(CGM.CreateRuntimeFunction(FTy, + "objc_setProperty")); } -llvm::Function *CGObjCGNU::EnumerationMutationFunction() { - std::vector Params(1, IdTy); - return cast(CGM.CreateRuntimeFunction( - llvm::FunctionType::get(llvm::Type::VoidTy, Params, true), - "objc_enumerationMutation")); +llvm::Constant *CGObjCGNU::EnumerationMutationFunction() { + CodeGen::CodeGenTypes &Types = CGM.getTypes(); + ASTContext &Ctx = CGM.getContext(); + // void objc_enumerationMutation (id) + llvm::SmallVector Params; + Params.push_back(ASTIdTy); + const llvm::FunctionType *FTy = + Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false); + return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation"); } void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, const Stmt &S) { // Pointer to the personality function llvm::Constant *Personality = - CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::Int32Ty, + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty(VMContext), true), "__gnu_objc_personality_v0"); Personality = llvm::ConstantExpr::getBitCast(Personality, PtrTy); std::vector Params; Params.push_back(PtrTy); llvm::Value *RethrowFn = - CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy, + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false), "_Unwind_Resume_or_Rethrow"); bool isTry = isa(S); @@ -1271,9 +1615,9 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, if (!isTry) { std::vector Args(1, IdTy); llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::VoidTy, Args, false); + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false); llvm::Value *SyncEnter = CGM.CreateRuntimeFunction(FTy, "objc_sync_enter"); - llvm::Value *SyncArg = + llvm::Value *SyncArg = CGF.EmitScalarExpr(cast(S).getSynchExpr()); SyncArg = CGF.Builder.CreateBitCast(SyncArg, IdTy); CGF.Builder.CreateCall(SyncEnter, SyncArg); @@ -1288,7 +1632,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.setInvokeDest(TryHandler); CGF.EmitBlock(TryBlock); - CGF.EmitStmt(isTry ? cast(S).getTryBody() + CGF.EmitStmt(isTry ? cast(S).getTryBody() : cast(S).getSynchBody()); // Jump to @finally if there is no exception @@ -1299,17 +1643,12 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // Get the correct versions of the exception handling intrinsics llvm::TargetData td = llvm::TargetData::TargetData(&TheModule); - int PointerWidth = td.getTypeSizeInBits(PtrTy); - assert((PointerWidth == 32 || PointerWidth == 64) && - "Can't yet handle exceptions if pointers are not 32 or 64 bits"); - llvm::Value *llvm_eh_exception = + llvm::Value *llvm_eh_exception = CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception); - llvm::Value *llvm_eh_selector = PointerWidth == 32 ? - CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector_i32) : - CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector_i64); - llvm::Value *llvm_eh_typeid_for = PointerWidth == 32 ? - CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for_i32) : - CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for_i64); + llvm::Value *llvm_eh_selector = + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector); + llvm::Value *llvm_eh_typeid_for = + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); // Exception object llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); @@ -1330,23 +1669,25 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) { const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); - Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody())); + Handlers.push_back(std::make_pair(CatchDecl, + CatchStmt->getCatchBody())); // @catch() and @catch(id) both catch any ObjC exception - if (!CatchDecl || CGF.getContext().isObjCIdType(CatchDecl->getType()) + if (!CatchDecl || CatchDecl->getType()->isObjCIdType() || CatchDecl->getType()->isObjCQualifiedIdType()) { // Use i8* null here to signal this is a catch all, not a cleanup. ESelArgs.push_back(NULLPtr); HasCatchAll = true; // No further catches after this one will ever by reached break; - } + } // All other types should be Objective-C interface pointer types. - const PointerType *PT = CatchDecl->getType()->getAsPointerType(); - assert(PT && "Invalid @catch type."); - const ObjCInterfaceType *IT = - PT->getPointeeType()->getAsObjCInterfaceType(); + const ObjCObjectPointerType *OPT = + CatchDecl->getType()->getAs(); + assert(OPT && "Invalid @catch type."); + const ObjCInterfaceType *IT = + OPT->getPointeeType()->getAs(); assert(IT && "Invalid @catch type."); llvm::Value *EHType = MakeConstantString(IT->getDecl()->getNameAsString()); @@ -1357,7 +1698,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // We use a cleanup unless there was already a catch all. if (!HasCatchAll) { - ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, 0)); + ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0)); Handlers.push_back(std::make_pair((const ParmVarDecl*) 0, (const Stmt*) 0)); } @@ -1386,11 +1727,11 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.EmitBlock(Match); } - + if (CatchBody) { llvm::Value *ExcObject = CGF.Builder.CreateBitCast(Exc, CGF.ConvertType(CatchParam->getType())); - + // Bind the catch parameter if it exists. if (CatchParam) { // CatchParam is a ParmVarDecl because of the grammar @@ -1422,7 +1763,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, ESelArgs.clear(); ESelArgs.push_back(Exc); ESelArgs.push_back(Personality); - ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, 0)); + ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0)); CGF.Builder.CreateCall(llvm_eh_selector, ESelArgs.begin(), ESelArgs.end(), "selector"); CGF.Builder.CreateCall(llvm_eh_typeid_for, @@ -1438,7 +1779,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, if (isTry) { - if (const ObjCAtFinallyStmt* FinallyStmt = + if (const ObjCAtFinallyStmt* FinallyStmt = cast(S).getFinallyStmt()) CGF.EmitStmt(FinallyStmt->getFinallyBody()); } else { @@ -1446,9 +1787,9 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // @synchronized. std::vector Args(1, IdTy); llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::VoidTy, Args, false); + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false); llvm::Value *SyncExit = CGM.CreateRuntimeFunction(FTy, "objc_sync_exit"); - llvm::Value *SyncArg = + llvm::Value *SyncArg = CGF.EmitScalarExpr(cast(S).getSynchExpr()); SyncArg = CGF.Builder.CreateBitCast(SyncArg, IdTy); CGF.Builder.CreateCall(SyncExit, SyncArg); @@ -1465,7 +1806,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.EmitBlock(FinallyRethrow); CGF.Builder.CreateCall(RethrowFn, CGF.Builder.CreateLoad(RethrowPtr)); CGF.Builder.CreateUnreachable(); - + CGF.EmitBlock(FinallyEnd); } @@ -1476,21 +1817,21 @@ void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, std::vector Args(1, IdTy); llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::VoidTy, Args, false); - llvm::Value *ThrowFn = + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false); + llvm::Value *ThrowFn = CGM.CreateRuntimeFunction(FTy, "objc_exception_throw"); - + if (const Expr *ThrowExpr = S.getThrowExpr()) { llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr); ExceptionAsObject = Exception; } else { - assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) && + assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) && "Unexpected rethrow outside @catch block."); ExceptionAsObject = CGF.ObjCEHValueStack.back(); } ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy, "tmp"); - + // Note: This may have to be an invoke, if we want to support constructs like: // @try { // @throw(obj); @@ -1513,32 +1854,35 @@ void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, } llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF, - llvm::Value *AddrWeakObj) -{ + llvm::Value *AddrWeakObj) { return 0; } void CGObjCGNU::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dst) -{ + llvm::Value *src, llvm::Value *dst) { return; } void CGObjCGNU::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dst) -{ + llvm::Value *src, llvm::Value *dst) { return; } void CGObjCGNU::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dst) -{ + llvm::Value *src, llvm::Value *dst, + llvm::Value *ivarOffset) { return; } void CGObjCGNU::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dst) -{ + llvm::Value *src, llvm::Value *dst) { + return; +} + +void CGObjCGNU::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, + llvm::Value *DestPtr, + llvm::Value *SrcPtr, + QualType Ty) { return; } @@ -1550,15 +1894,29 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable( // Emit the variable and initialize it with what we think the correct value // is. This allows code compiled with non-fragile ivars to work correctly // when linked against code which isn't (most of the time). - llvm::GlobalVariable *IvarOffsetGV = CGM.getModule().getGlobalVariable(Name); - if (!IvarOffsetGV) { + llvm::GlobalVariable *IvarOffsetPointer = TheModule.getNamedGlobal(Name); + if (!IvarOffsetPointer) { uint64_t Offset = ComputeIvarBaseOffset(CGM, ID, Ivar); llvm::ConstantInt *OffsetGuess = llvm::ConstantInt::get(LongTy, Offset, "ivar"); - IvarOffsetGV = new llvm::GlobalVariable(LongTy, false, - llvm::GlobalValue::CommonLinkage, OffsetGuess, Name, &TheModule); + // Don't emit the guess in non-PIC code because the linker will not be able + // to replace it with the real version for a library. In non-PIC code you + // must compile with the fragile ABI if you want to use ivars from a + // GCC-compiled class. + if (CGM.getLangOptions().PICLevel) { + llvm::GlobalVariable *IvarOffsetGV = new llvm::GlobalVariable(TheModule, + llvm::Type::getInt32Ty(VMContext), false, + llvm::GlobalValue::PrivateLinkage, OffsetGuess, Name+".guess"); + IvarOffsetPointer = new llvm::GlobalVariable(TheModule, + IvarOffsetGV->getType(), false, llvm::GlobalValue::LinkOnceAnyLinkage, + IvarOffsetGV, Name); + } else { + IvarOffsetPointer = new llvm::GlobalVariable(TheModule, + llvm::Type::getInt32PtrTy(VMContext), false, + llvm::GlobalValue::ExternalLinkage, 0, Name); + } } - return IvarOffsetGV; + return IvarOffsetPointer; } LValue CGObjCGNU::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, @@ -1566,10 +1924,11 @@ LValue CGObjCGNU::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, llvm::Value *BaseValue, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers) { - const ObjCInterfaceDecl *ID = ObjectTy->getAsObjCInterfaceType()->getDecl(); + const ObjCInterfaceDecl *ID = ObjectTy->getAs()->getDecl(); return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers, EmitIvarOffset(CGF, ID, Ivar)); } + static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context, const ObjCInterfaceDecl *OID, const ObjCIvarDecl *OIVD) { @@ -1579,27 +1938,27 @@ static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context, if (OIVD == Ivars[k]) return OID; } - + // Otherwise check in the super class. if (const ObjCInterfaceDecl *Super = OID->getSuperClass()) return FindIvarInterface(Context, Super, OIVD); - + return 0; } llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGen::CodeGenFunction &CGF, const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar) { - if (CGF.getContext().getLangOptions().ObjCNonFragileABI) - { + if (CGM.getLangOptions().ObjCNonFragileABI) { Interface = FindIvarInterface(CGM.getContext(), Interface, Ivar); - return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar), - false, "ivar"); + return CGF.Builder.CreateLoad(CGF.Builder.CreateLoad( + ObjCIvarOffsetVariable(Interface, Ivar), false, "ivar")); } uint64_t Offset = ComputeIvarBaseOffset(CGF.CGM, Interface, Ivar); return llvm::ConstantInt::get(LongTy, Offset, "ivar"); } -CodeGen::CGObjCRuntime *CodeGen::CreateGNUObjCRuntime(CodeGen::CodeGenModule &CGM){ +CodeGen::CGObjCRuntime * +CodeGen::CreateGNUObjCRuntime(CodeGen::CodeGenModule &CGM) { return new CGObjCGNU(CGM); } diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index c3354574c775..4485ed5aee75 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -23,10 +23,14 @@ #include "clang/Basic/LangOptions.h" #include "llvm/Intrinsics.h" +#include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetData.h" -#include +#include using namespace clang; using namespace CodeGen; @@ -35,7 +39,7 @@ using namespace CodeGen; // don't belong in CGObjCRuntime either so we will live with it for // now. -/// FindIvarInterface - Find the interface containing the ivar. +/// FindIvarInterface - Find the interface containing the ivar. /// /// FIXME: We shouldn't need to do this, the containing context should /// be fixed. @@ -54,11 +58,11 @@ static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context, return OID; ++Index; } - + // Otherwise check in the super class. if (const ObjCInterfaceDecl *Super = OID->getSuperClass()) return FindIvarInterface(Context, Super, OIVD, Index); - + return 0; } @@ -67,13 +71,13 @@ static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM, const ObjCImplementationDecl *ID, const ObjCIvarDecl *Ivar) { unsigned Index; - const ObjCInterfaceDecl *Container = + const ObjCInterfaceDecl *Container = FindIvarInterface(CGM.getContext(), OID, Ivar, Index); assert(Container && "Unable to find ivar container"); // If we know have an implementation (and the ivar is in it) then // look up in the implementation layout. - const ASTRecordLayout *RL; + const ASTRecordLayout *RL; if (ID && ID->getClassInterface() == Container) RL = &CGM.getContext().getASTObjCImplementationLayout(ID); else @@ -100,13 +104,16 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, unsigned CVRQualifiers, llvm::Value *Offset) { // Compute (type*) ( (char *) BaseValue + Offset) - llvm::Type *I8Ptr = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *I8Ptr = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); QualType IvarTy = Ivar->getType(); const llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy); llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, I8Ptr); V = CGF.Builder.CreateGEP(V, Offset, "add.ptr"); V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy)); - + + Qualifiers Quals = CGF.MakeQualifiers(IvarTy); + Quals.addCVRQualifiers(CVRQualifiers); + if (Ivar->isBitField()) { // We need to compute the bit offset for the bit-field, the offset // is to the byte. Note, there is a subtle invariant here: we can @@ -119,12 +126,11 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, Ivar->getBitWidth()->EvaluateAsInt(CGF.getContext()).getZExtValue(); return LValue::MakeBitfield(V, BitOffset, BitFieldSize, IvarTy->isSignedIntegerType(), - IvarTy.getCVRQualifiers()|CVRQualifiers); + Quals.getCVRQualifiers()); } - LValue LV = LValue::MakeAddr(V, IvarTy.getCVRQualifiers()|CVRQualifiers, - CGF.CGM.getContext().getObjCGCAttrKind(IvarTy)); - LValue::SetObjCIvar(LV, true); + + LValue LV = LValue::MakeAddr(V, Quals); return LV; } @@ -132,12 +138,15 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, namespace { - typedef std::vector ConstantVector; +typedef std::vector ConstantVector; - // FIXME: We should find a nicer way to make the labels for metadata, string - // concatenation is lame. +// FIXME: We should find a nicer way to make the labels for metadata, string +// concatenation is lame. class ObjCCommonTypesHelper { +protected: + llvm::LLVMContext &VMContext; + private: llvm::Constant *getMessageSendFn() const { // id objc_msgSend (id, SEL, ...) @@ -145,23 +154,23 @@ private: Params.push_back(ObjectPtrTy); Params.push_back(SelectorPtrTy); return - CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, - Params, true), - "objc_msgSend"); + CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, + Params, true), + "objc_msgSend"); } - + llvm::Constant *getMessageSendStretFn() const { // id objc_msgSend_stret (id, SEL, ...) std::vector Params; Params.push_back(ObjectPtrTy); Params.push_back(SelectorPtrTy); return - CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy, - Params, true), - "objc_msgSend_stret"); - + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + Params, true), + "objc_msgSend_stret"); + } - + llvm::Constant *getMessageSendFpretFn() const { // FIXME: This should be long double on x86_64? // [double | long double] objc_msgSend_fpret(id self, SEL op, ...) @@ -169,13 +178,14 @@ private: Params.push_back(ObjectPtrTy); Params.push_back(SelectorPtrTy); return - CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::DoubleTy, - Params, - true), - "objc_msgSend_fpret"); - + CGM.CreateRuntimeFunction(llvm::FunctionType::get( + llvm::Type::getDoubleTy(VMContext), + Params, + true), + "objc_msgSend_fpret"); + } - + llvm::Constant *getMessageSendSuperFn() const { // id objc_msgSendSuper(struct objc_super *super, SEL op, ...) const char *SuperName = "objc_msgSendSuper"; @@ -186,7 +196,7 @@ private: Params, true), SuperName); } - + llvm::Constant *getMessageSendSuperFn2() const { // id objc_msgSendSuper2(struct objc_super *super, SEL op, ...) const char *SuperName = "objc_msgSendSuper2"; @@ -197,7 +207,7 @@ private: Params, true), SuperName); } - + llvm::Constant *getMessageSendSuperStretFn() const { // void objc_msgSendSuper_stret(void * stretAddr, struct objc_super *super, // SEL op, ...) @@ -205,11 +215,12 @@ private: Params.push_back(Int8PtrTy); Params.push_back(SuperPtrTy); Params.push_back(SelectorPtrTy); - return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy, - Params, true), - "objc_msgSendSuper_stret"); + return CGM.CreateRuntimeFunction( + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + Params, true), + "objc_msgSendSuper_stret"); } - + llvm::Constant *getMessageSendSuperStretFn2() const { // void objc_msgSendSuper2_stret(void * stretAddr, struct objc_super *super, // SEL op, ...) @@ -217,68 +228,69 @@ private: Params.push_back(Int8PtrTy); Params.push_back(SuperPtrTy); Params.push_back(SelectorPtrTy); - return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy, - Params, true), - "objc_msgSendSuper2_stret"); + return CGM.CreateRuntimeFunction( + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + Params, true), + "objc_msgSendSuper2_stret"); } - + llvm::Constant *getMessageSendSuperFpretFn() const { // There is no objc_msgSendSuper_fpret? How can that work? return getMessageSendSuperFn(); } - + llvm::Constant *getMessageSendSuperFpretFn2() const { // There is no objc_msgSendSuper_fpret? How can that work? return getMessageSendSuperFn2(); } - + protected: CodeGen::CodeGenModule &CGM; - + public: const llvm::Type *ShortTy, *IntTy, *LongTy, *LongLongTy; const llvm::Type *Int8PtrTy; - + /// ObjectPtrTy - LLVM type for object handles (typeof(id)) const llvm::Type *ObjectPtrTy; - + /// PtrObjectPtrTy - LLVM type for id * const llvm::Type *PtrObjectPtrTy; - + /// SelectorPtrTy - LLVM type for selector handles (typeof(SEL)) const llvm::Type *SelectorPtrTy; /// ProtocolPtrTy - LLVM type for external protocol handles /// (typeof(Protocol)) const llvm::Type *ExternalProtocolPtrTy; - + // SuperCTy - clang type for struct objc_super. QualType SuperCTy; // SuperPtrCTy - clang type for struct objc_super *. QualType SuperPtrCTy; - + /// SuperTy - LLVM type for struct objc_super. const llvm::StructType *SuperTy; /// SuperPtrTy - LLVM type for struct objc_super *. const llvm::Type *SuperPtrTy; - + /// PropertyTy - LLVM type for struct objc_property (struct _prop_t /// in GCC parlance). const llvm::StructType *PropertyTy; - + /// PropertyListTy - LLVM type for struct objc_property_list /// (_prop_list_t in GCC parlance). const llvm::StructType *PropertyListTy; /// PropertyListPtrTy - LLVM type for struct objc_property_list*. const llvm::Type *PropertyListPtrTy; - + // MethodTy - LLVM type for struct objc_method. const llvm::StructType *MethodTy; - + /// CacheTy - LLVM type for struct objc_cache. const llvm::Type *CacheTy; /// CachePtrTy - LLVM type for struct objc_cache *. const llvm::Type *CachePtrTy; - + llvm::Constant *getGetPropertyFn() { CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); @@ -294,7 +306,7 @@ public: Types.GetFunctionType(Types.getFunctionInfo(IdType, Params), false); return CGM.CreateRuntimeFunction(FTy, "objc_getProperty"); } - + llvm::Constant *getSetPropertyFn() { CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); @@ -312,25 +324,28 @@ public: Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false); return CGM.CreateRuntimeFunction(FTy, "objc_setProperty"); } - + llvm::Constant *getEnumerationMutationFn() { + CodeGen::CodeGenTypes &Types = CGM.getTypes(); + ASTContext &Ctx = CGM.getContext(); // void objc_enumerationMutation (id) - std::vector Args; - Args.push_back(ObjectPtrTy); - llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::VoidTy, Args, false); + llvm::SmallVector Params; + Params.push_back(Ctx.getObjCIdType()); + const llvm::FunctionType *FTy = + Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false); return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation"); } - + /// GcReadWeakFn -- LLVM objc_read_weak (id *src) function. llvm::Constant *getGcReadWeakFn() { // id objc_read_weak (id *) std::vector Args; Args.push_back(ObjectPtrTy->getPointerTo()); - llvm::FunctionType *FTy = llvm::FunctionType::get(ObjectPtrTy, Args, false); + llvm::FunctionType *FTy = + llvm::FunctionType::get(ObjectPtrTy, Args, false); return CGM.CreateRuntimeFunction(FTy, "objc_read_weak"); - } - + } + /// GcAssignWeakFn -- LLVM objc_assign_weak function. llvm::Constant *getGcAssignWeakFn() { // id objc_assign_weak (id, id *) @@ -340,31 +355,45 @@ public: llvm::FunctionType::get(ObjectPtrTy, Args, false); return CGM.CreateRuntimeFunction(FTy, "objc_assign_weak"); } - + /// GcAssignGlobalFn -- LLVM objc_assign_global function. llvm::Constant *getGcAssignGlobalFn() { // id objc_assign_global(id, id *) std::vector Args(1, ObjectPtrTy); Args.push_back(ObjectPtrTy->getPointerTo()); - llvm::FunctionType *FTy = llvm::FunctionType::get(ObjectPtrTy, Args, false); + llvm::FunctionType *FTy = + llvm::FunctionType::get(ObjectPtrTy, Args, false); return CGM.CreateRuntimeFunction(FTy, "objc_assign_global"); } - + /// GcAssignIvarFn -- LLVM objc_assign_ivar function. llvm::Constant *getGcAssignIvarFn() { - // id objc_assign_ivar(id, id *) + // id objc_assign_ivar(id, id *, ptrdiff_t) std::vector Args(1, ObjectPtrTy); Args.push_back(ObjectPtrTy->getPointerTo()); - llvm::FunctionType *FTy = llvm::FunctionType::get(ObjectPtrTy, Args, false); + Args.push_back(LongTy); + llvm::FunctionType *FTy = + llvm::FunctionType::get(ObjectPtrTy, Args, false); return CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar"); } - + + /// GcMemmoveCollectableFn -- LLVM objc_memmove_collectable function. + llvm::Constant *GcMemmoveCollectableFn() { + // void *objc_memmove_collectable(void *dst, const void *src, size_t size) + std::vector Args(1, Int8PtrTy); + Args.push_back(Int8PtrTy); + Args.push_back(LongTy); + llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false); + return CGM.CreateRuntimeFunction(FTy, "objc_memmove_collectable"); + } + /// GcAssignStrongCastFn -- LLVM objc_assign_strongCast function. llvm::Constant *getGcAssignStrongCastFn() { // id objc_assign_global(id, id *) std::vector Args(1, ObjectPtrTy); Args.push_back(ObjectPtrTy->getPointerTo()); - llvm::FunctionType *FTy = llvm::FunctionType::get(ObjectPtrTy, Args, false); + llvm::FunctionType *FTy = + llvm::FunctionType::get(ObjectPtrTy, Args, false); return CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast"); } @@ -373,52 +402,52 @@ public: // void objc_exception_throw(id) std::vector Args(1, ObjectPtrTy); llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::VoidTy, Args, false); + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false); return CGM.CreateRuntimeFunction(FTy, "objc_exception_throw"); } - + /// SyncEnterFn - LLVM object_sync_enter function. llvm::Constant *getSyncEnterFn() { // void objc_sync_enter (id) std::vector Args(1, ObjectPtrTy); llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::VoidTy, Args, false); + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false); return CGM.CreateRuntimeFunction(FTy, "objc_sync_enter"); } - + /// SyncExitFn - LLVM object_sync_exit function. llvm::Constant *getSyncExitFn() { // void objc_sync_exit (id) std::vector Args(1, ObjectPtrTy); llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::VoidTy, Args, false); + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false); return CGM.CreateRuntimeFunction(FTy, "objc_sync_exit"); } - + llvm::Constant *getSendFn(bool IsSuper) const { return IsSuper ? getMessageSendSuperFn() : getMessageSendFn(); } - + llvm::Constant *getSendFn2(bool IsSuper) const { return IsSuper ? getMessageSendSuperFn2() : getMessageSendFn(); } - + llvm::Constant *getSendStretFn(bool IsSuper) const { return IsSuper ? getMessageSendSuperStretFn() : getMessageSendStretFn(); } - + llvm::Constant *getSendStretFn2(bool IsSuper) const { return IsSuper ? getMessageSendSuperStretFn2() : getMessageSendStretFn(); } - + llvm::Constant *getSendFpretFn(bool IsSuper) const { return IsSuper ? getMessageSendSuperFpretFn() : getMessageSendFpretFn(); } - + llvm::Constant *getSendFpretFn2(bool IsSuper) const { return IsSuper ? getMessageSendSuperFpretFn2() : getMessageSendFpretFn(); } - + ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm); ~ObjCCommonTypesHelper(){} }; @@ -477,26 +506,28 @@ public: const llvm::Type *MethodListTy; /// MethodListPtrTy - LLVM type for struct objc_method_list *. const llvm::Type *MethodListPtrTy; - + /// ExceptionDataTy - LLVM type for struct _objc_exception_data. const llvm::Type *ExceptionDataTy; - + /// ExceptionTryEnterFn - LLVM objc_exception_try_enter function. llvm::Constant *getExceptionTryEnterFn() { std::vector Params; Params.push_back(llvm::PointerType::getUnqual(ExceptionDataTy)); - return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy, - Params, false), - "objc_exception_try_enter"); + return CGM.CreateRuntimeFunction( + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + Params, false), + "objc_exception_try_enter"); } /// ExceptionTryExitFn - LLVM objc_exception_try_exit function. llvm::Constant *getExceptionTryExitFn() { std::vector Params; Params.push_back(llvm::PointerType::getUnqual(ExceptionDataTy)); - return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy, - Params, false), - "objc_exception_try_exit"); + return CGM.CreateRuntimeFunction( + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + Params, false), + "objc_exception_try_exit"); } /// ExceptionExtractFn - LLVM objc_exception_extract function. @@ -506,31 +537,32 @@ public: return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, Params, false), "objc_exception_extract"); - + } - + /// ExceptionMatchFn - LLVM objc_exception_match function. llvm::Constant *getExceptionMatchFn() { std::vector Params; Params.push_back(ClassPtrTy); Params.push_back(ObjectPtrTy); - return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::Int32Ty, - Params, false), - "objc_exception_match"); - + return CGM.CreateRuntimeFunction( + llvm::FunctionType::get(llvm::Type::getInt32Ty(VMContext), + Params, false), + "objc_exception_match"); + } - + /// SetJmpFn - LLVM _setjmp function. llvm::Constant *getSetJmpFn() { std::vector Params; - Params.push_back(llvm::PointerType::getUnqual(llvm::Type::Int32Ty)); + Params.push_back(llvm::Type::getInt32PtrTy(VMContext)); return - CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::Int32Ty, + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty(VMContext), Params, false), "_setjmp"); - + } - + public: ObjCTypesHelper(CodeGen::CodeGenModule &cgm); ~ObjCTypesHelper() {} @@ -540,51 +572,51 @@ public: /// modern abi class ObjCNonFragileABITypesHelper : public ObjCCommonTypesHelper { public: - + // MethodListnfABITy - LLVM for struct _method_list_t const llvm::StructType *MethodListnfABITy; - + // MethodListnfABIPtrTy - LLVM for struct _method_list_t* const llvm::Type *MethodListnfABIPtrTy; - + // ProtocolnfABITy = LLVM for struct _protocol_t const llvm::StructType *ProtocolnfABITy; - + // ProtocolnfABIPtrTy = LLVM for struct _protocol_t* const llvm::Type *ProtocolnfABIPtrTy; // ProtocolListnfABITy - LLVM for struct _objc_protocol_list const llvm::StructType *ProtocolListnfABITy; - + // ProtocolListnfABIPtrTy - LLVM for struct _objc_protocol_list* const llvm::Type *ProtocolListnfABIPtrTy; - + // ClassnfABITy - LLVM for struct _class_t const llvm::StructType *ClassnfABITy; - + // ClassnfABIPtrTy - LLVM for struct _class_t* const llvm::Type *ClassnfABIPtrTy; - + // IvarnfABITy - LLVM for struct _ivar_t const llvm::StructType *IvarnfABITy; - + // IvarListnfABITy - LLVM for struct _ivar_list_t const llvm::StructType *IvarListnfABITy; - + // IvarListnfABIPtrTy = LLVM for struct _ivar_list_t* const llvm::Type *IvarListnfABIPtrTy; - + // ClassRonfABITy - LLVM for struct _class_ro_t const llvm::StructType *ClassRonfABITy; - + // ImpnfABITy - LLVM for id (*)(id, SEL, ...) const llvm::Type *ImpnfABITy; - + // CategorynfABITy - LLVM for struct _category_t const llvm::StructType *CategorynfABITy; - + // New types for nonfragile abi messaging. - + // MessageRefTy - LLVM for: // struct _message_ref_t { // IMP messenger; @@ -593,22 +625,22 @@ public: const llvm::StructType *MessageRefTy; // MessageRefCTy - clang type for struct _message_ref_t QualType MessageRefCTy; - + // MessageRefPtrTy - LLVM for struct _message_ref_t* const llvm::Type *MessageRefPtrTy; // MessageRefCPtrTy - clang type for struct _message_ref_t* QualType MessageRefCPtrTy; - + // MessengerTy - Type of the messenger (shown as IMP above) const llvm::FunctionType *MessengerTy; - + // SuperMessageRefTy - LLVM for: // struct _super_message_ref_t { // SUPER_IMP messenger; // SEL name; // }; const llvm::StructType *SuperMessageRefTy; - + // SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t* const llvm::Type *SuperMessageRefPtrTy; @@ -621,7 +653,7 @@ public: Params, true), "objc_msgSend_fixup"); } - + llvm::Constant *getMessageSendFpretFixupFn() { // id objc_msgSend_fpret_fixup(id, struct message_ref_t*, ...) std::vector Params; @@ -631,7 +663,7 @@ public: Params, true), "objc_msgSend_fpret_fixup"); } - + llvm::Constant *getMessageSendStretFixupFn() { // id objc_msgSend_stret_fixup(id, struct message_ref_t*, ...) std::vector Params; @@ -641,7 +673,7 @@ public: Params, true), "objc_msgSend_stret_fixup"); } - + llvm::Constant *getMessageSendIdFixupFn() { // id objc_msgSendId_fixup(id, struct message_ref_t*, ...) std::vector Params; @@ -651,7 +683,7 @@ public: Params, true), "objc_msgSendId_fixup"); } - + llvm::Constant *getMessageSendIdStretFixupFn() { // id objc_msgSendId_stret_fixup(id, struct message_ref_t*, ...) std::vector Params; @@ -662,7 +694,7 @@ public: "objc_msgSendId_stret_fixup"); } llvm::Constant *getMessageSendSuper2FixupFn() { - // id objc_msgSendSuper2_fixup (struct objc_super *, + // id objc_msgSendSuper2_fixup (struct objc_super *, // struct _super_message_ref_t*, ...) std::vector Params; Params.push_back(SuperPtrTy); @@ -671,9 +703,9 @@ public: Params, true), "objc_msgSendSuper2_fixup"); } - + llvm::Constant *getMessageSendSuper2StretFixupFn() { - // id objc_msgSendSuper2_stret_fixup(struct objc_super *, + // id objc_msgSendSuper2_stret_fixup(struct objc_super *, // struct _super_message_ref_t*, ...) std::vector Params; Params.push_back(SuperPtrTy); @@ -682,34 +714,35 @@ public: Params, true), "objc_msgSendSuper2_stret_fixup"); } - - - + + + /// EHPersonalityPtr - LLVM value for an i8* to the Objective-C /// exception personality function. llvm::Value *getEHPersonalityPtr() { - llvm::Constant *Personality = - CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::Int32Ty, + llvm::Constant *Personality = + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty(VMContext), true), - "__objc_personality_v0"); + "__objc_personality_v0"); return llvm::ConstantExpr::getBitCast(Personality, Int8PtrTy); } llvm::Constant *getUnwindResumeOrRethrowFn() { std::vector Params; Params.push_back(Int8PtrTy); - return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy, - Params, false), - "_Unwind_Resume_or_Rethrow"); + return CGM.CreateRuntimeFunction( + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + Params, false), + "_Unwind_Resume_or_Rethrow"); } - + llvm::Constant *getObjCEndCatchFn() { - return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy, + return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false), "objc_end_catch"); - + } - + llvm::Constant *getObjCBeginCatchFn() { std::vector Params; Params.push_back(Int8PtrTy); @@ -724,7 +757,7 @@ public: ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm); ~ObjCNonFragileABITypesHelper(){} }; - + class CGObjCCommonMac : public CodeGen::CGObjCRuntime { public: // FIXME - accessibility @@ -733,129 +766,126 @@ public: unsigned ivar_bytepos; unsigned ivar_size; GC_IVAR(unsigned bytepos = 0, unsigned size = 0) - : ivar_bytepos(bytepos), ivar_size(size) {} + : ivar_bytepos(bytepos), ivar_size(size) {} // Allow sorting based on byte pos. bool operator<(const GC_IVAR &b) const { return ivar_bytepos < b.ivar_bytepos; } }; - + class SKIP_SCAN { public: unsigned skip; unsigned scan; - SKIP_SCAN(unsigned _skip = 0, unsigned _scan = 0) + SKIP_SCAN(unsigned _skip = 0, unsigned _scan = 0) : skip(_skip), scan(_scan) {} }; - + protected: CodeGen::CodeGenModule &CGM; + llvm::LLVMContext &VMContext; // FIXME! May not be needing this after all. unsigned ObjCABI; - + // gc ivar layout bitmap calculation helper caches. llvm::SmallVector SkipIvars; llvm::SmallVector IvarsInfo; - + /// LazySymbols - Symbols to generate a lazy reference for. See /// DefinedSymbols and FinishModule(). - std::set LazySymbols; - + llvm::SetVector LazySymbols; + /// DefinedSymbols - External symbols which are defined by this /// module. The symbols in this list and LazySymbols are used to add /// special linker symbols which ensure that Objective-C modules are /// linked properly. - std::set DefinedSymbols; - + llvm::SetVector DefinedSymbols; + /// ClassNames - uniqued class names. llvm::DenseMap ClassNames; - + /// MethodVarNames - uniqued method variable names. llvm::DenseMap MethodVarNames; - + /// MethodVarTypes - uniqued method type signatures. We have to use /// a StringMap here because have no other unique reference. llvm::StringMap MethodVarTypes; - + /// MethodDefinitions - map of methods which have been defined in /// this translation unit. llvm::DenseMap MethodDefinitions; - + /// PropertyNames - uniqued method variable names. llvm::DenseMap PropertyNames; - + /// ClassReferences - uniqued class references. llvm::DenseMap ClassReferences; - + /// SelectorReferences - uniqued selector references. llvm::DenseMap SelectorReferences; - + /// Protocols - Protocols for which an objc_protocol structure has /// been emitted. Forward declarations are handled by creating an /// empty structure whose initializer is filled in when/if defined. llvm::DenseMap Protocols; - + /// DefinedProtocols - Protocols which have actually been /// defined. We should not need this, see FIXME in GenerateProtocol. llvm::DenseSet DefinedProtocols; - + /// DefinedClasses - List of defined classes. std::vector DefinedClasses; /// DefinedNonLazyClasses - List of defined "non-lazy" classes. std::vector DefinedNonLazyClasses; - + /// DefinedCategories - List of defined categories. std::vector DefinedCategories; - + /// DefinedNonLazyCategories - List of defined "non-lazy" categories. std::vector DefinedNonLazyCategories; - - /// UsedGlobals - List of globals to pack into the llvm.used metadata - /// to prevent them from being clobbered. - std::vector UsedGlobals; /// GetNameForMethod - Return a name for the given method. /// \param[out] NameOut - The return value. void GetNameForMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD, std::string &NameOut); - + /// GetMethodVarName - Return a unique constant for the given /// selector's name. The return value has type char *. llvm::Constant *GetMethodVarName(Selector Sel); llvm::Constant *GetMethodVarName(IdentifierInfo *Ident); llvm::Constant *GetMethodVarName(const std::string &Name); - + /// GetMethodVarType - Return a unique constant for the given /// selector's name. The return value has type char *. - + // FIXME: This is a horrible name. llvm::Constant *GetMethodVarType(const ObjCMethodDecl *D); llvm::Constant *GetMethodVarType(const FieldDecl *D); - + /// GetPropertyName - Return a unique constant for the given /// name. The return value has type char *. llvm::Constant *GetPropertyName(IdentifierInfo *Ident); - + // FIXME: This can be dropped once string functions are unified. llvm::Constant *GetPropertyTypeString(const ObjCPropertyDecl *PD, const Decl *Container); - + /// GetClassName - Return a unique constant for the given selector's /// name. The return value has type char *. llvm::Constant *GetClassName(IdentifierInfo *Ident); - + /// BuildIvarLayout - Builds ivar layout bitmap for the class /// implementation for the __strong or __weak case. /// llvm::Constant *BuildIvarLayout(const ObjCImplementationDecl *OI, bool ForStrongLayout); - + void BuildAggrIvarRecordLayout(const RecordType *RT, - unsigned int BytePos, bool ForStrongLayout, - bool &HasUnion); + unsigned int BytePos, bool ForStrongLayout, + bool &HasUnion); void BuildAggrIvarLayout(const ObjCImplementationDecl *OI, const llvm::StructLayout *Layout, const RecordDecl *RD, @@ -867,14 +897,14 @@ protected: /// ivar layout bitmap. llvm::Constant *GetIvarLayoutName(IdentifierInfo *Ident, const ObjCCommonTypesHelper &ObjCTypes); - + /// EmitPropertyList - Emit the given property list. The return /// value has type PropertyListPtrTy. llvm::Constant *EmitPropertyList(const std::string &Name, - const Decl *Container, + const Decl *Container, const ObjCContainerDecl *OCD, const ObjCCommonTypesHelper &ObjCTypes); - + /// GetProtocolRef - Return a reference to the internal protocol /// description, creating an empty one if it has not been /// defined. The return value has type ProtocolPtrTy. @@ -885,7 +915,7 @@ protected: /// /// This is a convenience wrapper which not only creates the /// variable, but also sets the section and alignment and adds the - /// global to the UsedGlobals list. + /// global to the "llvm.used" list. /// /// \param Name - The variable name. /// \param Init - The variable initializer; this is also used to @@ -907,33 +937,32 @@ protected: QualType Arg0Ty, bool IsSuper, const CallArgList &CallArgs, + const ObjCMethodDecl *OMD, const ObjCCommonTypesHelper &ObjCTypes); - virtual void MergeMetadataGlobals(std::vector &UsedArray); - public: - CGObjCCommonMac(CodeGen::CodeGenModule &cgm) : CGM(cgm) - { } - + CGObjCCommonMac(CodeGen::CodeGenModule &cgm) : + CGM(cgm), VMContext(cgm.getLLVMContext()) { } + virtual llvm::Constant *GenerateConstantString(const ObjCStringLiteral *SL); - + virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD=0); - + virtual void GenerateProtocol(const ObjCProtocolDecl *PD); - + /// GetOrEmitProtocol - Get the protocol object for the given /// declaration, emitting it if necessary. The return value has type /// ProtocolPtrTy. virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD)=0; - + /// GetOrEmitProtocolRef - Get a forward reference to the protocol /// object for the given declaration, emitting it if needed. These /// forward references will be filled in with empty bodies if no /// definition is seen. The return value has type ProtocolPtrTy. virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD)=0; }; - + class CGObjCMac : public CGObjCCommonMac { private: ObjCTypesHelper ObjCTypes; @@ -942,7 +971,7 @@ private: void EmitImageInfo(); /// EmitModuleInfo - Another marker encoding module level - /// information. + /// information. void EmitModuleInfo(); /// EmitModuleSymols - Emit module symbols, the list of defined @@ -960,7 +989,7 @@ private: /// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy, /// for the given class. - llvm::Value *EmitClassRef(CGBuilderTy &Builder, + llvm::Value *EmitClassRef(CGBuilderTy &Builder, const ObjCInterfaceDecl *ID); CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF, @@ -978,7 +1007,7 @@ private: /// IvarListPtrTy. llvm::Constant *EmitIvarList(const ObjCImplementationDecl *ID, bool ForClass); - + /// EmitMetaClass - Emit a forward reference to the class structure /// for the metaclass of the given interface. The return value has /// type ClassPtrTy. @@ -989,9 +1018,9 @@ private: llvm::Constant *EmitMetaClass(const ObjCImplementationDecl *ID, llvm::Constant *Protocols, const ConstantVector &Methods); - + llvm::Constant *GetMethodConstant(const ObjCMethodDecl *MD); - + llvm::Constant *GetMethodDescriptionConstant(const ObjCMethodDecl *MD); /// EmitMethodList - Emit the method list for the given @@ -1001,7 +1030,7 @@ private: const ConstantVector &Methods); /// EmitMethodDescList - Emit a method description list for a list of - /// method declarations. + /// method declarations. /// - TypeName: The name for the type containing the methods. /// - IsProtocol: True iff these methods are for a protocol. /// - ClassMethds: True iff these are class methods. @@ -1044,12 +1073,12 @@ private: /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy, /// for the given selector. llvm::Value *EmitSelector(CGBuilderTy &Builder, Selector Sel); - - public: + +public: CGObjCMac(CodeGen::CodeGenModule &cgm); virtual llvm::Function *ModuleInitFunction(); - + virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, @@ -1058,7 +1087,7 @@ private: const CallArgList &CallArgs, const ObjCMethodDecl *Method); - virtual CodeGen::RValue + virtual CodeGen::RValue GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, @@ -1066,8 +1095,9 @@ private: bool isCategoryImpl, llvm::Value *Receiver, bool IsClassMessage, - const CallArgList &CallArgs); - + const CallArgList &CallArgs, + const ObjCMethodDecl *Method); + virtual llvm::Value *GetClass(CGBuilderTy &Builder, const ObjCInterfaceDecl *ID); @@ -1084,26 +1114,30 @@ private: virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder, const ObjCProtocolDecl *PD); - + virtual llvm::Constant *GetPropertyGetFunction(); virtual llvm::Constant *GetPropertySetFunction(); virtual llvm::Constant *EnumerationMutationFunction(); - + virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, const Stmt &S); virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S); virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF, - llvm::Value *AddrWeakObj); + llvm::Value *AddrWeakObj); virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dst); + llvm::Value *src, llvm::Value *dst); virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest); virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dest); + llvm::Value *src, llvm::Value *dest, + llvm::Value *ivarOffset); virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest); - + virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, + llvm::Value *dest, llvm::Value *src, + QualType Ty); + virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, QualType ObjectTy, llvm::Value *BaseValue, @@ -1113,30 +1147,30 @@ private: const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar); }; - + class CGObjCNonFragileABIMac : public CGObjCCommonMac { private: ObjCNonFragileABITypesHelper ObjCTypes; llvm::GlobalVariable* ObjCEmptyCacheVar; llvm::GlobalVariable* ObjCEmptyVtableVar; - + /// SuperClassReferences - uniqued super class references. llvm::DenseMap SuperClassReferences; - + /// MetaClassReferences - uniqued meta class references. llvm::DenseMap MetaClassReferences; /// EHTypeReferences - uniqued class ehtype references. llvm::DenseMap EHTypeReferences; - + /// NonLegacyDispatchMethods - List of methods for which we do *not* generate /// legacy messaging dispatch. llvm::DenseSet NonLegacyDispatchMethods; - + /// LegacyDispatchedSelector - Returns true if SEL is not in the list of /// NonLegacyDispatchMethods; false otherwise. bool LegacyDispatchedSelector(Selector Sel); - + /// FinishNonFragileABIModule - Write out global data structures at the end of /// processing a translation unit. void FinishNonFragileABIModule(); @@ -1147,20 +1181,20 @@ private: const char *SymbolName, const char *SectionName); - llvm::GlobalVariable * BuildClassRoTInitializer(unsigned flags, - unsigned InstanceStart, - unsigned InstanceSize, - const ObjCImplementationDecl *ID); + llvm::GlobalVariable * BuildClassRoTInitializer(unsigned flags, + unsigned InstanceStart, + unsigned InstanceSize, + const ObjCImplementationDecl *ID); llvm::GlobalVariable * BuildClassMetaData(std::string &ClassName, - llvm::Constant *IsAGV, + llvm::Constant *IsAGV, llvm::Constant *SuperClassGV, llvm::Constant *ClassRoGV, bool HiddenVisibility); - + llvm::Constant *GetMethodConstant(const ObjCMethodDecl *MD); - + llvm::Constant *GetMethodDescriptionConstant(const ObjCMethodDecl *MD); - + /// EmitMethodList - Emit the method list for the given /// implementation. The return value has type MethodListnfABITy. llvm::Constant *EmitMethodList(const std::string &Name, @@ -1172,28 +1206,28 @@ private: /// interface ivars will be emitted. The return value has type /// IvarListnfABIPtrTy. llvm::Constant *EmitIvarList(const ObjCImplementationDecl *ID); - + llvm::Constant *EmitIvarOffsetVar(const ObjCInterfaceDecl *ID, const ObjCIvarDecl *Ivar, unsigned long int offset); - + /// GetOrEmitProtocol - Get the protocol object for the given /// declaration, emitting it if necessary. The return value has type /// ProtocolPtrTy. virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD); - + /// GetOrEmitProtocolRef - Get a forward reference to the protocol /// object for the given declaration, emitting it if needed. These /// forward references will be filled in with empty bodies if no /// definition is seen. The return value has type ProtocolPtrTy. virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD); - + /// EmitProtocolList - Generate the list of referenced /// protocols. The return value has type ProtocolListPtrTy. llvm::Constant *EmitProtocolList(const std::string &Name, ObjCProtocolDecl::protocol_iterator begin, ObjCProtocolDecl::protocol_iterator end); - + CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, @@ -1205,29 +1239,29 @@ private: /// GetClassGlobal - Return the global variable for the Objective-C /// class of the given name. llvm::GlobalVariable *GetClassGlobal(const std::string &Name); - + /// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy, /// for the given class reference. - llvm::Value *EmitClassRef(CGBuilderTy &Builder, + llvm::Value *EmitClassRef(CGBuilderTy &Builder, const ObjCInterfaceDecl *ID); - + /// EmitSuperClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy, /// for the given super class reference. - llvm::Value *EmitSuperClassRef(CGBuilderTy &Builder, - const ObjCInterfaceDecl *ID); - + llvm::Value *EmitSuperClassRef(CGBuilderTy &Builder, + const ObjCInterfaceDecl *ID); + /// EmitMetaClassRef - Return a Value * of the address of _class_t /// meta-data - llvm::Value *EmitMetaClassRef(CGBuilderTy &Builder, + llvm::Value *EmitMetaClassRef(CGBuilderTy &Builder, const ObjCInterfaceDecl *ID); /// ObjCIvarOffsetVariable - Returns the ivar offset variable for /// the given ivar. /// llvm::GlobalVariable * ObjCIvarOffsetVariable( - const ObjCInterfaceDecl *ID, - const ObjCIvarDecl *Ivar); - + const ObjCInterfaceDecl *ID, + const ObjCIvarDecl *Ivar); + /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy, /// for the given selector. llvm::Value *EmitSelector(CGBuilderTy &Builder, Selector Sel); @@ -1237,10 +1271,10 @@ private: llvm::Value *GetInterfaceEHType(const ObjCInterfaceDecl *ID, bool ForDefinition); - const char *getMetaclassSymbolPrefix() const { + const char *getMetaclassSymbolPrefix() const { return "OBJC_METACLASS_$_"; } - + const char *getClassSymbolPrefix() const { return "OBJC_CLASS_$_"; } @@ -1248,13 +1282,13 @@ private: void GetClassSizeInfo(const ObjCImplementationDecl *OID, uint32_t &InstanceStart, uint32_t &InstanceSize); - + // Shamelessly stolen from Analysis/CFRefCount.cpp Selector GetNullarySelector(const char* name) const { IdentifierInfo* II = &CGM.getContext().Idents.get(name); return CGM.getContext().Selectors.getSelector(0, &II); } - + Selector GetUnarySelector(const char* name) const { IdentifierInfo* II = &CGM.getContext().Idents.get(name); return CGM.getContext().Selectors.getSelector(1, &II); @@ -1268,7 +1302,7 @@ public: CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm); // FIXME. All stubs for now! virtual llvm::Function *ModuleInitFunction(); - + virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, @@ -1276,8 +1310,8 @@ public: bool IsClassMessage, const CallArgList &CallArgs, const ObjCMethodDecl *Method); - - virtual CodeGen::RValue + + virtual CodeGen::RValue GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, @@ -1285,11 +1319,12 @@ public: bool isCategoryImpl, llvm::Value *Receiver, bool IsClassMessage, - const CallArgList &CallArgs); - + const CallArgList &CallArgs, + const ObjCMethodDecl *Method); + virtual llvm::Value *GetClass(CGBuilderTy &Builder, const ObjCInterfaceDecl *ID); - + virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel) { return EmitSelector(Builder, Sel); } @@ -1298,23 +1333,23 @@ public: virtual llvm::Value *GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl *Method) { return EmitSelector(Builder, Method->getSelector()); } - + virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD); - + virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl); virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder, const ObjCProtocolDecl *PD); - - virtual llvm::Constant *GetPropertyGetFunction() { + + virtual llvm::Constant *GetPropertyGetFunction() { return ObjCTypes.getGetPropertyFn(); } - virtual llvm::Constant *GetPropertySetFunction() { - return ObjCTypes.getSetPropertyFn(); + virtual llvm::Constant *GetPropertySetFunction() { + return ObjCTypes.getSetPropertyFn(); } virtual llvm::Constant *EnumerationMutationFunction() { return ObjCTypes.getEnumerationMutationFn(); } - + virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, const Stmt &S); virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, @@ -1326,9 +1361,13 @@ public: virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest); virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dest); + llvm::Value *src, llvm::Value *dest, + llvm::Value *ivarOffset); virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest); + virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, + llvm::Value *dest, llvm::Value *src, + QualType Ty); virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, QualType ObjectTy, llvm::Value *BaseValue, @@ -1338,25 +1377,26 @@ public: const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar); }; - + } // end anonymous namespace /* *** Helper Functions *** */ /// getConstantGEP() - Help routine to construct simple GEPs. -static llvm::Constant *getConstantGEP(llvm::Constant *C, +static llvm::Constant *getConstantGEP(llvm::LLVMContext &VMContext, + llvm::Constant *C, unsigned idx0, unsigned idx1) { llvm::Value *Idxs[] = { - llvm::ConstantInt::get(llvm::Type::Int32Ty, idx0), - llvm::ConstantInt::get(llvm::Type::Int32Ty, idx1) + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), idx0), + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), idx1) }; return llvm::ConstantExpr::getGetElementPtr(C, Idxs, 2); } /// hasObjCExceptionAttribute - Return true if this class or any super /// class has the __objc_exception__ attribute. -static bool hasObjCExceptionAttribute(ASTContext &Context, +static bool hasObjCExceptionAttribute(ASTContext &Context, const ObjCInterfaceDecl *OID) { if (OID->hasAttr()) return true; @@ -1366,12 +1406,11 @@ static bool hasObjCExceptionAttribute(ASTContext &Context, } /* *** CGObjCMac Public Interface *** */ - + CGObjCMac::CGObjCMac(CodeGen::CodeGenModule &cgm) : CGObjCCommonMac(cgm), - ObjCTypes(cgm) -{ + ObjCTypes(cgm) { ObjCABI = 1; - EmitImageInfo(); + EmitImageInfo(); } /// GetClass - Return a reference to the class for the given interface @@ -1386,18 +1425,18 @@ llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, Selector Sel) { return EmitSelector(Builder, Sel); } llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl - *Method) { + *Method) { return EmitSelector(Builder, Method->getSelector()); } /// Generate a constant CFString object. -/* - struct __builtin_CFString { - const int *isa; // point to __CFConstantStringClassReference - int flags; - const char *str; - long length; - }; +/* + struct __builtin_CFString { + const int *isa; // point to __CFConstantStringClassReference + int flags; + const char *str; + long length; + }; */ llvm::Constant *CGObjCCommonMac::GenerateConstantString( @@ -1416,14 +1455,15 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, bool isCategoryImpl, llvm::Value *Receiver, bool IsClassMessage, - const CodeGen::CallArgList &CallArgs) { + const CodeGen::CallArgList &CallArgs, + const ObjCMethodDecl *Method) { // Create and init a super structure; this is a (receiver, class) // pair we will pass to objc_msgSendSuper. - llvm::Value *ObjCSuper = + llvm::Value *ObjCSuper = CGF.Builder.CreateAlloca(ObjCTypes.SuperTy, 0, "objc_super"); - llvm::Value *ReceiverAsObject = + llvm::Value *ReceiverAsObject = CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy); - CGF.Builder.CreateStore(ReceiverAsObject, + CGF.Builder.CreateStore(ReceiverAsObject, CGF.Builder.CreateStructGEP(ObjCSuper, 0)); // If this is a class message the metaclass is passed as the target. @@ -1439,30 +1479,29 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, Target = EmitClassRef(CGF.Builder, Class->getSuperClass()); Target = CGF.Builder.CreateStructGEP(Target, 0); Target = CGF.Builder.CreateLoad(Target); - } - else { + } else { llvm::Value *MetaClassPtr = EmitMetaClassRef(Class); llvm::Value *SuperPtr = CGF.Builder.CreateStructGEP(MetaClassPtr, 1); llvm::Value *Super = CGF.Builder.CreateLoad(SuperPtr); Target = Super; - } + } } else { Target = EmitClassRef(CGF.Builder, Class->getSuperClass()); } // FIXME: We shouldn't need to do this cast, rectify the ASTContext and // ObjCTypes types. - const llvm::Type *ClassTy = + const llvm::Type *ClassTy = CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType()); Target = CGF.Builder.CreateBitCast(Target, ClassTy); - CGF.Builder.CreateStore(Target, + CGF.Builder.CreateStore(Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1)); - return EmitLegacyMessageSend(CGF, ResultType, + return EmitLegacyMessageSend(CGF, ResultType, EmitSelector(CGF.Builder, Sel), ObjCSuper, ObjCTypes.SuperPtrCTy, - true, CallArgs, ObjCTypes); + true, CallArgs, Method, ObjCTypes); } - -/// Generate code for a message send expression. + +/// Generate code for a message send expression. CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, @@ -1473,18 +1512,19 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, return EmitLegacyMessageSend(CGF, ResultType, EmitSelector(CGF.Builder, Sel), Receiver, CGF.getContext().getObjCIdType(), - false, CallArgs, ObjCTypes); + false, CallArgs, Method, ObjCTypes); } -CodeGen::RValue CGObjCCommonMac::EmitLegacyMessageSend( - CodeGen::CodeGenFunction &CGF, - QualType ResultType, - llvm::Value *Sel, - llvm::Value *Arg0, - QualType Arg0Ty, - bool IsSuper, - const CallArgList &CallArgs, - const ObjCCommonTypesHelper &ObjCTypes) { +CodeGen::RValue +CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF, + QualType ResultType, + llvm::Value *Sel, + llvm::Value *Arg0, + QualType Arg0Ty, + bool IsSuper, + const CallArgList &CallArgs, + const ObjCMethodDecl *Method, + const ObjCCommonTypesHelper &ObjCTypes) { CallArgList ActualArgs; if (!IsSuper) Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp"); @@ -1492,41 +1532,40 @@ CodeGen::RValue CGObjCCommonMac::EmitLegacyMessageSend( ActualArgs.push_back(std::make_pair(RValue::get(Sel), CGF.getContext().getObjCSelType())); ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); - + CodeGenTypes &Types = CGM.getTypes(); const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs); - // In 64bit ABI, type must be assumed VARARG. In 32bit abi, - // it seems not to matter. - const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo, (ObjCABI == 2)); - + const llvm::FunctionType *FTy = + Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); + llvm::Constant *Fn = NULL; if (CGM.ReturnTypeUsesSret(FnInfo)) { Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper) - : ObjCTypes.getSendStretFn(IsSuper); + : ObjCTypes.getSendStretFn(IsSuper); } else if (ResultType->isFloatingType()) { if (ObjCABI == 2) { - if (const BuiltinType *BT = ResultType->getAsBuiltinType()) { + if (const BuiltinType *BT = ResultType->getAs()) { BuiltinType::Kind k = BT->getKind(); Fn = (k == BuiltinType::LongDouble) ? ObjCTypes.getSendFpretFn2(IsSuper) - : ObjCTypes.getSendFn2(IsSuper); + : ObjCTypes.getSendFn2(IsSuper); } else { Fn = ObjCTypes.getSendFn2(IsSuper); } - } - else + } else // FIXME. This currently matches gcc's API for x86-32. May need to change // for others if we have their API. Fn = ObjCTypes.getSendFpretFn(IsSuper); } else { Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper) - : ObjCTypes.getSendFn(IsSuper); + : ObjCTypes.getSendFn(IsSuper); } assert(Fn && "EmitLegacyMessageSend - unknown API"); - Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy)); + Fn = llvm::ConstantExpr::getBitCast(Fn, + llvm::PointerType::getUnqual(FTy)); return CGF.EmitCall(FnInfo, Fn, ActualArgs); } -llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder, +llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder, const ObjCProtocolDecl *PD) { // FIXME: I don't understand why gcc generates this, or where it is // resolved. Investigate. Its also wasteful to look this up over and over. @@ -1544,7 +1583,7 @@ void CGObjCCommonMac::GenerateProtocol(const ObjCProtocolDecl *PD) { // If we have generated a forward reference to this protocol, emit // it now. Otherwise do nothing, the protocol objects are lazily // emitted. - if (Protocols.count(PD->getIdentifier())) + if (Protocols.count(PD->getIdentifier())) GetOrEmitProtocol(PD); } @@ -1555,16 +1594,16 @@ llvm::Constant *CGObjCCommonMac::GetProtocolRef(const ObjCProtocolDecl *PD) { } /* - // APPLE LOCAL radar 4585769 - Objective-C 1.0 extensions - struct _objc_protocol { - struct _objc_protocol_extension *isa; - char *protocol_name; - struct _objc_protocol_list *protocol_list; - struct _objc__method_prototype_list *instance_methods; - struct _objc__method_prototype_list *class_methods - }; +// APPLE LOCAL radar 4585769 - Objective-C 1.0 extensions +struct _objc_protocol { +struct _objc_protocol_extension *isa; +char *protocol_name; +struct _objc_protocol_list *protocol_list; +struct _objc__method_prototype_list *instance_methods; +struct _objc__method_prototype_list *class_methods +}; - See EmitProtocolExtension(). +See EmitProtocolExtension(). */ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()]; @@ -1582,7 +1621,7 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { // Construct method lists. std::vector InstanceMethods, ClassMethods; std::vector OptInstanceMethods, OptClassMethods; - for (ObjCProtocolDecl::instmeth_iterator + for (ObjCProtocolDecl::instmeth_iterator i = PD->instmeth_begin(), e = PD->instmeth_end(); i != e; ++i) { ObjCMethodDecl *MD = *i; llvm::Constant *C = GetMethodDescriptionConstant(MD); @@ -1590,10 +1629,10 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { OptInstanceMethods.push_back(C); } else { InstanceMethods.push_back(C); - } + } } - for (ObjCProtocolDecl::classmeth_iterator + for (ObjCProtocolDecl::classmeth_iterator i = PD->classmeth_begin(), e = PD->classmeth_end(); i != e; ++i) { ObjCMethodDecl *MD = *i; llvm::Constant *C = GetMethodDescriptionConstant(MD); @@ -1601,46 +1640,45 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { OptClassMethods.push_back(C); } else { ClassMethods.push_back(C); - } + } } std::vector Values(5); Values[0] = EmitProtocolExtension(PD, OptInstanceMethods, OptClassMethods); Values[1] = GetClassName(PD->getIdentifier()); - Values[2] = + Values[2] = EmitProtocolList("\01L_OBJC_PROTOCOL_REFS_" + PD->getNameAsString(), PD->protocol_begin(), PD->protocol_end()); - Values[3] = + Values[3] = EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_" - + PD->getNameAsString(), + + PD->getNameAsString(), "__OBJC,__cat_inst_meth,regular,no_dead_strip", InstanceMethods); - Values[4] = - EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_" - + PD->getNameAsString(), + Values[4] = + EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_" + + PD->getNameAsString(), "__OBJC,__cat_cls_meth,regular,no_dead_strip", ClassMethods); llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolTy, Values); - + if (Entry) { // Already created, fix the linkage and update the initializer. Entry->setLinkage(llvm::GlobalValue::InternalLinkage); Entry->setInitializer(Init); } else { - Entry = - new llvm::GlobalVariable(ObjCTypes.ProtocolTy, false, + Entry = + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy, false, llvm::GlobalValue::InternalLinkage, - Init, - std::string("\01L_OBJC_PROTOCOL_")+ProtocolName, - &CGM.getModule()); + Init, + std::string("\01L_OBJC_PROTOCOL_")+ProtocolName); Entry->setSection("__OBJC,__protocol,regular,no_dead_strip"); Entry->setAlignment(4); - UsedGlobals.push_back(Entry); // FIXME: Is this necessary? Why only for protocol? Entry->setAlignment(4); } + CGM.AddUsedGlobal(Entry); return Entry; } @@ -1652,71 +1690,69 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) { // We use the initializer as a marker of whether this is a forward // reference or not. At module finalization we add the empty // contents for protocols which were referenced but never defined. - Entry = - new llvm::GlobalVariable(ObjCTypes.ProtocolTy, false, + Entry = + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy, false, llvm::GlobalValue::ExternalLinkage, 0, - "\01L_OBJC_PROTOCOL_" + PD->getNameAsString(), - &CGM.getModule()); + "\01L_OBJC_PROTOCOL_" + PD->getNameAsString()); Entry->setSection("__OBJC,__protocol,regular,no_dead_strip"); Entry->setAlignment(4); - UsedGlobals.push_back(Entry); // FIXME: Is this necessary? Why only for protocol? Entry->setAlignment(4); } - + return Entry; } /* struct _objc_protocol_extension { - uint32_t size; - struct objc_method_description_list *optional_instance_methods; - struct objc_method_description_list *optional_class_methods; - struct objc_property_list *instance_properties; + uint32_t size; + struct objc_method_description_list *optional_instance_methods; + struct objc_method_description_list *optional_class_methods; + struct objc_property_list *instance_properties; }; */ llvm::Constant * CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD, const ConstantVector &OptInstanceMethods, const ConstantVector &OptClassMethods) { - uint64_t Size = + uint64_t Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy); std::vector Values(4); Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); - Values[1] = - EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_OPT_" - + PD->getNameAsString(), + Values[1] = + EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_OPT_" + + PD->getNameAsString(), "__OBJC,__cat_inst_meth,regular,no_dead_strip", OptInstanceMethods); - Values[2] = + Values[2] = EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_OPT_" - + PD->getNameAsString(), + + PD->getNameAsString(), "__OBJC,__cat_cls_meth,regular,no_dead_strip", OptClassMethods); - Values[3] = EmitPropertyList("\01L_OBJC_$_PROP_PROTO_LIST_" + - PD->getNameAsString(), + Values[3] = EmitPropertyList("\01L_OBJC_$_PROP_PROTO_LIST_" + + PD->getNameAsString(), 0, PD, ObjCTypes); // Return null if no extension bits are used. - if (Values[1]->isNullValue() && Values[2]->isNullValue() && + if (Values[1]->isNullValue() && Values[2]->isNullValue() && Values[3]->isNullValue()) return llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy); - llvm::Constant *Init = + llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolExtensionTy, Values); // No special section, but goes in llvm.used return CreateMetadataVar("\01L_OBJC_PROTOCOLEXT_" + PD->getNameAsString(), - Init, + Init, 0, 0, true); } /* struct objc_protocol_list { - struct objc_protocol_list *next; - long count; - Protocol *list[]; + struct objc_protocol_list *next; + long count; + Protocol *list[]; }; */ llvm::Constant * @@ -1729,7 +1765,7 @@ CGObjCMac::EmitProtocolList(const std::string &Name, ProtocolRefs.push_back(GetProtocolRef(*begin)); // Just return null for empty protocol lists - if (ProtocolRefs.empty()) + if (ProtocolRefs.empty()) return llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy); // This list is null terminated. @@ -1738,14 +1774,15 @@ CGObjCMac::EmitProtocolList(const std::string &Name, std::vector Values(3); // This field is only used by the runtime. Values[0] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy); - Values[1] = llvm::ConstantInt::get(ObjCTypes.LongTy, ProtocolRefs.size() - 1); - Values[2] = - llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.ProtocolPtrTy, - ProtocolRefs.size()), + Values[1] = llvm::ConstantInt::get(ObjCTypes.LongTy, + ProtocolRefs.size() - 1); + Values[2] = + llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.ProtocolPtrTy, + ProtocolRefs.size()), ProtocolRefs); - - llvm::Constant *Init = llvm::ConstantStruct::get(Values); - llvm::GlobalVariable *GV = + + llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false); + llvm::GlobalVariable *GV = CreateMetadataVar(Name, Init, "__OBJC,__cat_cls_meth,regular,no_dead_strip", 4, false); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListPtrTy); @@ -1753,23 +1790,23 @@ CGObjCMac::EmitProtocolList(const std::string &Name, /* struct _objc_property { - const char * const name; - const char * const attributes; + const char * const name; + const char * const attributes; }; struct _objc_property_list { - uint32_t entsize; // sizeof (struct _objc_property) - uint32_t prop_count; - struct _objc_property[prop_count]; + uint32_t entsize; // sizeof (struct _objc_property) + uint32_t prop_count; + struct _objc_property[prop_count]; }; */ llvm::Constant *CGObjCCommonMac::EmitPropertyList(const std::string &Name, - const Decl *Container, - const ObjCContainerDecl *OCD, - const ObjCCommonTypesHelper &ObjCTypes) { + const Decl *Container, + const ObjCContainerDecl *OCD, + const ObjCCommonTypesHelper &ObjCTypes) { std::vector Properties, Prop(2); - for (ObjCContainerDecl::prop_iterator I = OCD->prop_begin(), - E = OCD->prop_end(); I != E; ++I) { + for (ObjCContainerDecl::prop_iterator I = OCD->prop_begin(), + E = OCD->prop_end(); I != E; ++I) { const ObjCPropertyDecl *PD = *I; Prop[0] = GetPropertyName(PD->getIdentifier()); Prop[1] = GetPropertyTypeString(PD, Container); @@ -1781,36 +1818,37 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(const std::string &Name, if (Properties.empty()) return llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); - unsigned PropertySize = + unsigned PropertySize = CGM.getTargetData().getTypeAllocSize(ObjCTypes.PropertyTy); std::vector Values(3); Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, PropertySize); Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Properties.size()); - llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.PropertyTy, + llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.PropertyTy, Properties.size()); Values[2] = llvm::ConstantArray::get(AT, Properties); - llvm::Constant *Init = llvm::ConstantStruct::get(Values); + llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false); - llvm::GlobalVariable *GV = - CreateMetadataVar(Name, Init, - (ObjCABI == 2) ? "__DATA, __objc_const" : + llvm::GlobalVariable *GV = + CreateMetadataVar(Name, Init, + (ObjCABI == 2) ? "__DATA, __objc_const" : "__OBJC,__property,regular,no_dead_strip", - (ObjCABI == 2) ? 8 : 4, + (ObjCABI == 2) ? 8 : 4, true); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.PropertyListPtrTy); } /* struct objc_method_description_list { - int count; - struct objc_method_description list[]; + int count; + struct objc_method_description list[]; }; */ llvm::Constant * CGObjCMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) { std::vector Desc(2); - Desc[0] = llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()), - ObjCTypes.SelectorPtrTy); + Desc[0] = + llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()), + ObjCTypes.SelectorPtrTy); Desc[1] = GetMethodVarType(MD); return llvm::ConstantStruct::get(ObjCTypes.MethodDescriptionTy, Desc); @@ -1825,27 +1863,27 @@ llvm::Constant *CGObjCMac::EmitMethodDescList(const std::string &Name, std::vector Values(2); Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Methods.size()); - llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.MethodDescriptionTy, + llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.MethodDescriptionTy, Methods.size()); Values[1] = llvm::ConstantArray::get(AT, Methods); - llvm::Constant *Init = llvm::ConstantStruct::get(Values); + llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false); llvm::GlobalVariable *GV = CreateMetadataVar(Name, Init, Section, 4, true); - return llvm::ConstantExpr::getBitCast(GV, + return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodDescriptionListPtrTy); } /* struct _objc_category { - char *category_name; - char *class_name; - struct _objc_method_list *instance_methods; - struct _objc_method_list *class_methods; - struct _objc_protocol_list *protocols; - uint32_t size; // - struct _objc_property_list *instance_properties; + char *category_name; + char *class_name; + struct _objc_method_list *instance_methods; + struct _objc_method_list *class_methods; + struct _objc_protocol_list *protocols; + uint32_t size; // + struct _objc_property_list *instance_properties; }; - */ +*/ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.CategoryTy); @@ -1854,18 +1892,18 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { // w/o an @interface case. Sema should just create one for us as it does for // @implementation so everyone else can live life under a clear blue sky. const ObjCInterfaceDecl *Interface = OCD->getClassInterface(); - const ObjCCategoryDecl *Category = + const ObjCCategoryDecl *Category = Interface->FindCategoryDeclaration(OCD->getIdentifier()); std::string ExtName(Interface->getNameAsString() + "_" + OCD->getNameAsString()); std::vector InstanceMethods, ClassMethods; - for (ObjCCategoryImplDecl::instmeth_iterator + for (ObjCCategoryImplDecl::instmeth_iterator i = OCD->instmeth_begin(), e = OCD->instmeth_end(); i != e; ++i) { // Instance methods should always be defined. InstanceMethods.push_back(GetMethodConstant(*i)); } - for (ObjCCategoryImplDecl::classmeth_iterator + for (ObjCCategoryImplDecl::classmeth_iterator i = OCD->classmeth_begin(), e = OCD->classmeth_end(); i != e; ++i) { // Class methods should always be defined. ClassMethods.push_back(GetMethodConstant(*i)); @@ -1875,17 +1913,17 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { Values[0] = GetClassName(OCD->getIdentifier()); Values[1] = GetClassName(Interface->getIdentifier()); LazySymbols.insert(Interface->getIdentifier()); - Values[2] = - EmitMethodList(std::string("\01L_OBJC_CATEGORY_INSTANCE_METHODS_") + + Values[2] = + EmitMethodList(std::string("\01L_OBJC_CATEGORY_INSTANCE_METHODS_") + ExtName, "__OBJC,__cat_inst_meth,regular,no_dead_strip", InstanceMethods); - Values[3] = + Values[3] = EmitMethodList(std::string("\01L_OBJC_CATEGORY_CLASS_METHODS_") + ExtName, "__OBJC,__cat_cls_meth,regular,no_dead_strip", ClassMethods); if (Category) { - Values[4] = + Values[4] = EmitProtocolList(std::string("\01L_OBJC_CATEGORY_PROTOCOLS_") + ExtName, Category->protocol_begin(), Category->protocol_end()); @@ -1896,16 +1934,16 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { // If there is no category @interface then there can be no properties. if (Category) { - Values[6] = EmitPropertyList(std::string("\01l_OBJC_$_PROP_LIST_") + ExtName, + Values[6] = EmitPropertyList(std::string("\01l_OBJC_$_PROP_LIST_")+ExtName, OCD, Category, ObjCTypes); } else { Values[6] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); } - + llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.CategoryTy, Values); - llvm::GlobalVariable *GV = + llvm::GlobalVariable *GV = CreateMetadataVar(std::string("\01L_OBJC_CATEGORY_")+ExtName, Init, "__OBJC,__category,regular,no_dead_strip", 4, true); @@ -1925,36 +1963,36 @@ enum ClassFlags { /* struct _objc_class { - Class isa; - Class super_class; - const char *name; - long version; - long info; - long instance_size; - struct _objc_ivar_list *ivars; - struct _objc_method_list *methods; - struct _objc_cache *cache; - struct _objc_protocol_list *protocols; - // Objective-C 1.0 extensions () - const char *ivar_layout; - struct _objc_class_ext *ext; + Class isa; + Class super_class; + const char *name; + long version; + long info; + long instance_size; + struct _objc_ivar_list *ivars; + struct _objc_method_list *methods; + struct _objc_cache *cache; + struct _objc_protocol_list *protocols; + // Objective-C 1.0 extensions () + const char *ivar_layout; + struct _objc_class_ext *ext; }; See EmitClassExtension(); - */ +*/ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { DefinedSymbols.insert(ID->getIdentifier()); std::string ClassName = ID->getNameAsString(); // FIXME: Gross - ObjCInterfaceDecl *Interface = + ObjCInterfaceDecl *Interface = const_cast(ID->getClassInterface()); - llvm::Constant *Protocols = + llvm::Constant *Protocols = EmitProtocolList("\01L_OBJC_CLASS_PROTOCOLS_" + ID->getNameAsString(), Interface->protocol_begin(), Interface->protocol_end()); unsigned Flags = eClassFlags_Factory; - unsigned Size = + unsigned Size = CGM.getContext().getASTObjCImplementationLayout(ID).getSize() / 8; // FIXME: Set CXX-structors flag. @@ -1962,18 +2000,18 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { Flags |= eClassFlags_Hidden; std::vector InstanceMethods, ClassMethods; - for (ObjCImplementationDecl::instmeth_iterator + for (ObjCImplementationDecl::instmeth_iterator i = ID->instmeth_begin(), e = ID->instmeth_end(); i != e; ++i) { // Instance methods should always be defined. InstanceMethods.push_back(GetMethodConstant(*i)); } - for (ObjCImplementationDecl::classmeth_iterator + for (ObjCImplementationDecl::classmeth_iterator i = ID->classmeth_begin(), e = ID->classmeth_end(); i != e; ++i) { // Class methods should always be defined. ClassMethods.push_back(GetMethodConstant(*i)); } - for (ObjCImplementationDecl::propimpl_iterator + for (ObjCImplementationDecl::propimpl_iterator i = ID->propimpl_begin(), e = ID->propimpl_end(); i != e; ++i) { ObjCPropertyImplDecl *PID = *i; @@ -1995,7 +2033,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { // Record a reference to the super class. LazySymbols.insert(Super->getIdentifier()); - Values[ 1] = + Values[ 1] = llvm::ConstantExpr::getBitCast(GetClassName(Super->getIdentifier()), ObjCTypes.ClassPtrTy); } else { @@ -2007,19 +2045,19 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { Values[ 4] = llvm::ConstantInt::get(ObjCTypes.LongTy, Flags); Values[ 5] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size); Values[ 6] = EmitIvarList(ID, false); - Values[ 7] = + Values[ 7] = EmitMethodList("\01L_OBJC_INSTANCE_METHODS_" + ID->getNameAsString(), "__OBJC,__inst_meth,regular,no_dead_strip", InstanceMethods); // cache is always NULL. Values[ 8] = llvm::Constant::getNullValue(ObjCTypes.CachePtrTy); Values[ 9] = Protocols; - Values[10] = BuildIvarLayout(ID, true); + Values[10] = BuildIvarLayout(ID, true); Values[11] = EmitClassExtension(ID); llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy, Values); - llvm::GlobalVariable *GV = + llvm::GlobalVariable *GV = CreateMetadataVar(std::string("\01L_OBJC_CLASS_")+ClassName, Init, "__OBJC,__class,regular,no_dead_strip", 4, true); @@ -2034,20 +2072,20 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID, if (CGM.getDeclVisibilityMode(ID->getClassInterface()) == LangOptions::Hidden) Flags |= eClassFlags_Hidden; - + std::vector Values(12); // The isa for the metaclass is the root of the hierarchy. const ObjCInterfaceDecl *Root = ID->getClassInterface(); while (const ObjCInterfaceDecl *Super = Root->getSuperClass()) Root = Super; - Values[ 0] = + Values[ 0] = llvm::ConstantExpr::getBitCast(GetClassName(Root->getIdentifier()), ObjCTypes.ClassPtrTy); // The super class for the metaclass is emitted as the name of the // super class. The runtime fixes this up to point to the // *metaclass* for the super class. if (ObjCInterfaceDecl *Super = ID->getClassInterface()->getSuperClass()) { - Values[ 1] = + Values[ 1] = llvm::ConstantExpr::getBitCast(GetClassName(Super->getIdentifier()), ObjCTypes.ClassPtrTy); } else { @@ -2059,7 +2097,7 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID, Values[ 4] = llvm::ConstantInt::get(ObjCTypes.LongTy, Flags); Values[ 5] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size); Values[ 6] = EmitIvarList(ID, true); - Values[ 7] = + Values[ 7] = EmitMethodList("\01L_OBJC_CLASS_METHODS_" + ID->getNameAsString(), "__OBJC,__cls_meth,regular,no_dead_strip", Methods); @@ -2084,19 +2122,18 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID, GV->setLinkage(llvm::GlobalValue::InternalLinkage); GV->setInitializer(Init); } else { - GV = new llvm::GlobalVariable(ObjCTypes.ClassTy, false, + GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false, llvm::GlobalValue::InternalLinkage, - Init, Name, - &CGM.getModule()); + Init, Name); } GV->setSection("__OBJC,__meta_class,regular,no_dead_strip"); GV->setAlignment(4); - UsedGlobals.push_back(GV); + CGM.AddUsedGlobal(GV); return GV; } -llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) { +llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) { std::string Name = "\01L_OBJC_METACLASS_" + ID->getNameAsString(); // FIXME: Should we look these up somewhere other than the module. Its a bit @@ -2107,31 +2144,31 @@ llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) { // Check for an existing forward reference. // Previously, metaclass with internal linkage may have been defined. // pass 'true' as 2nd argument so it is returned. - if (llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true)) { + if (llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, + true)) { assert(GV->getType()->getElementType() == ObjCTypes.ClassTy && "Forward metaclass reference has incorrect type."); return GV; } else { // Generate as an external reference to keep a consistent // module. This will be patched up when we emit the metaclass. - return new llvm::GlobalVariable(ObjCTypes.ClassTy, false, + return new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false, llvm::GlobalValue::ExternalLinkage, 0, - Name, - &CGM.getModule()); + Name); } } /* struct objc_class_ext { - uint32_t size; - const char *weak_ivar_layout; - struct _objc_property_list *properties; + uint32_t size; + const char *weak_ivar_layout; + struct _objc_property_list *properties; }; */ llvm::Constant * CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) { - uint64_t Size = + uint64_t Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassExtensionTy); std::vector Values(3); @@ -2144,25 +2181,25 @@ CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) { if (Values[1]->isNullValue() && Values[2]->isNullValue()) return llvm::Constant::getNullValue(ObjCTypes.ClassExtensionPtrTy); - llvm::Constant *Init = + llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassExtensionTy, Values); return CreateMetadataVar("\01L_OBJC_CLASSEXT_" + ID->getNameAsString(), - Init, "__OBJC,__class_ext,regular,no_dead_strip", + Init, "__OBJC,__class_ext,regular,no_dead_strip", 4, true); } /* struct objc_ivar { - char *ivar_name; - char *ivar_type; - int ivar_offset; + char *ivar_name; + char *ivar_type; + int ivar_offset; }; struct objc_ivar_list { - int ivar_count; - struct objc_ivar list[count]; + int ivar_count; + struct objc_ivar list[count]; }; - */ +*/ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID, bool ForClass) { std::vector Ivars, Ivar(3); @@ -2174,21 +2211,21 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID, // for the class. if (ForClass) return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy); - - ObjCInterfaceDecl *OID = + + ObjCInterfaceDecl *OID = const_cast(ID->getClassInterface()); - + llvm::SmallVector OIvars; CGM.getContext().ShallowCollectObjCIvars(OID, OIvars); - + for (unsigned i = 0, e = OIvars.size(); i != e; ++i) { ObjCIvarDecl *IVD = OIvars[i]; // Ignore unnamed bit-fields. if (!IVD->getDeclName()) - continue; + continue; Ivar[0] = GetMethodVarName(IVD->getIdentifier()); Ivar[1] = GetMethodVarType(IVD); - Ivar[2] = llvm::ConstantInt::get(ObjCTypes.IntTy, + Ivar[2] = llvm::ConstantInt::get(ObjCTypes.IntTy, ComputeIvarBaseOffset(CGM, OID, IVD)); Ivars.push_back(llvm::ConstantStruct::get(ObjCTypes.IvarTy, Ivar)); } @@ -2202,12 +2239,12 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID, llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.IvarTy, Ivars.size()); Values[1] = llvm::ConstantArray::get(AT, Ivars); - llvm::Constant *Init = llvm::ConstantStruct::get(Values); + llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false); llvm::GlobalVariable *GV; if (ForClass) GV = CreateMetadataVar("\01L_OBJC_CLASS_VARIABLES_" + ID->getNameAsString(), - Init, "__OBJC,__class_vars,regular,no_dead_strip", + Init, "__OBJC,__class_vars,regular,no_dead_strip", 4, true); else GV = CreateMetadataVar("\01L_OBJC_INSTANCE_VARIABLES_" @@ -2219,15 +2256,15 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID, /* struct objc_method { - SEL method_name; - char *method_types; - void *method; + SEL method_name; + char *method_types; + void *method; }; - + struct objc_method_list { - struct objc_method_list *obsolete; - int count; - struct objc_method methods_list[count]; + struct objc_method_list *obsolete; + int count; + struct objc_method methods_list[count]; }; */ @@ -2239,9 +2276,9 @@ llvm::Constant *CGObjCMac::GetMethodConstant(const ObjCMethodDecl *MD) { llvm::Function *Fn = MethodDefinitions[MD]; if (!Fn) return 0; - + std::vector Method(3); - Method[0] = + Method[0] = llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()), ObjCTypes.SelectorPtrTy); Method[1] = GetMethodVarType(MD); @@ -2262,7 +2299,7 @@ llvm::Constant *CGObjCMac::EmitMethodList(const std::string &Name, llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.MethodTy, Methods.size()); Values[2] = llvm::ConstantArray::get(AT, Methods); - llvm::Constant *Init = llvm::ConstantStruct::get(Values); + llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false); llvm::GlobalVariable *GV = CreateMetadataVar(Name, Init, Section, 4, true); return llvm::ConstantExpr::getBitCast(GV, @@ -2270,14 +2307,14 @@ llvm::Constant *CGObjCMac::EmitMethodList(const std::string &Name, } llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD, - const ObjCContainerDecl *CD) { + const ObjCContainerDecl *CD) { std::string Name; GetNameForMethod(OMD, CD, Name); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *MethodTy = Types.GetFunctionType(Types.getFunctionInfo(OMD), OMD->isVariadic()); - llvm::Function *Method = + llvm::Function *Method = llvm::Function::Create(MethodTy, llvm::GlobalValue::InternalLinkage, Name, @@ -2294,25 +2331,21 @@ CGObjCCommonMac::CreateMetadataVar(const std::string &Name, unsigned Align, bool AddToUsed) { const llvm::Type *Ty = Init->getType(); - llvm::GlobalVariable *GV = - new llvm::GlobalVariable(Ty, false, - llvm::GlobalValue::InternalLinkage, - Init, - Name, - &CGM.getModule()); + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(CGM.getModule(), Ty, false, + llvm::GlobalValue::InternalLinkage, Init, Name); if (Section) GV->setSection(Section); if (Align) GV->setAlignment(Align); if (AddToUsed) - UsedGlobals.push_back(GV); + CGM.AddUsedGlobal(GV); return GV; } -llvm::Function *CGObjCMac::ModuleInitFunction() { +llvm::Function *CGObjCMac::ModuleInitFunction() { // Abuse this interface function as a place to finalize. FinishModule(); - return NULL; } @@ -2328,92 +2361,92 @@ llvm::Constant *CGObjCMac::EnumerationMutationFunction() { return ObjCTypes.getEnumerationMutationFn(); } -/* +/* -Objective-C setjmp-longjmp (sjlj) Exception Handling --- + Objective-C setjmp-longjmp (sjlj) Exception Handling + -- -The basic framework for a @try-catch-finally is as follows: -{ + The basic framework for a @try-catch-finally is as follows: + { objc_exception_data d; id _rethrow = null; bool _call_try_exit = true; - + objc_exception_try_enter(&d); if (!setjmp(d.jmp_buf)) { - ... try body ... + ... try body ... } else { - // exception path - id _caught = objc_exception_extract(&d); - - // enter new try scope for handlers - if (!setjmp(d.jmp_buf)) { - ... match exception and execute catch blocks ... - - // fell off end, rethrow. - _rethrow = _caught; - ... jump-through-finally to finally_rethrow ... - } else { - // exception in catch block - _rethrow = objc_exception_extract(&d); - _call_try_exit = false; - ... jump-through-finally to finally_rethrow ... - } + // exception path + id _caught = objc_exception_extract(&d); + + // enter new try scope for handlers + if (!setjmp(d.jmp_buf)) { + ... match exception and execute catch blocks ... + + // fell off end, rethrow. + _rethrow = _caught; + ... jump-through-finally to finally_rethrow ... + } else { + // exception in catch block + _rethrow = objc_exception_extract(&d); + _call_try_exit = false; + ... jump-through-finally to finally_rethrow ... + } } ... jump-through-finally to finally_end ... -finally: + finally: if (_call_try_exit) - objc_exception_try_exit(&d); + objc_exception_try_exit(&d); ... finally block .... ... dispatch to finally destination ... -finally_rethrow: + finally_rethrow: objc_exception_throw(_rethrow); -finally_end: -} + finally_end: + } -This framework differs slightly from the one gcc uses, in that gcc -uses _rethrow to determine if objc_exception_try_exit should be called -and if the object should be rethrown. This breaks in the face of -throwing nil and introduces unnecessary branches. - -We specialize this framework for a few particular circumstances: - - - If there are no catch blocks, then we avoid emitting the second - exception handling context. - - - If there is a catch-all catch block (i.e. @catch(...) or @catch(id - e)) we avoid emitting the code to rethrow an uncaught exception. - - - FIXME: If there is no @finally block we can do a few more - simplifications. - -Rethrows and Jumps-Through-Finally --- - -Support for implicit rethrows and jumping through the finally block is -handled by storing the current exception-handling context in -ObjCEHStack. - -In order to implement proper @finally semantics, we support one basic -mechanism for jumping through the finally block to an arbitrary -destination. Constructs which generate exits from a @try or @catch -block use this mechanism to implement the proper semantics by chaining -jumps, as necessary. - -This mechanism works like the one used for indirect goto: we -arbitrarily assign an ID to each destination and store the ID for the -destination in a variable prior to entering the finally block. At the -end of the finally block we simply create a switch to the proper -destination. - -Code gen for @synchronized(expr) stmt; -Effectively generating code for: -objc_sync_enter(expr); -@try stmt @finally { objc_sync_exit(expr); } + This framework differs slightly from the one gcc uses, in that gcc + uses _rethrow to determine if objc_exception_try_exit should be called + and if the object should be rethrown. This breaks in the face of + throwing nil and introduces unnecessary branches. + + We specialize this framework for a few particular circumstances: + + - If there are no catch blocks, then we avoid emitting the second + exception handling context. + + - If there is a catch-all catch block (i.e. @catch(...) or @catch(id + e)) we avoid emitting the code to rethrow an uncaught exception. + + - FIXME: If there is no @finally block we can do a few more + simplifications. + + Rethrows and Jumps-Through-Finally + -- + + Support for implicit rethrows and jumping through the finally block is + handled by storing the current exception-handling context in + ObjCEHStack. + + In order to implement proper @finally semantics, we support one basic + mechanism for jumping through the finally block to an arbitrary + destination. Constructs which generate exits from a @try or @catch + block use this mechanism to implement the proper semantics by chaining + jumps, as necessary. + + This mechanism works like the one used for indirect goto: we + arbitrarily assign an ID to each destination and store the ID for the + destination in a variable prior to entering the finally block. At the + end of the finally block we simply create a switch to the proper + destination. + + Code gen for @synchronized(expr) stmt; + Effectively generating code for: + objc_sync_enter(expr); + @try stmt @finally { objc_sync_exit(expr); } */ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, @@ -2425,14 +2458,14 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, llvm::BasicBlock *FinallyNoExit = CGF.createBasicBlock("finally.noexit"); llvm::BasicBlock *FinallyRethrow = CGF.createBasicBlock("finally.throw"); llvm::BasicBlock *FinallyEnd = CGF.createBasicBlock("finally.end"); - + // For @synchronized, call objc_sync_enter(sync.expr). The // evaluation of the expression must occur before we enter the // @synchronized. We can safely avoid a temp here because jumps into // @synchronized are illegal & this will dominate uses. llvm::Value *SyncArg = 0; if (!isTry) { - SyncArg = + SyncArg = CGF.EmitScalarExpr(cast(S).getSynchExpr()); SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy); CGF.Builder.CreateCall(ObjCTypes.getSyncEnterFn(), SyncArg); @@ -2443,19 +2476,21 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.PushCleanupBlock(FinallyBlock); CGF.ObjCEHValueStack.push_back(0); - + // Allocate memory for the exception data and rethrow pointer. llvm::Value *ExceptionData = CGF.CreateTempAlloca(ObjCTypes.ExceptionDataTy, "exceptiondata.ptr"); - llvm::Value *RethrowPtr = CGF.CreateTempAlloca(ObjCTypes.ObjectPtrTy, + llvm::Value *RethrowPtr = CGF.CreateTempAlloca(ObjCTypes.ObjectPtrTy, "_rethrow"); - llvm::Value *CallTryExitPtr = CGF.CreateTempAlloca(llvm::Type::Int1Ty, + llvm::Value *CallTryExitPtr = CGF.CreateTempAlloca( + llvm::Type::getInt1Ty(VMContext), "_call_try_exit"); - CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(), CallTryExitPtr); - + CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(VMContext), + CallTryExitPtr); + // Enter a new try block and call setjmp. CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData); - llvm::Value *JmpBufPtr = CGF.Builder.CreateStructGEP(ExceptionData, 0, + llvm::Value *JmpBufPtr = CGF.Builder.CreateStructGEP(ExceptionData, 0, "jmpbufarray"); JmpBufPtr = CGF.Builder.CreateStructGEP(JmpBufPtr, 0, "tmp"); llvm::Value *SetJmpResult = CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(), @@ -2463,15 +2498,15 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try"); llvm::BasicBlock *TryHandler = CGF.createBasicBlock("try.handler"); - CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNotNull(SetJmpResult, "threw"), + CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNotNull(SetJmpResult, "threw"), TryHandler, TryBlock); // Emit the @try block. CGF.EmitBlock(TryBlock); - CGF.EmitStmt(isTry ? cast(S).getTryBody() - : cast(S).getSynchBody()); + CGF.EmitStmt(isTry ? cast(S).getTryBody() + : cast(S).getSynchBody()); CGF.EmitBranchThroughCleanup(FinallyEnd); - + // Emit the "exception in @try" block. CGF.EmitBlock(TryHandler); @@ -2481,19 +2516,17 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(), ExceptionData, "caught"); CGF.ObjCEHValueStack.back() = Caught; - if (!isTry) - { + if (!isTry) { CGF.Builder.CreateStore(Caught, RethrowPtr); - CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(), CallTryExitPtr); + CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext), + CallTryExitPtr); CGF.EmitBranchThroughCleanup(FinallyRethrow); - } - else if (const ObjCAtCatchStmt* CatchStmt = - cast(S).getCatchStmts()) - { + } else if (const ObjCAtCatchStmt* CatchStmt = + cast(S).getCatchStmts()) { // Enter a new exception try block (in case a @catch block throws // an exception). CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData); - + llvm::Value *SetJmpResult = CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(), JmpBufPtr, "result"); llvm::Value *Threw = CGF.Builder.CreateIsNotNull(SetJmpResult, "threw"); @@ -2501,9 +2534,9 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, llvm::BasicBlock *CatchBlock = CGF.createBasicBlock("catch"); llvm::BasicBlock *CatchHandler = CGF.createBasicBlock("catch.handler"); CGF.Builder.CreateCondBr(Threw, CatchHandler, CatchBlock); - + CGF.EmitBlock(CatchBlock); - + // Handle catch list. As a special case we check if everything is // matched and avoid generating code for falling off the end if // so. @@ -2512,64 +2545,64 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch"); const ParmVarDecl *CatchParam = CatchStmt->getCatchParamDecl(); - const PointerType *PT = 0; + const ObjCObjectPointerType *OPT = 0; // catch(...) always matches. if (!CatchParam) { AllMatched = true; } else { - PT = CatchParam->getType()->getAsPointerType(); - - // catch(id e) always matches. + OPT = CatchParam->getType()->getAs(); + + // catch(id e) always matches. // FIXME: For the time being we also match id; this should // be rejected by Sema instead. - if ((PT && CGF.getContext().isObjCIdStructType(PT->getPointeeType())) || - CatchParam->getType()->isObjCQualifiedIdType()) + if (OPT && (OPT->isObjCIdType() || OPT->isObjCQualifiedIdType())) AllMatched = true; } - - if (AllMatched) { + + if (AllMatched) { if (CatchParam) { CGF.EmitLocalBlockVarDecl(*CatchParam); assert(CGF.HaveInsertPoint() && "DeclStmt destroyed insert point?"); CGF.Builder.CreateStore(Caught, CGF.GetAddrOfLocalVar(CatchParam)); } - + CGF.EmitStmt(CatchStmt->getCatchBody()); CGF.EmitBranchThroughCleanup(FinallyEnd); break; } - - assert(PT && "Unexpected non-pointer type in @catch"); - QualType T = PT->getPointeeType(); - const ObjCInterfaceType *ObjCType = T->getAsObjCInterfaceType(); + + assert(OPT && "Unexpected non-object pointer type in @catch"); + QualType T = OPT->getPointeeType(); + const ObjCInterfaceType *ObjCType = T->getAs(); assert(ObjCType && "Catch parameter must have Objective-C type!"); // Check if the @catch block matches the exception object. llvm::Value *Class = EmitClassRef(CGF.Builder, ObjCType->getDecl()); - + llvm::Value *Match = CGF.Builder.CreateCall2(ObjCTypes.getExceptionMatchFn(), Class, Caught, "match"); - + llvm::BasicBlock *MatchedBlock = CGF.createBasicBlock("matched"); - - CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNotNull(Match, "matched"), + + CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNotNull(Match, "matched"), MatchedBlock, NextCatchBlock); - + // Emit the @catch block. CGF.EmitBlock(MatchedBlock); CGF.EmitLocalBlockVarDecl(*CatchParam); assert(CGF.HaveInsertPoint() && "DeclStmt destroyed insert point?"); - llvm::Value *Tmp = - CGF.Builder.CreateBitCast(Caught, CGF.ConvertType(CatchParam->getType()), + llvm::Value *Tmp = + CGF.Builder.CreateBitCast(Caught, + CGF.ConvertType(CatchParam->getType()), "tmp"); CGF.Builder.CreateStore(Tmp, CGF.GetAddrOfLocalVar(CatchParam)); - + CGF.EmitStmt(CatchStmt->getCatchBody()); CGF.EmitBranchThroughCleanup(FinallyEnd); - + CGF.EmitBlock(NextCatchBlock); } @@ -2579,41 +2612,43 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.Builder.CreateStore(Caught, RethrowPtr); CGF.EmitBranchThroughCleanup(FinallyRethrow); } - + // Emit the exception handler for the @catch blocks. - CGF.EmitBlock(CatchHandler); + CGF.EmitBlock(CatchHandler); CGF.Builder.CreateStore( - CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(), - ExceptionData), - RethrowPtr); - CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(), CallTryExitPtr); + CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(), + ExceptionData), + RethrowPtr); + CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext), + CallTryExitPtr); CGF.EmitBranchThroughCleanup(FinallyRethrow); } else { CGF.Builder.CreateStore(Caught, RethrowPtr); - CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(), CallTryExitPtr); + CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext), + CallTryExitPtr); CGF.EmitBranchThroughCleanup(FinallyRethrow); } - + // Pop the exception-handling stack entry. It is important to do // this now, because the code in the @finally block is not in this // context. CodeGenFunction::CleanupBlockInfo Info = CGF.PopCleanupBlock(); CGF.ObjCEHValueStack.pop_back(); - + // Emit the @finally block. CGF.EmitBlock(FinallyBlock); llvm::Value* CallTryExit = CGF.Builder.CreateLoad(CallTryExitPtr, "tmp"); - + CGF.Builder.CreateCondBr(CallTryExit, FinallyExit, FinallyNoExit); - + CGF.EmitBlock(FinallyExit); CGF.Builder.CreateCall(ObjCTypes.getExceptionTryExitFn(), ExceptionData); CGF.EmitBlock(FinallyNoExit); if (isTry) { - if (const ObjCAtFinallyStmt* FinallyStmt = - cast(S).getFinallyStmt()) + if (const ObjCAtFinallyStmt* FinallyStmt = + cast(S).getFinallyStmt()) CGF.EmitStmt(FinallyStmt->getFinallyBody()); } else { // Emit objc_sync_exit(expr); as finally's sole statement for @@ -2626,29 +2661,29 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.EmitBlock(Info.SwitchBlock); if (Info.EndBlock) CGF.EmitBlock(Info.EndBlock); - + CGF.EmitBlock(FinallyRethrow); - CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), + CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), CGF.Builder.CreateLoad(RethrowPtr)); CGF.Builder.CreateUnreachable(); - + CGF.EmitBlock(FinallyEnd); } void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S) { llvm::Value *ExceptionAsObject; - + if (const Expr *ThrowExpr = S.getThrowExpr()) { llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr); - ExceptionAsObject = + ExceptionAsObject = CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy, "tmp"); } else { - assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) && + assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) && "Unexpected rethrow outside @catch block."); ExceptionAsObject = CGF.ObjCEHValueStack.back(); } - + CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), ExceptionAsObject); CGF.Builder.CreateUnreachable(); @@ -2660,11 +2695,11 @@ void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, /// object: objc_read_weak (id *src) /// llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF, - llvm::Value *AddrWeakObj) -{ + llvm::Value *AddrWeakObj) { const llvm::Type* DestTy = - cast(AddrWeakObj->getType())->getElementType(); - AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy); + cast(AddrWeakObj->getType())->getElementType(); + AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, + ObjCTypes.PtrObjectPtrTy); llvm::Value *read_weak = CGF.Builder.CreateCall(ObjCTypes.getGcReadWeakFn(), AddrWeakObj, "weakread"); read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy); @@ -2675,14 +2710,13 @@ llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF, /// objc_assign_weak (id src, id *dst) /// void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dst) -{ + llvm::Value *src, llvm::Value *dst) { const llvm::Type * SrcTy = src->getType(); if (!isa(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy) - : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy); + : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy); src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); @@ -2696,14 +2730,13 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, /// objc_assign_global (id src, id *dst) /// void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dst) -{ + llvm::Value *src, llvm::Value *dst) { const llvm::Type * SrcTy = src->getType(); if (!isa(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy) - : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy); + : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy); src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); @@ -2714,23 +2747,24 @@ void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, } /// EmitObjCIvarAssign - Code gen for assigning to a __strong object. -/// objc_assign_ivar (id src, id *dst) +/// objc_assign_ivar (id src, id *dst, ptrdiff_t ivaroffset) /// void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dst) -{ + llvm::Value *src, llvm::Value *dst, + llvm::Value *ivarOffset) { + assert(ivarOffset && "EmitObjCIvarAssign - ivarOffset is NULL"); const llvm::Type * SrcTy = src->getType(); if (!isa(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy) - : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy); + : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy); src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy); - CGF.Builder.CreateCall2(ObjCTypes.getGcAssignIvarFn(), - src, dst, "assignivar"); + CGF.Builder.CreateCall3(ObjCTypes.getGcAssignIvarFn(), + src, dst, ivarOffset); return; } @@ -2738,14 +2772,13 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, /// objc_assign_strongCast (id src, id *dst) /// void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dst) -{ + llvm::Value *src, llvm::Value *dst) { const llvm::Type * SrcTy = src->getType(); if (!isa(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy) - : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy); + : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy); src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); @@ -2755,6 +2788,21 @@ void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, return; } +void CGObjCMac::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, + llvm::Value *DestPtr, + llvm::Value *SrcPtr, + QualType Ty) { + // Get size info for this aggregate. + std::pair TypeInfo = CGM.getContext().getTypeInfo(Ty); + unsigned long size = TypeInfo.first/8; + SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy); + DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy); + llvm::Value *N = llvm::ConstantInt::get(ObjCTypes.LongTy, size); + CGF.Builder.CreateCall3(ObjCTypes.GcMemmoveCollectableFn(), + DestPtr, SrcPtr, N); + return; +} + /// EmitObjCValueForIvar - Code Gen for ivar reference. /// LValue CGObjCMac::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, @@ -2762,7 +2810,7 @@ LValue CGObjCMac::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, llvm::Value *BaseValue, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers) { - const ObjCInterfaceDecl *ID = ObjectTy->getAsObjCInterfaceType()->getDecl(); + const ObjCInterfaceDecl *ID = ObjectTy->getAs()->getDecl(); return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers, EmitIvarOffset(CGF, ID, Ivar)); } @@ -2772,8 +2820,8 @@ llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF, const ObjCIvarDecl *Ivar) { uint64_t Offset = ComputeIvarBaseOffset(CGM, Interface, Ivar); return llvm::ConstantInt::get( - CGM.getTypes().ConvertType(CGM.getContext().LongTy), - Offset); + CGM.getTypes().ConvertType(CGM.getContext().LongTy), + Offset); } /* *** Private Interface *** */ @@ -2789,8 +2837,8 @@ llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF, enum ImageInfoFlags { eImageInfo_FixAndContinue = (1 << 0), // FIXME: Not sure what // this implies. - eImageInfo_GarbageCollected = (1 << 1), - eImageInfo_GCOnly = (1 << 2), + eImageInfo_GarbageCollected = (1 << 1), + eImageInfo_GCOnly = (1 << 2), eImageInfo_OptimizedByDyld = (1 << 3), // FIXME: When is this set. // A flag indicating that the module has no instances of an @@ -2807,23 +2855,23 @@ void CGObjCMac::EmitImageInfo() { flags |= eImageInfo_GarbageCollected; if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) flags |= eImageInfo_GCOnly; - + // We never allow @synthesize of a superclass property. flags |= eImageInfo_CorrectedSynthesize; // Emitted as int[2]; llvm::Constant *values[2] = { - llvm::ConstantInt::get(llvm::Type::Int32Ty, version), - llvm::ConstantInt::get(llvm::Type::Int32Ty, flags) + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), version), + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), flags) }; - llvm::ArrayType *AT = llvm::ArrayType::get(llvm::Type::Int32Ty, 2); + llvm::ArrayType *AT = llvm::ArrayType::get(llvm::Type::getInt32Ty(VMContext), 2); const char *Section; if (ObjCABI == 1) Section = "__OBJC, __image_info,regular"; else Section = "__DATA, __objc_imageinfo, regular, no_dead_strip"; - llvm::GlobalVariable *GV = + llvm::GlobalVariable *GV = CreateMetadataVar("\01L_OBJC_IMAGE_INFO", llvm::ConstantArray::get(AT, values, 2), Section, @@ -2845,14 +2893,14 @@ static const int ModuleVersion = 7; void CGObjCMac::EmitModuleInfo() { uint64_t Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ModuleTy); - + std::vector Values(4); Values[0] = llvm::ConstantInt::get(ObjCTypes.LongTy, ModuleVersion); Values[1] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size); // This used to be the filename, now it is unused. Values[2] = GetClassName(&CGM.getContext().Idents.get("")); Values[3] = EmitModuleSymbols(); - CreateMetadataVar("\01L_OBJC_MODULES", + CreateMetadataVar("\01L_OBJC_MODULES", llvm::ConstantStruct::get(ObjCTypes.ModuleTy, Values), "__OBJC,__module_info,regular,no_dead_strip", 4, true); @@ -2879,16 +2927,16 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() { Symbols[i] = llvm::ConstantExpr::getBitCast(DefinedClasses[i], ObjCTypes.Int8PtrTy); for (unsigned i=0; igetIdentifier()); llvm::GlobalVariable *&Entry = ClassReferences[ID->getIdentifier()]; - + if (!Entry) { - llvm::Constant *Casted = + llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(GetClassName(ID->getIdentifier()), ObjCTypes.ClassPtrTy); - Entry = + Entry = CreateMetadataVar("\01L_OBJC_CLASS_REFERENCES_", Casted, "__OBJC,__cls_refs,literal_pointers,no_dead_strip", 4, true); @@ -2918,12 +2966,12 @@ llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder, llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel) { llvm::GlobalVariable *&Entry = SelectorReferences[Sel]; - + if (!Entry) { - llvm::Constant *Casted = + llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel), ObjCTypes.SelectorPtrTy); - Entry = + Entry = CreateMetadataVar("\01L_OBJC_SELECTOR_REFERENCES_", Casted, "__OBJC,__message_refs,literal_pointers,no_dead_strip", 4, true); @@ -2936,59 +2984,58 @@ llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) { llvm::GlobalVariable *&Entry = ClassNames[Ident]; if (!Entry) - Entry = CreateMetadataVar("\01L_OBJC_CLASS_NAME_", - llvm::ConstantArray::get(Ident->getName()), + Entry = CreateMetadataVar("\01L_OBJC_CLASS_NAME_", + llvm::ConstantArray::get(VMContext, Ident->getName()), "__TEXT,__cstring,cstring_literals", 1, true); - return getConstantGEP(Entry, 0, 0); + return getConstantGEP(VMContext, Entry, 0, 0); } /// GetIvarLayoutName - Returns a unique constant for the given /// ivar layout bitmap. llvm::Constant *CGObjCCommonMac::GetIvarLayoutName(IdentifierInfo *Ident, - const ObjCCommonTypesHelper &ObjCTypes) { + const ObjCCommonTypesHelper &ObjCTypes) { return llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); } -static QualType::GCAttrTypes GetGCAttrTypeForType(ASTContext &Ctx, - QualType FQT) { +static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) { if (FQT.isObjCGCStrong()) - return QualType::Strong; + return Qualifiers::Strong; if (FQT.isObjCGCWeak()) - return QualType::Weak; + return Qualifiers::Weak; - if (Ctx.isObjCObjectPointerType(FQT)) - return QualType::Strong; + if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType()) + return Qualifiers::Strong; - if (const PointerType *PT = FQT->getAsPointerType()) + if (const PointerType *PT = FQT->getAs()) return GetGCAttrTypeForType(Ctx, PT->getPointeeType()); - return QualType::GCNone; + return Qualifiers::GCNone; } void CGObjCCommonMac::BuildAggrIvarRecordLayout(const RecordType *RT, - unsigned int BytePos, + unsigned int BytePos, bool ForStrongLayout, bool &HasUnion) { const RecordDecl *RD = RT->getDecl(); // FIXME - Use iterator. llvm::SmallVector Fields(RD->field_begin(), RD->field_end()); const llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0)); - const llvm::StructLayout *RecLayout = + const llvm::StructLayout *RecLayout = CGM.getTargetData().getStructLayout(cast(Ty)); - + BuildAggrIvarLayout(0, RecLayout, RD, Fields, BytePos, ForStrongLayout, HasUnion); } void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, - const llvm::StructLayout *Layout, - const RecordDecl *RD, + const llvm::StructLayout *Layout, + const RecordDecl *RD, const llvm::SmallVectorImpl &RecFields, - unsigned int BytePos, bool ForStrongLayout, - bool &HasUnion) { + unsigned int BytePos, bool ForStrongLayout, + bool &HasUnion) { bool IsUnion = (RD && RD->isUnion()); uint64_t MaxUnionIvarSize = 0; uint64_t MaxSkippedUnionIvarSize = 0; @@ -2998,7 +3045,7 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, uint64_t MaxFieldOffset = 0; uint64_t MaxSkippedFieldOffset = 0; uint64_t LastBitfieldOffset = 0; - + if (RecFields.empty()) return; unsigned WordSizeInBits = CGM.getContext().Target.getPointerWidth(0); @@ -3007,10 +3054,19 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { FieldDecl *Field = RecFields[i]; uint64_t FieldOffset; - if (RD) - FieldOffset = - Layout->getElementOffset(CGM.getTypes().getLLVMFieldNo(Field)); - else + if (RD) { + if (Field->isBitField()) { + CodeGenTypes::BitFieldInfo Info = CGM.getTypes().getBitFieldInfo(Field); + + const llvm::Type *Ty = + CGM.getTypes().ConvertTypeForMemRecursive(Field->getType()); + uint64_t TypeSize = + CGM.getTypes().getTargetData().getTypeAllocSize(Ty); + FieldOffset = Info.FieldNo * TypeSize; + } else + FieldOffset = + Layout->getElementOffset(CGM.getTypes().getLLVMFieldNo(Field)); + } else FieldOffset = ComputeIvarBaseOffset(CGM, OI, cast(Field)); // Skip over unnamed or bitfields @@ -3026,14 +3082,14 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, if (FQT->isUnionType()) HasUnion = true; - BuildAggrIvarRecordLayout(FQT->getAsRecordType(), + BuildAggrIvarRecordLayout(FQT->getAs(), BytePos + FieldOffset, ForStrongLayout, HasUnion); continue; } - + if (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) { - const ConstantArrayType *CArray = + const ConstantArrayType *CArray = dyn_cast_or_null(Array); uint64_t ElCount = CArray->getSize().getZExtValue(); assert(CArray && "only array with known element size is supported"); @@ -3044,22 +3100,22 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, ElCount *= CArray->getSize().getZExtValue(); FQT = CArray->getElementType(); } - - assert(!FQT->isUnionType() && + + assert(!FQT->isUnionType() && "layout for array of unions not supported"); if (FQT->isRecordType()) { int OldIndex = IvarsInfo.size() - 1; int OldSkIndex = SkipIvars.size() -1; - - const RecordType *RT = FQT->getAsRecordType(); + + const RecordType *RT = FQT->getAs(); BuildAggrIvarRecordLayout(RT, BytePos + FieldOffset, ForStrongLayout, HasUnion); - + // Replicate layout information for each array element. Note that // one element is already done. uint64_t ElIx = 1; - for (int FirstIndex = IvarsInfo.size() - 1, - FirstSkIndex = SkipIvars.size() - 1 ;ElIx < ElCount; ElIx++) { + for (int FirstIndex = IvarsInfo.size() - 1, + FirstSkIndex = SkipIvars.size() - 1 ;ElIx < ElCount; ElIx++) { uint64_t Size = CGM.getContext().getTypeSize(RT)/ByteSizeInBits; for (int i = OldIndex+1; i <= FirstIndex; ++i) IvarsInfo.push_back(GC_IVAR(IvarsInfo[i].ivar_bytepos + Size*ElIx, @@ -3073,11 +3129,11 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, } // At this point, we are done with Record/Union and array there of. // For other arrays we are down to its element type. - QualType::GCAttrTypes GCAttr = GetGCAttrTypeForType(CGM.getContext(), FQT); + Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), FQT); unsigned FieldSize = CGM.getContext().getTypeSize(Field->getType()); - if ((ForStrongLayout && GCAttr == QualType::Strong) - || (!ForStrongLayout && GCAttr == QualType::Weak)) { + if ((ForStrongLayout && GCAttr == Qualifiers::Strong) + || (!ForStrongLayout && GCAttr == Qualifiers::Weak)) { if (IsUnion) { uint64_t UnionIvarSize = FieldSize / WordSizeInBits; if (UnionIvarSize > MaxUnionIvarSize) { @@ -3089,9 +3145,9 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, IvarsInfo.push_back(GC_IVAR(BytePos + FieldOffset, FieldSize / WordSizeInBits)); } - } else if ((ForStrongLayout && - (GCAttr == QualType::GCNone || GCAttr == QualType::Weak)) - || (!ForStrongLayout && GCAttr != QualType::Weak)) { + } else if ((ForStrongLayout && + (GCAttr == Qualifiers::GCNone || GCAttr == Qualifiers::Weak)) + || (!ForStrongLayout && GCAttr != Qualifiers::Weak)) { if (IsUnion) { // FIXME: Why the asymmetry? We divide by word size in bits on other // side. @@ -3116,13 +3172,13 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue(); GC_IVAR skivar; skivar.ivar_bytepos = BytePos + LastBitfieldOffset; - skivar.ivar_size = (BitFieldSize / ByteSizeInBits) - + ((BitFieldSize % ByteSizeInBits) != 0); - SkipIvars.push_back(skivar); + skivar.ivar_size = (BitFieldSize / ByteSizeInBits) + + ((BitFieldSize % ByteSizeInBits) != 0); + SkipIvars.push_back(skivar); } - + if (MaxField) - IvarsInfo.push_back(GC_IVAR(BytePos + MaxFieldOffset, + IvarsInfo.push_back(GC_IVAR(BytePos + MaxFieldOffset, MaxUnionIvarSize)); if (MaxSkippedField) SkipIvars.push_back(GC_IVAR(BytePos + MaxSkippedFieldOffset, @@ -3131,60 +3187,60 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, /// BuildIvarLayout - Builds ivar layout bitmap for the class /// implementation for the __strong or __weak case. -/// The layout map displays which words in ivar list must be skipped -/// and which must be scanned by GC (see below). String is built of bytes. -/// Each byte is divided up in two nibbles (4-bit each). Left nibble is count +/// The layout map displays which words in ivar list must be skipped +/// and which must be scanned by GC (see below). String is built of bytes. +/// Each byte is divided up in two nibbles (4-bit each). Left nibble is count /// of words to skip and right nibble is count of words to scan. So, each -/// nibble represents up to 15 workds to skip or scan. Skipping the rest is +/// nibble represents up to 15 workds to skip or scan. Skipping the rest is /// represented by a 0x00 byte which also ends the string. /// 1. when ForStrongLayout is true, following ivars are scanned: /// - id, Class /// - object * /// - __strong anything -/// +/// /// 2. When ForStrongLayout is false, following ivars are scanned: /// - __weak anything /// llvm::Constant *CGObjCCommonMac::BuildIvarLayout( - const ObjCImplementationDecl *OMD, - bool ForStrongLayout) { + const ObjCImplementationDecl *OMD, + bool ForStrongLayout) { bool hasUnion = false; - + unsigned int WordsToScan, WordsToSkip; - const llvm::Type *PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext); if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC) return llvm::Constant::getNullValue(PtrTy); - + llvm::SmallVector RecFields; const ObjCInterfaceDecl *OI = OMD->getClassInterface(); CGM.getContext().CollectObjCIvars(OI, RecFields); - + // Add this implementations synthesized ivars. llvm::SmallVector Ivars; CGM.getContext().CollectSynthesizedIvars(OI, Ivars); for (unsigned k = 0, e = Ivars.size(); k != e; ++k) RecFields.push_back(cast(Ivars[k])); - + if (RecFields.empty()) return llvm::Constant::getNullValue(PtrTy); - - SkipIvars.clear(); + + SkipIvars.clear(); IvarsInfo.clear(); - + BuildAggrIvarLayout(OMD, 0, 0, RecFields, 0, ForStrongLayout, hasUnion); if (IvarsInfo.empty()) return llvm::Constant::getNullValue(PtrTy); - + // Sort on byte position in case we encounterred a union nested in // the ivar list. if (hasUnion && !IvarsInfo.empty()) std::sort(IvarsInfo.begin(), IvarsInfo.end()); if (hasUnion && !SkipIvars.empty()) std::sort(SkipIvars.begin(), SkipIvars.end()); - + // Build the string of skip/scan nibbles llvm::SmallVector SkipScanIvars; - unsigned int WordSize = + unsigned int WordSize = CGM.getTypes().getTargetData().getTypeAllocSize(PtrTy); if (IvarsInfo[0].ivar_bytepos == 0) { WordsToSkip = 0; @@ -3194,7 +3250,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( WordsToScan = IvarsInfo[0].ivar_size; } for (unsigned int i=1, Last=IvarsInfo.size(); i != Last; i++) { - unsigned int TailPrevGCObjC = + unsigned int TailPrevGCObjC = IvarsInfo[i-1].ivar_bytepos + IvarsInfo[i-1].ivar_size * WordSize; if (IvarsInfo[i].ivar_bytepos == TailPrevGCObjC) { // consecutive 'scanned' object pointers. @@ -3209,7 +3265,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( SkScan.skip = WordsToSkip; SkScan.scan = WordsToScan; SkipScanIvars.push_back(SkScan); - + // Skip the hole. SkScan.skip = (IvarsInfo[i].ivar_bytepos - TailPrevGCObjC) / WordSize; SkScan.scan = 0; @@ -3224,16 +3280,16 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( SkScan.scan = WordsToScan; SkipScanIvars.push_back(SkScan); } - + bool BytesSkipped = false; if (!SkipIvars.empty()) { unsigned int LastIndex = SkipIvars.size()-1; - int LastByteSkipped = - SkipIvars[LastIndex].ivar_bytepos + SkipIvars[LastIndex].ivar_size; + int LastByteSkipped = + SkipIvars[LastIndex].ivar_bytepos + SkipIvars[LastIndex].ivar_size; LastIndex = IvarsInfo.size()-1; - int LastByteScanned = - IvarsInfo[LastIndex].ivar_bytepos + - IvarsInfo[LastIndex].ivar_size * WordSize; + int LastByteScanned = + IvarsInfo[LastIndex].ivar_bytepos + + IvarsInfo[LastIndex].ivar_size * WordSize; BytesSkipped = (LastByteSkipped > LastByteScanned); // Compute number of bytes to skip at the tail end of the last ivar scanned. if (BytesSkipped) { @@ -3257,7 +3313,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( --SkipScan; } } - + // Generate the string. std::string BitMap; for (int i = 0; i <= SkipScan; i++) { @@ -3272,7 +3328,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( // first skip big. for (unsigned int ix = 0; ix < skip_big; ix++) BitMap += (unsigned char)(0xf0); - + // next (skip small, scan) if (skip_small) { byte = skip_small << 4; @@ -3297,9 +3353,9 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( // null terminate string. unsigned char zero = 0; BitMap += zero; - + if (CGM.getLangOptions().ObjCGCBitmapPrint) { - printf("\n%s ivar layout for class '%s': ", + printf("\n%s ivar layout for class '%s': ", ForStrongLayout ? "strong" : "weak", OMD->getClassInterface()->getNameAsCString()); const unsigned char *s = (unsigned char*)BitMap.c_str(); @@ -3310,16 +3366,12 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( printf("0x%x%s", s[i], s[i] != 0 ? ", " : ""); printf("\n"); } - - // if ivar_layout bitmap is all 1 bits (nothing skipped) then use NULL as - // final layout. - if (ForStrongLayout && !BytesSkipped) - return llvm::Constant::getNullValue(PtrTy); - llvm::GlobalVariable * Entry = CreateMetadataVar("\01L_OBJC_CLASS_NAME_", - llvm::ConstantArray::get(BitMap.c_str()), - "__TEXT,__cstring,cstring_literals", - 1, true); - return getConstantGEP(Entry, 0, 0); + llvm::GlobalVariable * Entry = + CreateMetadataVar("\01L_OBJC_CLASS_NAME_", + llvm::ConstantArray::get(VMContext, BitMap.c_str()), + "__TEXT,__cstring,cstring_literals", + 1, true); + return getConstantGEP(VMContext, Entry, 0, 0); } llvm::Constant *CGObjCCommonMac::GetMethodVarName(Selector Sel) { @@ -3327,12 +3379,12 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarName(Selector Sel) { // FIXME: Avoid std::string copying. if (!Entry) - Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_NAME_", - llvm::ConstantArray::get(Sel.getAsString()), + Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_NAME_", + llvm::ConstantArray::get(VMContext, Sel.getAsString()), "__TEXT,__cstring,cstring_literals", 1, true); - return getConstantGEP(Entry, 0, 0); + return getConstantGEP(VMContext, Entry, 0, 0); } // FIXME: Merge into a single cstring creation function. @@ -3353,11 +3405,11 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) { if (!Entry) Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_TYPE_", - llvm::ConstantArray::get(TypeStr), + llvm::ConstantArray::get(VMContext, TypeStr), "__TEXT,__cstring,cstring_literals", 1, true); - - return getConstantGEP(Entry, 0, 0); + + return getConstantGEP(VMContext, Entry, 0, 0); } llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D) { @@ -3369,37 +3421,37 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D) { if (!Entry) Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_TYPE_", - llvm::ConstantArray::get(TypeStr), + llvm::ConstantArray::get(VMContext, TypeStr), "__TEXT,__cstring,cstring_literals", 1, true); - return getConstantGEP(Entry, 0, 0); + return getConstantGEP(VMContext, Entry, 0, 0); } // FIXME: Merge into a single cstring creation function. llvm::Constant *CGObjCCommonMac::GetPropertyName(IdentifierInfo *Ident) { llvm::GlobalVariable *&Entry = PropertyNames[Ident]; - + if (!Entry) - Entry = CreateMetadataVar("\01L_OBJC_PROP_NAME_ATTR_", - llvm::ConstantArray::get(Ident->getName()), + Entry = CreateMetadataVar("\01L_OBJC_PROP_NAME_ATTR_", + llvm::ConstantArray::get(VMContext, Ident->getName()), "__TEXT,__cstring,cstring_literals", 1, true); - return getConstantGEP(Entry, 0, 0); + return getConstantGEP(VMContext, Entry, 0, 0); } // FIXME: Merge into a single cstring creation function. // FIXME: This Decl should be more precise. llvm::Constant * - CGObjCCommonMac::GetPropertyTypeString(const ObjCPropertyDecl *PD, - const Decl *Container) { +CGObjCCommonMac::GetPropertyTypeString(const ObjCPropertyDecl *PD, + const Decl *Container) { std::string TypeStr; CGM.getContext().getObjCEncodingForPropertyDecl(PD, Container, TypeStr); return GetPropertyName(&CGM.getContext().Idents.get(TypeStr)); } -void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D, +void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D, const ObjCContainerDecl *CD, std::string &NameOut) { NameOut = '\01'; @@ -3407,7 +3459,7 @@ void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D, NameOut += '['; assert (CD && "Missing container decl in GetNameForMethod"); NameOut += CD->getNameAsString(); - if (const ObjCCategoryImplDecl *CID = + if (const ObjCCategoryImplDecl *CID = dyn_cast(D->getDeclContext())) { NameOut += '('; NameOut += CID->getNameAsString(); @@ -3418,64 +3470,55 @@ void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D, NameOut += ']'; } -void CGObjCCommonMac::MergeMetadataGlobals( - std::vector &UsedArray) { - llvm::Type *i8PTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); - for (std::vector::iterator i = UsedGlobals.begin(), - e = UsedGlobals.end(); i != e; ++i) { - UsedArray.push_back(llvm::ConstantExpr::getBitCast(cast(*i), - i8PTy)); - } -} - void CGObjCMac::FinishModule() { EmitModuleInfo(); // Emit the dummy bodies for any protocols which were referenced but // never defined. - for (llvm::DenseMap::iterator - i = Protocols.begin(), e = Protocols.end(); i != e; ++i) { - if (i->second->hasInitializer()) + for (llvm::DenseMap::iterator + I = Protocols.begin(), e = Protocols.end(); I != e; ++I) { + if (I->second->hasInitializer()) continue; std::vector Values(5); Values[0] = llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy); - Values[1] = GetClassName(i->first); + Values[1] = GetClassName(I->first); Values[2] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy); Values[3] = Values[4] = llvm::Constant::getNullValue(ObjCTypes.MethodDescriptionListPtrTy); - i->second->setLinkage(llvm::GlobalValue::InternalLinkage); - i->second->setInitializer(llvm::ConstantStruct::get(ObjCTypes.ProtocolTy, + I->second->setLinkage(llvm::GlobalValue::InternalLinkage); + I->second->setInitializer(llvm::ConstantStruct::get(ObjCTypes.ProtocolTy, Values)); + CGM.AddUsedGlobal(I->second); } // Add assembler directives to add lazy undefined symbol references // for classes which are referenced but not defined. This is // important for correct linker interaction. - - // FIXME: Uh, this isn't particularly portable. - std::stringstream s; - - if (!CGM.getModule().getModuleInlineAsm().empty()) - s << "\n"; - - for (std::set::iterator i = LazySymbols.begin(), - e = LazySymbols.end(); i != e; ++i) { - s << "\t.lazy_reference .objc_class_name_" << (*i)->getName() << "\n"; - } - for (std::set::iterator i = DefinedSymbols.begin(), - e = DefinedSymbols.end(); i != e; ++i) { - s << "\t.objc_class_name_" << (*i)->getName() << "=0\n" - << "\t.globl .objc_class_name_" << (*i)->getName() << "\n"; - } - - CGM.getModule().appendModuleInlineAsm(s.str()); + // + // FIXME: It would be nice if we had an LLVM construct for this. + if (!LazySymbols.empty() || !DefinedSymbols.empty()) { + llvm::SmallString<256> Asm; + Asm += CGM.getModule().getModuleInlineAsm(); + if (!Asm.empty() && Asm.back() != '\n') + Asm += '\n'; + + llvm::raw_svector_ostream OS(Asm); + for (llvm::SetVector::iterator I = LazySymbols.begin(), + e = LazySymbols.end(); I != e; ++I) + OS << "\t.lazy_reference .objc_class_name_" << (*I)->getName() << "\n"; + for (llvm::SetVector::iterator I = DefinedSymbols.begin(), + e = DefinedSymbols.end(); I != e; ++I) + OS << "\t.objc_class_name_" << (*I)->getName() << "=0\n" + << "\t.globl .objc_class_name_" << (*I)->getName() << "\n"; + + CGM.getModule().setModuleInlineAsm(OS.str()); + } } -CGObjCNonFragileABIMac::CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm) +CGObjCNonFragileABIMac::CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm) : CGObjCCommonMac(cgm), - ObjCTypes(cgm) -{ + ObjCTypes(cgm) { ObjCEmptyCacheVar = ObjCEmptyVtableVar = NULL; ObjCABI = 2; } @@ -3483,119 +3526,117 @@ CGObjCNonFragileABIMac::CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm) /* *** */ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) -: CGM(cgm) -{ + : VMContext(cgm.getLLVMContext()), CGM(cgm) { CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); - + ShortTy = Types.ConvertType(Ctx.ShortTy); IntTy = Types.ConvertType(Ctx.IntTy); LongTy = Types.ConvertType(Ctx.LongTy); LongLongTy = Types.ConvertType(Ctx.LongLongTy); - Int8PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); - + Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + ObjectPtrTy = Types.ConvertType(Ctx.getObjCIdType()); PtrObjectPtrTy = llvm::PointerType::getUnqual(ObjectPtrTy); SelectorPtrTy = Types.ConvertType(Ctx.getObjCSelType()); - + // FIXME: It would be nice to unify this with the opaque type, so that the IR // comes out a bit cleaner. const llvm::Type *T = Types.ConvertType(Ctx.getObjCProtoType()); ExternalProtocolPtrTy = llvm::PointerType::getUnqual(T); - + // I'm not sure I like this. The implicit coordination is a bit // gross. We should solve this in a reasonable fashion because this // is a pretty common task (match some runtime data structure with // an LLVM data structure). - + // FIXME: This is leaked. // FIXME: Merge with rewriter code? - + // struct _objc_super { // id self; // Class cls; // } RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, 0, SourceLocation(), - &Ctx.Idents.get("_objc_super")); - RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0, - Ctx.getObjCIdType(), 0, false)); + &Ctx.Idents.get("_objc_super")); + RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0, + Ctx.getObjCIdType(), 0, 0, false)); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0, - Ctx.getObjCClassType(), 0, false)); + Ctx.getObjCClassType(), 0, 0, false)); RD->completeDefinition(Ctx); - + SuperCTy = Ctx.getTagDeclType(RD); SuperPtrCTy = Ctx.getPointerType(SuperCTy); - + SuperTy = cast(Types.ConvertType(SuperCTy)); - SuperPtrTy = llvm::PointerType::getUnqual(SuperTy); - + SuperPtrTy = llvm::PointerType::getUnqual(SuperTy); + // struct _prop_t { // char *name; - // char *attributes; + // char *attributes; // } - PropertyTy = llvm::StructType::get(Int8PtrTy, Int8PtrTy, NULL); - CGM.getModule().addTypeName("struct._prop_t", + PropertyTy = llvm::StructType::get(VMContext, Int8PtrTy, Int8PtrTy, NULL); + CGM.getModule().addTypeName("struct._prop_t", PropertyTy); - + // struct _prop_list_t { // uint32_t entsize; // sizeof(struct _prop_t) // uint32_t count_of_properties; // struct _prop_t prop_list[count_of_properties]; // } - PropertyListTy = llvm::StructType::get(IntTy, + PropertyListTy = llvm::StructType::get(VMContext, IntTy, IntTy, llvm::ArrayType::get(PropertyTy, 0), NULL); - CGM.getModule().addTypeName("struct._prop_list_t", + CGM.getModule().addTypeName("struct._prop_list_t", PropertyListTy); // struct _prop_list_t * PropertyListPtrTy = llvm::PointerType::getUnqual(PropertyListTy); - + // struct _objc_method { // SEL _cmd; // char *method_type; // char *_imp; // } - MethodTy = llvm::StructType::get(SelectorPtrTy, + MethodTy = llvm::StructType::get(VMContext, SelectorPtrTy, Int8PtrTy, Int8PtrTy, NULL); CGM.getModule().addTypeName("struct._objc_method", MethodTy); - + // struct _objc_cache * - CacheTy = llvm::OpaqueType::get(); + CacheTy = llvm::OpaqueType::get(VMContext); CGM.getModule().addTypeName("struct._objc_cache", CacheTy); CachePtrTy = llvm::PointerType::getUnqual(CacheTy); } -ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) - : ObjCCommonTypesHelper(cgm) -{ +ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) + : ObjCCommonTypesHelper(cgm) { // struct _objc_method_description { // SEL name; // char *types; // } - MethodDescriptionTy = - llvm::StructType::get(SelectorPtrTy, + MethodDescriptionTy = + llvm::StructType::get(VMContext, SelectorPtrTy, Int8PtrTy, NULL); - CGM.getModule().addTypeName("struct._objc_method_description", + CGM.getModule().addTypeName("struct._objc_method_description", MethodDescriptionTy); // struct _objc_method_description_list { // int count; // struct _objc_method_description[1]; // } - MethodDescriptionListTy = - llvm::StructType::get(IntTy, + MethodDescriptionListTy = + llvm::StructType::get(VMContext, IntTy, llvm::ArrayType::get(MethodDescriptionTy, 0), NULL); - CGM.getModule().addTypeName("struct._objc_method_description_list", + CGM.getModule().addTypeName("struct._objc_method_description_list", MethodDescriptionListTy); - + // struct _objc_method_description_list * - MethodDescriptionListPtrTy = + MethodDescriptionListPtrTy = llvm::PointerType::getUnqual(MethodDescriptionListTy); // Protocol description structures @@ -3606,25 +3647,26 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) // struct _objc_method_description_list *optional_class_methods; // struct _objc_property_list *instance_properties; // } - ProtocolExtensionTy = - llvm::StructType::get(IntTy, + ProtocolExtensionTy = + llvm::StructType::get(VMContext, IntTy, MethodDescriptionListPtrTy, MethodDescriptionListPtrTy, PropertyListPtrTy, NULL); - CGM.getModule().addTypeName("struct._objc_protocol_extension", + CGM.getModule().addTypeName("struct._objc_protocol_extension", ProtocolExtensionTy); - + // struct _objc_protocol_extension * ProtocolExtensionPtrTy = llvm::PointerType::getUnqual(ProtocolExtensionTy); // Handle recursive construction of Protocol and ProtocolList types - llvm::PATypeHolder ProtocolTyHolder = llvm::OpaqueType::get(); - llvm::PATypeHolder ProtocolListTyHolder = llvm::OpaqueType::get(); + llvm::PATypeHolder ProtocolTyHolder = llvm::OpaqueType::get(VMContext); + llvm::PATypeHolder ProtocolListTyHolder = llvm::OpaqueType::get(VMContext); - const llvm::Type *T = - llvm::StructType::get(llvm::PointerType::getUnqual(ProtocolListTyHolder), + const llvm::Type *T = + llvm::StructType::get(VMContext, + llvm::PointerType::getUnqual(ProtocolListTyHolder), LongTy, llvm::ArrayType::get(ProtocolTyHolder, 0), NULL); @@ -3637,7 +3679,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) // struct _objc_method_description_list *instance_methods; // struct _objc_method_description_list *class_methods; // } - T = llvm::StructType::get(ProtocolExtensionPtrTy, + T = llvm::StructType::get(VMContext, ProtocolExtensionPtrTy, Int8PtrTy, llvm::PointerType::getUnqual(ProtocolListTyHolder), MethodDescriptionListPtrTy, @@ -3646,7 +3688,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) cast(ProtocolTyHolder.get())->refineAbstractTypeTo(T); ProtocolListTy = cast(ProtocolListTyHolder.get()); - CGM.getModule().addTypeName("struct._objc_protocol_list", + CGM.getModule().addTypeName("struct._objc_protocol_list", ProtocolListTy); // struct _objc_protocol_list * ProtocolListPtrTy = llvm::PointerType::getUnqual(ProtocolListTy); @@ -3662,32 +3704,32 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) // char *ivar_type; // int ivar_offset; // } - IvarTy = llvm::StructType::get(Int8PtrTy, - Int8PtrTy, - IntTy, + IvarTy = llvm::StructType::get(VMContext, Int8PtrTy, + Int8PtrTy, + IntTy, NULL); CGM.getModule().addTypeName("struct._objc_ivar", IvarTy); // struct _objc_ivar_list * - IvarListTy = llvm::OpaqueType::get(); + IvarListTy = llvm::OpaqueType::get(VMContext); CGM.getModule().addTypeName("struct._objc_ivar_list", IvarListTy); IvarListPtrTy = llvm::PointerType::getUnqual(IvarListTy); // struct _objc_method_list * - MethodListTy = llvm::OpaqueType::get(); + MethodListTy = llvm::OpaqueType::get(VMContext); CGM.getModule().addTypeName("struct._objc_method_list", MethodListTy); MethodListPtrTy = llvm::PointerType::getUnqual(MethodListTy); // struct _objc_class_extension * - ClassExtensionTy = - llvm::StructType::get(IntTy, + ClassExtensionTy = + llvm::StructType::get(VMContext, IntTy, Int8PtrTy, PropertyListPtrTy, NULL); CGM.getModule().addTypeName("struct._objc_class_extension", ClassExtensionTy); ClassExtensionPtrTy = llvm::PointerType::getUnqual(ClassExtensionTy); - llvm::PATypeHolder ClassTyHolder = llvm::OpaqueType::get(); + llvm::PATypeHolder ClassTyHolder = llvm::OpaqueType::get(VMContext); // struct _objc_class { // Class isa; @@ -3703,7 +3745,8 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) // char *ivar_layout; // struct _objc_class_ext *ext; // }; - T = llvm::StructType::get(llvm::PointerType::getUnqual(ClassTyHolder), + T = llvm::StructType::get(VMContext, + llvm::PointerType::getUnqual(ClassTyHolder), llvm::PointerType::getUnqual(ClassTyHolder), Int8PtrTy, LongTy, @@ -3717,7 +3760,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) ClassExtensionPtrTy, NULL); cast(ClassTyHolder.get())->refineAbstractTypeTo(T); - + ClassTy = cast(ClassTyHolder.get()); CGM.getModule().addTypeName("struct._objc_class", ClassTy); ClassPtrTy = llvm::PointerType::getUnqual(ClassTy); @@ -3730,7 +3773,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) // uint32_t size; // sizeof(struct _objc_category) // struct _objc_property_list *instance_properties;// category's @property // } - CategoryTy = llvm::StructType::get(Int8PtrTy, + CategoryTy = llvm::StructType::get(VMContext, Int8PtrTy, Int8PtrTy, MethodListPtrTy, MethodListPtrTy, @@ -3749,7 +3792,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) // short cat_def_cnt; // char *defs[cls_def_cnt + cat_def_cnt]; // } - SymtabTy = llvm::StructType::get(LongTy, + SymtabTy = llvm::StructType::get(VMContext, LongTy, SelectorPtrTy, ShortTy, ShortTy, @@ -3764,41 +3807,40 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) // char *name; // struct _objc_symtab* symtab; // } - ModuleTy = - llvm::StructType::get(LongTy, + ModuleTy = + llvm::StructType::get(VMContext, LongTy, LongTy, Int8PtrTy, SymtabPtrTy, NULL); CGM.getModule().addTypeName("struct._objc_module", ModuleTy); - + // FIXME: This is the size of the setjmp buffer and should be target // specific. 18 is what's used on 32-bit X86. uint64_t SetJmpBufferSize = 18; - + // Exceptions - const llvm::Type *StackPtrTy = - llvm::ArrayType::get(llvm::PointerType::getUnqual(llvm::Type::Int8Ty), 4); - - ExceptionDataTy = - llvm::StructType::get(llvm::ArrayType::get(llvm::Type::Int32Ty, - SetJmpBufferSize), + const llvm::Type *StackPtrTy = llvm::ArrayType::get( + llvm::Type::getInt8PtrTy(VMContext), 4); + + ExceptionDataTy = + llvm::StructType::get(VMContext, llvm::ArrayType::get(llvm::Type::getInt32Ty(VMContext), + SetJmpBufferSize), StackPtrTy, NULL); - CGM.getModule().addTypeName("struct._objc_exception_data", + CGM.getModule().addTypeName("struct._objc_exception_data", ExceptionDataTy); } -ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm) -: ObjCCommonTypesHelper(cgm) -{ +ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm) + : ObjCCommonTypesHelper(cgm) { // struct _method_list_t { // uint32_t entsize; // sizeof(struct _objc_method) // uint32_t method_count; // struct _objc_method method_list[method_count]; // } - MethodListnfABITy = llvm::StructType::get(IntTy, + MethodListnfABITy = llvm::StructType::get(VMContext, IntTy, IntTy, llvm::ArrayType::get(MethodTy, 0), NULL); @@ -3806,7 +3848,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul MethodListnfABITy); // struct method_list_t * MethodListnfABIPtrTy = llvm::PointerType::getUnqual(MethodListnfABITy); - + // struct _protocol_t { // id isa; // NULL // const char * const protocol_name; @@ -3819,11 +3861,11 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // const uint32_t size; // sizeof(struct _protocol_t) // const uint32_t flags; // = 0 // } - + // Holder for struct _protocol_list_t * - llvm::PATypeHolder ProtocolListTyHolder = llvm::OpaqueType::get(); - - ProtocolnfABITy = llvm::StructType::get(ObjectPtrTy, + llvm::PATypeHolder ProtocolListTyHolder = llvm::OpaqueType::get(VMContext); + + ProtocolnfABITy = llvm::StructType::get(VMContext, ObjectPtrTy, Int8PtrTy, llvm::PointerType::getUnqual( ProtocolListTyHolder), @@ -3840,23 +3882,23 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // struct _protocol_t* ProtocolnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolnfABITy); - + // struct _protocol_list_t { // long protocol_count; // Note, this is 32/64 bit // struct _protocol_t *[protocol_count]; // } - ProtocolListnfABITy = llvm::StructType::get(LongTy, + ProtocolListnfABITy = llvm::StructType::get(VMContext, LongTy, llvm::ArrayType::get( ProtocolnfABIPtrTy, 0), NULL); CGM.getModule().addTypeName("struct._objc_protocol_list", ProtocolListnfABITy); cast(ProtocolListTyHolder.get())->refineAbstractTypeTo( - ProtocolListnfABITy); - + ProtocolListnfABITy); + // struct _objc_protocol_list* ProtocolListnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolListnfABITy); - + // struct _ivar_t { // unsigned long int *offset; // pointer to ivar offset location // char *name; @@ -3864,28 +3906,29 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // uint32_t alignment; // uint32_t size; // } - IvarnfABITy = llvm::StructType::get(llvm::PointerType::getUnqual(LongTy), + IvarnfABITy = llvm::StructType::get(VMContext, + llvm::PointerType::getUnqual(LongTy), Int8PtrTy, Int8PtrTy, IntTy, IntTy, NULL); CGM.getModule().addTypeName("struct._ivar_t", IvarnfABITy); - + // struct _ivar_list_t { // uint32 entsize; // sizeof(struct _ivar_t) // uint32 count; // struct _iver_t list[count]; // } - IvarListnfABITy = llvm::StructType::get(IntTy, + IvarListnfABITy = llvm::StructType::get(VMContext, IntTy, IntTy, llvm::ArrayType::get( - IvarnfABITy, 0), + IvarnfABITy, 0), NULL); CGM.getModule().addTypeName("struct._ivar_list_t", IvarListnfABITy); - + IvarListnfABIPtrTy = llvm::PointerType::getUnqual(IvarListnfABITy); - + // struct _class_ro_t { // uint32_t const flags; // uint32_t const instanceStart; @@ -3899,9 +3942,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // const uint8_t * const weakIvarLayout; // const struct _prop_list_t * const properties; // } - + // FIXME. Add 'reserved' field in 64bit abi mode! - ClassRonfABITy = llvm::StructType::get(IntTy, + ClassRonfABITy = llvm::StructType::get(VMContext, IntTy, IntTy, IntTy, Int8PtrTy, @@ -3914,14 +3957,14 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul NULL); CGM.getModule().addTypeName("struct._class_ro_t", ClassRonfABITy); - + // ImpnfABITy - LLVM for id (*)(id, SEL, ...) std::vector Params; Params.push_back(ObjectPtrTy); Params.push_back(SelectorPtrTy); ImpnfABITy = llvm::PointerType::getUnqual( - llvm::FunctionType::get(ObjectPtrTy, Params, false)); - + llvm::FunctionType::get(ObjectPtrTy, Params, false)); + // struct _class_t { // struct _class_t *isa; // struct _class_t * const superclass; @@ -3929,23 +3972,24 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // IMP *vtable; // struct class_ro_t *ro; // } - - llvm::PATypeHolder ClassTyHolder = llvm::OpaqueType::get(); - ClassnfABITy = llvm::StructType::get(llvm::PointerType::getUnqual(ClassTyHolder), - llvm::PointerType::getUnqual(ClassTyHolder), - CachePtrTy, - llvm::PointerType::getUnqual(ImpnfABITy), - llvm::PointerType::getUnqual( - ClassRonfABITy), - NULL); + + llvm::PATypeHolder ClassTyHolder = llvm::OpaqueType::get(VMContext); + ClassnfABITy = + llvm::StructType::get(VMContext, + llvm::PointerType::getUnqual(ClassTyHolder), + llvm::PointerType::getUnqual(ClassTyHolder), + CachePtrTy, + llvm::PointerType::getUnqual(ImpnfABITy), + llvm::PointerType::getUnqual(ClassRonfABITy), + NULL); CGM.getModule().addTypeName("struct._class_t", ClassnfABITy); cast(ClassTyHolder.get())->refineAbstractTypeTo( - ClassnfABITy); - + ClassnfABITy); + // LLVM for struct _class_t * ClassnfABIPtrTy = llvm::PointerType::getUnqual(ClassnfABITy); - + // struct _category_t { // const char * const name; // struct _class_t *const cls; @@ -3954,7 +3998,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // const struct _protocol_list_t * const protocols; // const struct _prop_list_t * const properties; // } - CategorynfABITy = llvm::StructType::get(Int8PtrTy, + CategorynfABITy = llvm::StructType::get(VMContext, Int8PtrTy, ClassnfABIPtrTy, MethodListnfABIPtrTy, MethodListnfABIPtrTy, @@ -3962,54 +4006,55 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul PropertyListPtrTy, NULL); CGM.getModule().addTypeName("struct._category_t", CategorynfABITy); - + // New types for nonfragile abi messaging. CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); - + // MessageRefTy - LLVM for: // struct _message_ref_t { // IMP messenger; // SEL name; // }; - + // First the clang type for struct _message_ref_t RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, 0, SourceLocation(), &Ctx.Idents.get("_message_ref_t")); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0, - Ctx.VoidPtrTy, 0, false)); + Ctx.VoidPtrTy, 0, 0, false)); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0, - Ctx.getObjCSelType(), 0, false)); + Ctx.getObjCSelType(), 0, 0, false)); RD->completeDefinition(Ctx); - + MessageRefCTy = Ctx.getTagDeclType(RD); MessageRefCPtrTy = Ctx.getPointerType(MessageRefCTy); MessageRefTy = cast(Types.ConvertType(MessageRefCTy)); - + // MessageRefPtrTy - LLVM for struct _message_ref_t* MessageRefPtrTy = llvm::PointerType::getUnqual(MessageRefTy); - + // SuperMessageRefTy - LLVM for: // struct _super_message_ref_t { // SUPER_IMP messenger; // SEL name; // }; - SuperMessageRefTy = llvm::StructType::get(ImpnfABITy, + SuperMessageRefTy = llvm::StructType::get(VMContext, ImpnfABITy, SelectorPtrTy, NULL); CGM.getModule().addTypeName("struct._super_message_ref_t", SuperMessageRefTy); - + // SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t* - SuperMessageRefPtrTy = llvm::PointerType::getUnqual(SuperMessageRefTy); - + SuperMessageRefPtrTy = llvm::PointerType::getUnqual(SuperMessageRefTy); + // struct objc_typeinfo { // const void** vtable; // objc_ehtype_vtable + 2 // const char* name; // c++ typeinfo string // Class cls; // }; - EHTypeTy = llvm::StructType::get(llvm::PointerType::getUnqual(Int8PtrTy), + EHTypeTy = llvm::StructType::get(VMContext, + llvm::PointerType::getUnqual(Int8PtrTy), Int8PtrTy, ClassnfABIPtrTy, NULL); @@ -4017,63 +4062,62 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul EHTypePtrTy = llvm::PointerType::getUnqual(EHTypeTy); } -llvm::Function *CGObjCNonFragileABIMac::ModuleInitFunction() { +llvm::Function *CGObjCNonFragileABIMac::ModuleInitFunction() { FinishNonFragileABIModule(); - + return NULL; } -void CGObjCNonFragileABIMac::AddModuleClassList(const - std::vector - &Container, +void CGObjCNonFragileABIMac::AddModuleClassList(const + std::vector + &Container, const char *SymbolName, const char *SectionName) { unsigned NumClasses = Container.size(); - + if (!NumClasses) return; - + std::vector Symbols(NumClasses); for (unsigned i=0; igetType(), false, + new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, llvm::GlobalValue::InternalLinkage, Init, - SymbolName, - &CGM.getModule()); + SymbolName); GV->setAlignment(8); GV->setSection(SectionName); - UsedGlobals.push_back(GV); + CGM.AddUsedGlobal(GV); } - + void CGObjCNonFragileABIMac::FinishNonFragileABIModule() { // nonfragile abi has no module definition. - + // Build list of all implemented class addresses in array // L_OBJC_LABEL_CLASS_$. - AddModuleClassList(DefinedClasses, + AddModuleClassList(DefinedClasses, "\01L_OBJC_LABEL_CLASS_$", "__DATA, __objc_classlist, regular, no_dead_strip"); - AddModuleClassList(DefinedNonLazyClasses, + AddModuleClassList(DefinedNonLazyClasses, "\01L_OBJC_LABEL_NONLAZY_CLASS_$", "__DATA, __objc_nlclslist, regular, no_dead_strip"); - + // Build list of all implemented category addresses in array // L_OBJC_LABEL_CATEGORY_$. - AddModuleClassList(DefinedCategories, + AddModuleClassList(DefinedCategories, "\01L_OBJC_LABEL_CATEGORY_$", "__DATA, __objc_catlist, regular, no_dead_strip"); - AddModuleClassList(DefinedNonLazyCategories, + AddModuleClassList(DefinedNonLazyCategories, "\01L_OBJC_LABEL_NONLAZY_CATEGORY_$", "__DATA, __objc_nlcatlist, regular, no_dead_strip"); - + // static int L_OBJC_IMAGE_INFO[2] = { 0, flags }; // FIXME. flags can be 0 | 1 | 2 | 6. For now just use 0 std::vector Values(2); @@ -4086,22 +4130,21 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() { flags |= eImageInfo_GCOnly; Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags); llvm::Constant* Init = llvm::ConstantArray::get( - llvm::ArrayType::get(ObjCTypes.IntTy, 2), - Values); + llvm::ArrayType::get(ObjCTypes.IntTy, 2), + Values); llvm::GlobalVariable *IMGV = - new llvm::GlobalVariable(Init->getType(), false, + new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, llvm::GlobalValue::InternalLinkage, Init, - "\01L_OBJC_IMAGE_INFO", - &CGM.getModule()); + "\01L_OBJC_IMAGE_INFO"); IMGV->setSection("__DATA, __objc_imageinfo, regular, no_dead_strip"); IMGV->setConstant(true); - UsedGlobals.push_back(IMGV); + CGM.AddUsedGlobal(IMGV); } /// LegacyDispatchedSelector - Returns true if SEL is not in the list of /// NonLegacyDispatchMethods; false otherwise. What this means is that -/// except for the 19 selectors in the list, we generate 32bit-style +/// except for the 19 selectors in the list, we generate 32bit-style /// message dispatch call for all the rest. /// bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) { @@ -4116,7 +4159,7 @@ bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) { NonLegacyDispatchMethods.insert(GetNullarySelector("release")); NonLegacyDispatchMethods.insert(GetNullarySelector("autorelease")); NonLegacyDispatchMethods.insert(GetNullarySelector("hash")); - + NonLegacyDispatchMethods.insert(GetUnarySelector("allocWithZone")); NonLegacyDispatchMethods.insert(GetUnarySelector("isKindOfClass")); NonLegacyDispatchMethods.insert(GetUnarySelector("respondsToSelector")); @@ -4125,11 +4168,11 @@ bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) { NonLegacyDispatchMethods.insert(GetUnarySelector("isEqualToString")); NonLegacyDispatchMethods.insert(GetUnarySelector("isEqual")); NonLegacyDispatchMethods.insert(GetUnarySelector("addObject")); - // "countByEnumeratingWithState:objects:count" + // "countByEnumeratingWithState:objects:count" IdentifierInfo *KeyIdents[] = { - &CGM.getContext().Idents.get("countByEnumeratingWithState"), - &CGM.getContext().Idents.get("objects"), - &CGM.getContext().Idents.get("count") + &CGM.getContext().Idents.get("countByEnumeratingWithState"), + &CGM.getContext().Idents.get("objects"), + &CGM.getContext().Idents.get("count") }; NonLegacyDispatchMethods.insert( CGM.getContext().Selectors.getSelector(3, KeyIdents)); @@ -4161,43 +4204,43 @@ enum MetaDataDlags { /// } /// llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( - unsigned flags, - unsigned InstanceStart, - unsigned InstanceSize, - const ObjCImplementationDecl *ID) { + unsigned flags, + unsigned InstanceStart, + unsigned InstanceSize, + const ObjCImplementationDecl *ID) { std::string ClassName = ID->getNameAsString(); std::vector Values(10); // 11 for 64bit targets! Values[ 0] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags); Values[ 1] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceStart); Values[ 2] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceSize); // FIXME. For 64bit targets add 0 here. - Values[ 3] = (flags & CLS_META) ? GetIvarLayoutName(0, ObjCTypes) - : BuildIvarLayout(ID, true); + Values[ 3] = (flags & CLS_META) ? GetIvarLayoutName(0, ObjCTypes) + : BuildIvarLayout(ID, true); Values[ 4] = GetClassName(ID->getIdentifier()); // const struct _method_list_t * const baseMethods; std::vector Methods; std::string MethodListName("\01l_OBJC_$_"); if (flags & CLS_META) { MethodListName += "CLASS_METHODS_" + ID->getNameAsString(); - for (ObjCImplementationDecl::classmeth_iterator + for (ObjCImplementationDecl::classmeth_iterator i = ID->classmeth_begin(), e = ID->classmeth_end(); i != e; ++i) { // Class methods should always be defined. Methods.push_back(GetMethodConstant(*i)); } } else { MethodListName += "INSTANCE_METHODS_" + ID->getNameAsString(); - for (ObjCImplementationDecl::instmeth_iterator + for (ObjCImplementationDecl::instmeth_iterator i = ID->instmeth_begin(), e = ID->instmeth_end(); i != e; ++i) { // Instance methods should always be defined. Methods.push_back(GetMethodConstant(*i)); } - for (ObjCImplementationDecl::propimpl_iterator + for (ObjCImplementationDecl::propimpl_iterator i = ID->propimpl_begin(), e = ID->propimpl_end(); i != e; ++i) { ObjCPropertyImplDecl *PID = *i; - + if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize){ ObjCPropertyDecl *PD = PID->getPropertyDecl(); - + if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) if (llvm::Constant *C = GetMethodConstant(MD)) Methods.push_back(C); @@ -4207,39 +4250,37 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( } } } - Values[ 5] = EmitMethodList(MethodListName, - "__DATA, __objc_const", Methods); - + Values[ 5] = EmitMethodList(MethodListName, + "__DATA, __objc_const", Methods); + const ObjCInterfaceDecl *OID = ID->getClassInterface(); assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer"); - Values[ 6] = EmitProtocolList("\01l_OBJC_CLASS_PROTOCOLS_$_" + Values[ 6] = EmitProtocolList("\01l_OBJC_CLASS_PROTOCOLS_$_" + OID->getNameAsString(), OID->protocol_begin(), OID->protocol_end()); - + if (flags & CLS_META) Values[ 7] = llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy); else Values[ 7] = EmitIvarList(ID); - Values[ 8] = (flags & CLS_META) ? GetIvarLayoutName(0, ObjCTypes) - : BuildIvarLayout(ID, false); + Values[ 8] = (flags & CLS_META) ? GetIvarLayoutName(0, ObjCTypes) + : BuildIvarLayout(ID, false); if (flags & CLS_META) Values[ 9] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); else - Values[ 9] = - EmitPropertyList( - "\01l_OBJC_$_PROP_LIST_" + ID->getNameAsString(), + Values[ 9] = + EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getNameAsString(), ID, ID->getClassInterface(), ObjCTypes); llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassRonfABITy, Values); llvm::GlobalVariable *CLASS_RO_GV = - new llvm::GlobalVariable(ObjCTypes.ClassRonfABITy, false, - llvm::GlobalValue::InternalLinkage, - Init, - (flags & CLS_META) ? - std::string("\01l_OBJC_METACLASS_RO_$_")+ClassName : - std::string("\01l_OBJC_CLASS_RO_$_")+ClassName, - &CGM.getModule()); + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassRonfABITy, false, + llvm::GlobalValue::InternalLinkage, + Init, + (flags & CLS_META) ? + std::string("\01l_OBJC_METACLASS_RO_$_")+ClassName : + std::string("\01l_OBJC_CLASS_RO_$_")+ClassName); CLASS_RO_GV->setAlignment( CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ClassRonfABITy)); CLASS_RO_GV->setSection("__DATA, __objc_const"); @@ -4258,20 +4299,20 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( /// } /// llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData( - std::string &ClassName, - llvm::Constant *IsAGV, - llvm::Constant *SuperClassGV, - llvm::Constant *ClassRoGV, - bool HiddenVisibility) { + std::string &ClassName, + llvm::Constant *IsAGV, + llvm::Constant *SuperClassGV, + llvm::Constant *ClassRoGV, + bool HiddenVisibility) { std::vector Values(5); Values[0] = IsAGV; - Values[1] = SuperClassGV - ? SuperClassGV - : llvm::Constant::getNullValue(ObjCTypes.ClassnfABIPtrTy); + Values[1] = SuperClassGV; + if (!Values[1]) + Values[1] = llvm::Constant::getNullValue(ObjCTypes.ClassnfABIPtrTy); Values[2] = ObjCEmptyCacheVar; // &ObjCEmptyCacheVar Values[3] = ObjCEmptyVtableVar; // &ObjCEmptyVtableVar Values[4] = ClassRoGV; // &CLASS_RO_GV - llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassnfABITy, + llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassnfABITy, Values); llvm::GlobalVariable *GV = GetClassGlobal(ClassName); GV->setInitializer(Init); @@ -4283,7 +4324,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData( return GV; } -bool +bool CGObjCNonFragileABIMac::ImplementationIsNonLazy(const ObjCImplDecl *OD) const { return OD->getClassMethod(GetNullarySelector("load")) != 0; } @@ -4291,11 +4332,11 @@ CGObjCNonFragileABIMac::ImplementationIsNonLazy(const ObjCImplDecl *OD) const { void CGObjCNonFragileABIMac::GetClassSizeInfo(const ObjCImplementationDecl *OID, uint32_t &InstanceStart, uint32_t &InstanceSize) { - const ASTRecordLayout &RL = + const ASTRecordLayout &RL = CGM.getContext().getASTObjCImplementationLayout(OID); - + // InstanceSize is really instance end. - InstanceSize = llvm::RoundUpToAlignment(RL.getNextOffset(), 8) / 8; + InstanceSize = llvm::RoundUpToAlignment(RL.getDataSize(), 8) / 8; // If there are no fields, the start is the same as the end. if (!RL.getFieldCount()) @@ -4308,34 +4349,34 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { std::string ClassName = ID->getNameAsString(); if (!ObjCEmptyCacheVar) { ObjCEmptyCacheVar = new llvm::GlobalVariable( - ObjCTypes.CacheTy, - false, - llvm::GlobalValue::ExternalLinkage, - 0, - "_objc_empty_cache", - &CGM.getModule()); - + CGM.getModule(), + ObjCTypes.CacheTy, + false, + llvm::GlobalValue::ExternalLinkage, + 0, + "_objc_empty_cache"); + ObjCEmptyVtableVar = new llvm::GlobalVariable( - ObjCTypes.ImpnfABITy, - false, - llvm::GlobalValue::ExternalLinkage, - 0, - "_objc_empty_vtable", - &CGM.getModule()); - } - assert(ID->getClassInterface() && + CGM.getModule(), + ObjCTypes.ImpnfABITy, + false, + llvm::GlobalValue::ExternalLinkage, + 0, + "_objc_empty_vtable"); + } + assert(ID->getClassInterface() && "CGObjCNonFragileABIMac::GenerateClass - class is 0"); // FIXME: Is this correct (that meta class size is never computed)? - uint32_t InstanceStart = + uint32_t InstanceStart = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassnfABITy); uint32_t InstanceSize = InstanceStart; uint32_t flags = CLS_META; std::string ObjCMetaClassName(getMetaclassSymbolPrefix()); std::string ObjCClassName(getClassSymbolPrefix()); - + llvm::GlobalVariable *SuperClassGV, *IsAGV; - - bool classIsHidden = + + bool classIsHidden = CGM.getDeclVisibilityMode(ID->getClassInterface()) == LangOptions::Hidden; if (classIsHidden) flags |= OBJC2_CLS_HIDDEN; @@ -4351,7 +4392,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { Root = Super; IsAGV = GetClassGlobal(ObjCMetaClassName + Root->getNameAsString()); // work on super class metadata symbol. - std::string SuperClassName = + std::string SuperClassName = ObjCMetaClassName + ID->getClassInterface()->getSuperClass()->getNameAsString(); SuperClassGV = GetClassGlobal(SuperClassName); } @@ -4359,7 +4400,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { InstanceStart, InstanceSize,ID); std::string TClassName = ObjCMetaClassName + ClassName; - llvm::GlobalVariable *MetaTClass = + llvm::GlobalVariable *MetaTClass = BuildClassMetaData(TClassName, IsAGV, SuperClassGV, CLASS_RO_GV, classIsHidden); @@ -4383,11 +4424,11 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { GetClassSizeInfo(ID, InstanceStart, InstanceSize); CLASS_RO_GV = BuildClassRoTInitializer(flags, InstanceStart, - InstanceSize, + InstanceSize, ID); - + TClassName = ObjCClassName + ClassName; - llvm::GlobalVariable *ClassMD = + llvm::GlobalVariable *ClassMD = BuildClassMetaData(TClassName, MetaTClass, SuperClassGV, CLASS_RO_GV, classIsHidden); DefinedClasses.push_back(ClassMD); @@ -4410,29 +4451,30 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { /// which will hold address of the protocol meta-data. /// llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder, - const ObjCProtocolDecl *PD) { - + const ObjCProtocolDecl *PD) { + // This routine is called for @protocol only. So, we must build definition // of protocol's meta-data (not a reference to it!) // - llvm::Constant *Init = llvm::ConstantExpr::getBitCast(GetOrEmitProtocol(PD), - ObjCTypes.ExternalProtocolPtrTy); - + llvm::Constant *Init = + llvm::ConstantExpr::getBitCast(GetOrEmitProtocol(PD), + ObjCTypes.ExternalProtocolPtrTy); + std::string ProtocolName("\01l_OBJC_PROTOCOL_REFERENCE_$_"); ProtocolName += PD->getNameAsCString(); - + llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName); if (PTGV) return Builder.CreateLoad(PTGV, false, "tmp"); PTGV = new llvm::GlobalVariable( - Init->getType(), false, - llvm::GlobalValue::WeakAnyLinkage, - Init, - ProtocolName, - &CGM.getModule()); + CGM.getModule(), + Init->getType(), false, + llvm::GlobalValue::WeakAnyLinkage, + Init, + ProtocolName); PTGV->setSection("__DATA, __objc_protorefs, coalesced, no_dead_strip"); PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility); - UsedGlobals.push_back(PTGV); + CGM.AddUsedGlobal(PTGV); return Builder.CreateLoad(PTGV, false, "tmp"); } @@ -4449,11 +4491,11 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder, void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { const ObjCInterfaceDecl *Interface = OCD->getClassInterface(); const char *Prefix = "\01l_OBJC_$_CATEGORY_"; - std::string ExtCatName(Prefix + Interface->getNameAsString()+ - "_$_" + OCD->getNameAsString()); - std::string ExtClassName(getClassSymbolPrefix() + + std::string ExtCatName(Prefix + Interface->getNameAsString()+ + "_$_" + OCD->getNameAsString()); + std::string ExtClassName(getClassSymbolPrefix() + Interface->getNameAsString()); - + std::vector Values(6); Values[0] = GetClassName(OCD->getIdentifier()); // meta-class entry symbol @@ -4461,33 +4503,33 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { Values[1] = ClassGV; std::vector Methods; std::string MethodListName(Prefix); - MethodListName += "INSTANCE_METHODS_" + Interface->getNameAsString() + + MethodListName += "INSTANCE_METHODS_" + Interface->getNameAsString() + "_$_" + OCD->getNameAsString(); - - for (ObjCCategoryImplDecl::instmeth_iterator + + for (ObjCCategoryImplDecl::instmeth_iterator i = OCD->instmeth_begin(), e = OCD->instmeth_end(); i != e; ++i) { // Instance methods should always be defined. Methods.push_back(GetMethodConstant(*i)); } - - Values[2] = EmitMethodList(MethodListName, - "__DATA, __objc_const", + + Values[2] = EmitMethodList(MethodListName, + "__DATA, __objc_const", Methods); MethodListName = Prefix; MethodListName += "CLASS_METHODS_" + Interface->getNameAsString() + "_$_" + OCD->getNameAsString(); Methods.clear(); - for (ObjCCategoryImplDecl::classmeth_iterator + for (ObjCCategoryImplDecl::classmeth_iterator i = OCD->classmeth_begin(), e = OCD->classmeth_end(); i != e; ++i) { // Class methods should always be defined. Methods.push_back(GetMethodConstant(*i)); } - - Values[3] = EmitMethodList(MethodListName, - "__DATA, __objc_const", + + Values[3] = EmitMethodList(MethodListName, + "__DATA, __objc_const", Methods); - const ObjCCategoryDecl *Category = + const ObjCCategoryDecl *Category = Interface->FindCategoryDeclaration(OCD->getIdentifier()); if (Category) { std::string ExtName(Interface->getNameAsString() + "_$_" + @@ -4500,26 +4542,24 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { Values[5] = EmitPropertyList(std::string("\01l_OBJC_$_PROP_LIST_") + ExtName, OCD, Category, ObjCTypes); - } - else { + } else { Values[4] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy); Values[5] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); } - - llvm::Constant *Init = - llvm::ConstantStruct::get(ObjCTypes.CategorynfABITy, + + llvm::Constant *Init = + llvm::ConstantStruct::get(ObjCTypes.CategorynfABITy, Values); llvm::GlobalVariable *GCATV - = new llvm::GlobalVariable(ObjCTypes.CategorynfABITy, + = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.CategorynfABITy, false, llvm::GlobalValue::InternalLinkage, Init, - ExtCatName, - &CGM.getModule()); + ExtCatName); GCATV->setAlignment( CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.CategorynfABITy)); GCATV->setSection("__DATA, __objc_const"); - UsedGlobals.push_back(GCATV); + CGM.AddUsedGlobal(GCATV); DefinedCategories.push_back(GCATV); // Determine if this category is also "non-lazy". @@ -4531,16 +4571,16 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { /// given method if it has been defined. The result is null if the /// method has not been defined. The return value has type MethodPtrTy. llvm::Constant *CGObjCNonFragileABIMac::GetMethodConstant( - const ObjCMethodDecl *MD) { + const ObjCMethodDecl *MD) { // FIXME: Use DenseMap::lookup llvm::Function *Fn = MethodDefinitions[MD]; if (!Fn) return 0; - + std::vector Method(3); - Method[0] = - llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()), - ObjCTypes.SelectorPtrTy); + Method[0] = + llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()), + ObjCTypes.SelectorPtrTy); Method[1] = GetMethodVarType(MD); Method[2] = llvm::ConstantExpr::getBitCast(Fn, ObjCTypes.Int8PtrTy); return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Method); @@ -4554,13 +4594,13 @@ llvm::Constant *CGObjCNonFragileABIMac::GetMethodConstant( /// } /// llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList( - const std::string &Name, - const char *Section, - const ConstantVector &Methods) { + const std::string &Name, + const char *Section, + const ConstantVector &Methods) { // Return null for empty list. if (Methods.empty()) return llvm::Constant::getNullValue(ObjCTypes.MethodListnfABIPtrTy); - + std::vector Values(3); // sizeof(struct _objc_method) unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.MethodTy); @@ -4570,18 +4610,17 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList( llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.MethodTy, Methods.size()); Values[2] = llvm::ConstantArray::get(AT, Methods); - llvm::Constant *Init = llvm::ConstantStruct::get(Values); - + llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false); + llvm::GlobalVariable *GV = - new llvm::GlobalVariable(Init->getType(), false, + new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, llvm::GlobalValue::InternalLinkage, Init, - Name, - &CGM.getModule()); + Name); GV->setAlignment( CGM.getTargetData().getPrefTypeAlignment(Init->getType())); GV->setSection(Section); - UsedGlobals.push_back(GV); + CGM.AddUsedGlobal(GV); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListnfABIPtrTy); } @@ -4589,34 +4628,33 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList( /// ObjCIvarOffsetVariable - Returns the ivar offset variable for /// the given ivar. llvm::GlobalVariable * CGObjCNonFragileABIMac::ObjCIvarOffsetVariable( - const ObjCInterfaceDecl *ID, - const ObjCIvarDecl *Ivar) { + const ObjCInterfaceDecl *ID, + const ObjCIvarDecl *Ivar) { // FIXME: We shouldn't need to do this lookup. unsigned Index; - const ObjCInterfaceDecl *Container = + const ObjCInterfaceDecl *Container = FindIvarInterface(CGM.getContext(), ID, Ivar, Index); assert(Container && "Unable to find ivar container!"); std::string Name = "OBJC_IVAR_$_" + Container->getNameAsString() + '.' + Ivar->getNameAsString(); - llvm::GlobalVariable *IvarOffsetGV = + llvm::GlobalVariable *IvarOffsetGV = CGM.getModule().getGlobalVariable(Name); if (!IvarOffsetGV) - IvarOffsetGV = - new llvm::GlobalVariable(ObjCTypes.LongTy, + IvarOffsetGV = + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.LongTy, false, llvm::GlobalValue::ExternalLinkage, 0, - Name, - &CGM.getModule()); + Name); return IvarOffsetGV; } llvm::Constant * CGObjCNonFragileABIMac::EmitIvarOffsetVar( - const ObjCInterfaceDecl *ID, - const ObjCIvarDecl *Ivar, - unsigned long int Offset) { + const ObjCInterfaceDecl *ID, + const ObjCIvarDecl *Ivar, + unsigned long int Offset) { llvm::GlobalVariable *IvarOffsetGV = ObjCIvarOffsetVariable(ID, Ivar); - IvarOffsetGV->setInitializer(llvm::ConstantInt::get(ObjCTypes.LongTy, + IvarOffsetGV->setInitializer(llvm::ConstantInt::get(ObjCTypes.LongTy, Offset)); IvarOffsetGV->setAlignment( CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.LongTy)); @@ -4651,25 +4689,25 @@ llvm::Constant * CGObjCNonFragileABIMac::EmitIvarOffsetVar( /// llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( - const ObjCImplementationDecl *ID) { - + const ObjCImplementationDecl *ID) { + std::vector Ivars, Ivar(5); - + const ObjCInterfaceDecl *OID = ID->getClassInterface(); assert(OID && "CGObjCNonFragileABIMac::EmitIvarList - null interface"); - + // FIXME. Consolidate this with similar code in GenerateClass. - + // Collect declared and synthesized ivars in a small vector. llvm::SmallVector OIvars; CGM.getContext().ShallowCollectObjCIvars(OID, OIvars); - + for (unsigned i = 0, e = OIvars.size(); i != e; ++i) { ObjCIvarDecl *IVD = OIvars[i]; // Ignore unnamed bit-fields. if (!IVD->getDeclName()) continue; - Ivar[0] = EmitIvarOffsetVar(ID->getClassInterface(), IVD, + Ivar[0] = EmitIvarOffsetVar(ID->getClassInterface(), IVD, ComputeIvarBaseOffset(CGM, ID, IVD)); Ivar[1] = GetMethodVarName(IVD->getIdentifier()); Ivar[2] = GetMethodVarType(IVD); @@ -4677,7 +4715,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( CGM.getTypes().ConvertTypeForMem(IVD->getType()); unsigned Size = CGM.getTargetData().getTypeAllocSize(FieldTy); unsigned Align = CGM.getContext().getPreferredTypeAlign( - IVD->getType().getTypePtr()) >> 3; + IVD->getType().getTypePtr()) >> 3; Align = llvm::Log2_32(Align); Ivar[3] = llvm::ConstantInt::get(ObjCTypes.IntTy, Align); // NOTE. Size of a bitfield does not match gcc's, because of the @@ -4698,41 +4736,37 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.IvarnfABITy, Ivars.size()); Values[2] = llvm::ConstantArray::get(AT, Ivars); - llvm::Constant *Init = llvm::ConstantStruct::get(Values); + llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false); const char *Prefix = "\01l_OBJC_$_INSTANCE_VARIABLES_"; llvm::GlobalVariable *GV = - new llvm::GlobalVariable(Init->getType(), false, + new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, llvm::GlobalValue::InternalLinkage, Init, - Prefix + OID->getNameAsString(), - &CGM.getModule()); + Prefix + OID->getNameAsString()); GV->setAlignment( CGM.getTargetData().getPrefTypeAlignment(Init->getType())); GV->setSection("__DATA, __objc_const"); - - UsedGlobals.push_back(GV); - return llvm::ConstantExpr::getBitCast(GV, - ObjCTypes.IvarListnfABIPtrTy); + + CGM.AddUsedGlobal(GV); + return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListnfABIPtrTy); } llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocolRef( - const ObjCProtocolDecl *PD) { + const ObjCProtocolDecl *PD) { llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()]; - + if (!Entry) { // We use the initializer as a marker of whether this is a forward // reference or not. At module finalization we add the empty // contents for protocols which were referenced but never defined. - Entry = - new llvm::GlobalVariable(ObjCTypes.ProtocolnfABITy, false, - llvm::GlobalValue::ExternalLinkage, - 0, - "\01l_OBJC_PROTOCOL_$_" + PD->getNameAsString(), - &CGM.getModule()); + Entry = + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy, false, + llvm::GlobalValue::ExternalLinkage, + 0, + "\01l_OBJC_PROTOCOL_$_" + PD->getNameAsString()); Entry->setSection("__DATA,__datacoal_nt,coalesced"); - UsedGlobals.push_back(Entry); } - + return Entry; } @@ -4754,19 +4788,19 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocolRef( /// llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( - const ObjCProtocolDecl *PD) { + const ObjCProtocolDecl *PD) { llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()]; - + // Early exit if a defining object has already been generated. if (Entry && Entry->hasInitializer()) return Entry; const char *ProtocolName = PD->getNameAsCString(); - + // Construct method lists. std::vector InstanceMethods, ClassMethods; std::vector OptInstanceMethods, OptClassMethods; - for (ObjCProtocolDecl::instmeth_iterator + for (ObjCProtocolDecl::instmeth_iterator i = PD->instmeth_begin(), e = PD->instmeth_end(); i != e; ++i) { ObjCMethodDecl *MD = *i; llvm::Constant *C = GetMethodDescriptionConstant(MD); @@ -4774,10 +4808,10 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( OptInstanceMethods.push_back(C); } else { InstanceMethods.push_back(C); - } + } } - - for (ObjCProtocolDecl::classmeth_iterator + + for (ObjCProtocolDecl::classmeth_iterator i = PD->classmeth_begin(), e = PD->classmeth_end(); i != e; ++i) { ObjCMethodDecl *MD = *i; llvm::Constant *C = GetMethodDescriptionConstant(MD); @@ -4785,23 +4819,23 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( OptClassMethods.push_back(C); } else { ClassMethods.push_back(C); - } + } } - + std::vector Values(10); // isa is NULL Values[0] = llvm::Constant::getNullValue(ObjCTypes.ObjectPtrTy); Values[1] = GetClassName(PD->getIdentifier()); Values[2] = EmitProtocolList( - "\01l_OBJC_$_PROTOCOL_REFS_" + PD->getNameAsString(), - PD->protocol_begin(), - PD->protocol_end()); - + "\01l_OBJC_$_PROTOCOL_REFS_" + PD->getNameAsString(), + PD->protocol_begin(), + PD->protocol_end()); + Values[3] = EmitMethodList("\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_" + PD->getNameAsString(), "__DATA, __objc_const", InstanceMethods); - Values[4] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_" + Values[4] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_" + PD->getNameAsString(), "__DATA, __objc_const", ClassMethods); @@ -4809,50 +4843,50 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( + PD->getNameAsString(), "__DATA, __objc_const", OptInstanceMethods); - Values[6] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_OPT_" + Values[6] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_OPT_" + PD->getNameAsString(), "__DATA, __objc_const", OptClassMethods); Values[7] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + PD->getNameAsString(), 0, PD, ObjCTypes); - uint32_t Size = + uint32_t Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolnfABITy); Values[8] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); Values[9] = llvm::Constant::getNullValue(ObjCTypes.IntTy); llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolnfABITy, Values); - + if (Entry) { // Already created, fix the linkage and update the initializer. Entry->setLinkage(llvm::GlobalValue::WeakAnyLinkage); Entry->setInitializer(Init); } else { - Entry = - new llvm::GlobalVariable(ObjCTypes.ProtocolnfABITy, false, - llvm::GlobalValue::WeakAnyLinkage, - Init, - std::string("\01l_OBJC_PROTOCOL_$_")+ProtocolName, - &CGM.getModule()); + Entry = + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy, false, + llvm::GlobalValue::WeakAnyLinkage, + Init, + std::string("\01l_OBJC_PROTOCOL_$_")+ProtocolName); Entry->setAlignment( CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABITy)); Entry->setSection("__DATA,__datacoal_nt,coalesced"); } Entry->setVisibility(llvm::GlobalValue::HiddenVisibility); - + CGM.AddUsedGlobal(Entry); + // Use this protocol meta-data to build protocol list table in section // __DATA, __objc_protolist llvm::GlobalVariable *PTGV = new llvm::GlobalVariable( - ObjCTypes.ProtocolnfABIPtrTy, false, - llvm::GlobalValue::WeakAnyLinkage, - Entry, - std::string("\01l_OBJC_LABEL_PROTOCOL_$_") - +ProtocolName, - &CGM.getModule()); + CGM.getModule(), + ObjCTypes.ProtocolnfABIPtrTy, false, + llvm::GlobalValue::WeakAnyLinkage, + Entry, + std::string("\01l_OBJC_LABEL_PROTOCOL_$_") + +ProtocolName); PTGV->setAlignment( CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABIPtrTy)); PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip"); PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility); - UsedGlobals.push_back(PTGV); + CGM.AddUsedGlobal(PTGV); return Entry; } @@ -4866,45 +4900,46 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( /// llvm::Constant * CGObjCNonFragileABIMac::EmitProtocolList(const std::string &Name, - ObjCProtocolDecl::protocol_iterator begin, - ObjCProtocolDecl::protocol_iterator end) { + ObjCProtocolDecl::protocol_iterator begin, + ObjCProtocolDecl::protocol_iterator end) { std::vector ProtocolRefs; - + // Just return null for empty protocol lists - if (begin == end) + if (begin == end) return llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy); - + // FIXME: We shouldn't need to do this lookup here, should we? llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true); if (GV) - return llvm::ConstantExpr::getBitCast(GV, + return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListnfABIPtrTy); - + for (; begin != end; ++begin) ProtocolRefs.push_back(GetProtocolRef(*begin)); // Implemented??? // This list is null terminated. ProtocolRefs.push_back(llvm::Constant::getNullValue( - ObjCTypes.ProtocolnfABIPtrTy)); - + ObjCTypes.ProtocolnfABIPtrTy)); + std::vector Values(2); - Values[0] = llvm::ConstantInt::get(ObjCTypes.LongTy, ProtocolRefs.size() - 1); - Values[1] = - llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.ProtocolnfABIPtrTy, - ProtocolRefs.size()), - ProtocolRefs); - - llvm::Constant *Init = llvm::ConstantStruct::get(Values); - GV = new llvm::GlobalVariable(Init->getType(), false, + Values[0] = + llvm::ConstantInt::get(ObjCTypes.LongTy, ProtocolRefs.size() - 1); + Values[1] = + llvm::ConstantArray::get( + llvm::ArrayType::get(ObjCTypes.ProtocolnfABIPtrTy, + ProtocolRefs.size()), + ProtocolRefs); + + llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false); + GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, llvm::GlobalValue::InternalLinkage, Init, - Name, - &CGM.getModule()); + Name); GV->setSection("__DATA, __objc_const"); GV->setAlignment( CGM.getTargetData().getPrefTypeAlignment(Init->getType())); - UsedGlobals.push_back(GV); - return llvm::ConstantExpr::getBitCast(GV, + CGM.AddUsedGlobal(GV); + return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListnfABIPtrTy); } @@ -4918,8 +4953,9 @@ CGObjCNonFragileABIMac::EmitProtocolList(const std::string &Name, llvm::Constant * CGObjCNonFragileABIMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) { std::vector Desc(3); - Desc[0] = llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()), - ObjCTypes.SelectorPtrTy); + Desc[0] = + llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()), + ObjCTypes.SelectorPtrTy); Desc[1] = GetMethodVarType(MD); // Protocol methods have no implementation. So, this entry is always NULL. Desc[2] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); @@ -4931,46 +4967,46 @@ CGObjCNonFragileABIMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) { /// @code /// (type *)((char *)base + _OBJC_IVAR_$_.ivar; /// @encode -/// +/// LValue CGObjCNonFragileABIMac::EmitObjCValueForIvar( - CodeGen::CodeGenFunction &CGF, - QualType ObjectTy, - llvm::Value *BaseValue, - const ObjCIvarDecl *Ivar, - unsigned CVRQualifiers) { - const ObjCInterfaceDecl *ID = ObjectTy->getAsObjCInterfaceType()->getDecl(); + CodeGen::CodeGenFunction &CGF, + QualType ObjectTy, + llvm::Value *BaseValue, + const ObjCIvarDecl *Ivar, + unsigned CVRQualifiers) { + const ObjCInterfaceDecl *ID = ObjectTy->getAs()->getDecl(); return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers, EmitIvarOffset(CGF, ID, Ivar)); } llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset( - CodeGen::CodeGenFunction &CGF, - const ObjCInterfaceDecl *Interface, - const ObjCIvarDecl *Ivar) { - return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar), + CodeGen::CodeGenFunction &CGF, + const ObjCInterfaceDecl *Interface, + const ObjCIvarDecl *Ivar) { + return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar), false, "ivar"); } CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( - CodeGen::CodeGenFunction &CGF, - QualType ResultType, - Selector Sel, - llvm::Value *Receiver, - QualType Arg0Ty, - bool IsSuper, - const CallArgList &CallArgs) { + CodeGen::CodeGenFunction &CGF, + QualType ResultType, + Selector Sel, + llvm::Value *Receiver, + QualType Arg0Ty, + bool IsSuper, + const CallArgList &CallArgs) { // FIXME. Even though IsSuper is passes. This function doese not handle calls // to 'super' receivers. CodeGenTypes &Types = CGM.getTypes(); llvm::Value *Arg0 = Receiver; if (!IsSuper) Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp"); - + // Find the message function name. // 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()); + const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, + llvm::SmallVector()); llvm::Constant *Fn = 0; std::string Name("\01l_"); if (CGM.ReturnTypeUsesSret(FnInfo)) { @@ -4981,53 +5017,44 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( // FIXME. Is there a better way of getting these names. // They are available in RuntimeFunctions vector pair. Name += "objc_msgSendId_stret_fixup"; - } - else + } else #endif - if (IsSuper) { + if (IsSuper) { Fn = ObjCTypes.getMessageSendSuper2StretFixupFn(); Name += "objc_msgSendSuper2_stret_fixup"; - } - else - { - Fn = ObjCTypes.getMessageSendStretFixupFn(); - Name += "objc_msgSend_stret_fixup"; - } - } - else if (!IsSuper && ResultType->isFloatingType()) { + } else { + Fn = ObjCTypes.getMessageSendStretFixupFn(); + Name += "objc_msgSend_stret_fixup"; + } + } else if (!IsSuper && ResultType->isFloatingType()) { if (ResultType->isSpecificBuiltinType(BuiltinType::LongDouble)) { Fn = ObjCTypes.getMessageSendFpretFixupFn(); Name += "objc_msgSend_fpret_fixup"; - } - else { + } else { Fn = ObjCTypes.getMessageSendFixupFn(); Name += "objc_msgSend_fixup"; } - } - else { + } else { #if 0 // unlike what is documented. gcc never generates this API!! if (Receiver->getType() == ObjCTypes.ObjectPtrTy) { Fn = ObjCTypes.getMessageSendIdFixupFn(); Name += "objc_msgSendId_fixup"; - } - else + } else #endif - if (IsSuper) { + if (IsSuper) { Fn = ObjCTypes.getMessageSendSuper2FixupFn(); Name += "objc_msgSendSuper2_fixup"; - } - else - { - Fn = ObjCTypes.getMessageSendFixupFn(); - Name += "objc_msgSend_fixup"; - } + } else { + Fn = ObjCTypes.getMessageSendFixupFn(); + Name += "objc_msgSend_fixup"; + } } assert(Fn && "CGObjCNonFragileABIMac::EmitMessageSend"); Name += '_'; std::string SelName(Sel.getAsString()); // Replace all ':' in selector name with '_' ouch! - for(unsigned i = 0; i < SelName.size(); i++) + for (unsigned i = 0; i < SelName.size(); i++) if (SelName[i] == ':') SelName[i] = '_'; Name += SelName; @@ -5037,21 +5064,20 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( std::vector Values(2); Values[0] = Fn; Values[1] = GetMethodVarName(Sel); - llvm::Constant *Init = llvm::ConstantStruct::get(Values); - GV = new llvm::GlobalVariable(Init->getType(), false, + llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false); + GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, llvm::GlobalValue::WeakAnyLinkage, Init, - Name, - &CGM.getModule()); + Name); GV->setVisibility(llvm::GlobalValue::HiddenVisibility); GV->setAlignment(16); GV->setSection("__DATA, __objc_msgrefs, coalesced"); } llvm::Value *Arg1 = CGF.Builder.CreateBitCast(GV, ObjCTypes.MessageRefPtrTy); - + CallArgList ActualArgs; ActualArgs.push_back(std::make_pair(RValue::get(Arg0), Arg0Ty)); - ActualArgs.push_back(std::make_pair(RValue::get(Arg1), + 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); @@ -5064,21 +5090,21 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( } /// Generate code for a message send expression in the nonfragile abi. -CodeGen::RValue CGObjCNonFragileABIMac::GenerateMessageSend( - CodeGen::CodeGenFunction &CGF, - QualType ResultType, - Selector Sel, - llvm::Value *Receiver, - bool IsClassMessage, - const CallArgList &CallArgs, - const ObjCMethodDecl *Method) { +CodeGen::RValue +CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, + QualType ResultType, + Selector Sel, + llvm::Value *Receiver, + bool IsClassMessage, + const CallArgList &CallArgs, + const ObjCMethodDecl *Method) { return LegacyDispatchedSelector(Sel) - ? EmitLegacyMessageSend(CGF, ResultType, EmitSelector(CGF.Builder, Sel), - Receiver, CGF.getContext().getObjCIdType(), - false, CallArgs, ObjCTypes) - : EmitMessageSend(CGF, ResultType, Sel, - Receiver, CGF.getContext().getObjCIdType(), - false, CallArgs); + ? EmitLegacyMessageSend(CGF, ResultType, EmitSelector(CGF.Builder, Sel), + Receiver, CGF.getContext().getObjCIdType(), + false, CallArgs, Method, ObjCTypes) + : EmitMessageSend(CGF, ResultType, Sel, + Receiver, CGF.getContext().getObjCIdType(), + false, CallArgs); } llvm::GlobalVariable * @@ -5086,85 +5112,82 @@ CGObjCNonFragileABIMac::GetClassGlobal(const std::string &Name) { llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); if (!GV) { - GV = new llvm::GlobalVariable(ObjCTypes.ClassnfABITy, false, - llvm::GlobalValue::ExternalLinkage, - 0, Name, &CGM.getModule()); + GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABITy, + false, llvm::GlobalValue::ExternalLinkage, + 0, Name); } return GV; } -llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder, - const ObjCInterfaceDecl *ID) { +llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder, + const ObjCInterfaceDecl *ID) { llvm::GlobalVariable *&Entry = ClassReferences[ID->getIdentifier()]; - + if (!Entry) { std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString()); llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName); - Entry = - new llvm::GlobalVariable(ObjCTypes.ClassnfABIPtrTy, false, - llvm::GlobalValue::InternalLinkage, - ClassGV, - "\01L_OBJC_CLASSLIST_REFERENCES_$_", - &CGM.getModule()); + Entry = + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy, + false, llvm::GlobalValue::InternalLinkage, + ClassGV, + "\01L_OBJC_CLASSLIST_REFERENCES_$_"); Entry->setAlignment( - CGM.getTargetData().getPrefTypeAlignment( - ObjCTypes.ClassnfABIPtrTy)); + CGM.getTargetData().getPrefTypeAlignment( + ObjCTypes.ClassnfABIPtrTy)); Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip"); - UsedGlobals.push_back(Entry); + CGM.AddUsedGlobal(Entry); } - + return Builder.CreateLoad(Entry, false, "tmp"); } llvm::Value * -CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder, +CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder, const ObjCInterfaceDecl *ID) { llvm::GlobalVariable *&Entry = SuperClassReferences[ID->getIdentifier()]; - + if (!Entry) { std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString()); llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName); - Entry = - new llvm::GlobalVariable(ObjCTypes.ClassnfABIPtrTy, false, - llvm::GlobalValue::InternalLinkage, - ClassGV, - "\01L_OBJC_CLASSLIST_SUP_REFS_$_", - &CGM.getModule()); + Entry = + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy, + false, llvm::GlobalValue::InternalLinkage, + ClassGV, + "\01L_OBJC_CLASSLIST_SUP_REFS_$_"); Entry->setAlignment( - CGM.getTargetData().getPrefTypeAlignment( - ObjCTypes.ClassnfABIPtrTy)); + CGM.getTargetData().getPrefTypeAlignment( + ObjCTypes.ClassnfABIPtrTy)); Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip"); - UsedGlobals.push_back(Entry); + CGM.AddUsedGlobal(Entry); } - + return Builder.CreateLoad(Entry, false, "tmp"); } /// EmitMetaClassRef - Return a Value * of the address of _class_t /// meta-data /// -llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder, - const ObjCInterfaceDecl *ID) { +llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder, + const ObjCInterfaceDecl *ID) { llvm::GlobalVariable * &Entry = MetaClassReferences[ID->getIdentifier()]; if (Entry) return Builder.CreateLoad(Entry, false, "tmp"); - + std::string MetaClassName(getMetaclassSymbolPrefix() + ID->getNameAsString()); llvm::GlobalVariable *MetaClassGV = GetClassGlobal(MetaClassName); - Entry = - new llvm::GlobalVariable(ObjCTypes.ClassnfABIPtrTy, false, + Entry = + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy, false, llvm::GlobalValue::InternalLinkage, - MetaClassGV, - "\01L_OBJC_CLASSLIST_SUP_REFS_$_", - &CGM.getModule()); + MetaClassGV, + "\01L_OBJC_CLASSLIST_SUP_REFS_$_"); Entry->setAlignment( - CGM.getTargetData().getPrefTypeAlignment( - ObjCTypes.ClassnfABIPtrTy)); - + CGM.getTargetData().getPrefTypeAlignment( + ObjCTypes.ClassnfABIPtrTy)); + Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip"); - UsedGlobals.push_back(Entry); - + CGM.AddUsedGlobal(Entry); + return Builder.CreateLoad(Entry, false, "tmp"); } @@ -5180,24 +5203,25 @@ llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder, /// which class's method should be called. CodeGen::RValue CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, - QualType ResultType, - Selector Sel, - const ObjCInterfaceDecl *Class, - bool isCategoryImpl, - llvm::Value *Receiver, - bool IsClassMessage, - const CodeGen::CallArgList &CallArgs) { + QualType ResultType, + Selector Sel, + const ObjCInterfaceDecl *Class, + bool isCategoryImpl, + llvm::Value *Receiver, + bool IsClassMessage, + const CodeGen::CallArgList &CallArgs, + const ObjCMethodDecl *Method) { // ... // Create and init a super structure; this is a (receiver, class) // pair we will pass to objc_msgSendSuper. llvm::Value *ObjCSuper = CGF.Builder.CreateAlloca(ObjCTypes.SuperTy, 0, "objc_super"); - + llvm::Value *ReceiverAsObject = CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy); CGF.Builder.CreateStore(ReceiverAsObject, CGF.Builder.CreateStructGEP(ObjCSuper, 0)); - + // If this is a class message the metaclass is passed as the target. llvm::Value *Target; if (IsClassMessage) { @@ -5207,13 +5231,11 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, Target = EmitClassRef(CGF.Builder, Class); Target = CGF.Builder.CreateStructGEP(Target, 0); Target = CGF.Builder.CreateLoad(Target); - } - else + } else Target = EmitMetaClassRef(CGF.Builder, Class); - } - else + } else Target = EmitSuperClassRef(CGF.Builder, Class); - + // FIXME: We shouldn't need to do this cast, rectify the ASTContext and // ObjCTypes types. const llvm::Type *ClassTy = @@ -5221,42 +5243,41 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, Target = CGF.Builder.CreateBitCast(Target, ClassTy); CGF.Builder.CreateStore(Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1)); - + return (LegacyDispatchedSelector(Sel)) - ? EmitLegacyMessageSend(CGF, ResultType,EmitSelector(CGF.Builder, Sel), - ObjCSuper, ObjCTypes.SuperPtrCTy, - true, CallArgs, - ObjCTypes) - : EmitMessageSend(CGF, ResultType, Sel, - ObjCSuper, ObjCTypes.SuperPtrCTy, - true, CallArgs); + ? EmitLegacyMessageSend(CGF, ResultType,EmitSelector(CGF.Builder, Sel), + ObjCSuper, ObjCTypes.SuperPtrCTy, + true, CallArgs, Method, ObjCTypes) + : EmitMessageSend(CGF, ResultType, Sel, + ObjCSuper, ObjCTypes.SuperPtrCTy, + true, CallArgs); } -llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder, +llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder, Selector Sel) { llvm::GlobalVariable *&Entry = SelectorReferences[Sel]; - + if (!Entry) { - llvm::Constant *Casted = - llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel), - ObjCTypes.SelectorPtrTy); - Entry = - new llvm::GlobalVariable(ObjCTypes.SelectorPtrTy, false, - llvm::GlobalValue::InternalLinkage, - Casted, "\01L_OBJC_SELECTOR_REFERENCES_", - &CGM.getModule()); + llvm::Constant *Casted = + llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel), + ObjCTypes.SelectorPtrTy); + Entry = + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.SelectorPtrTy, false, + llvm::GlobalValue::InternalLinkage, + Casted, "\01L_OBJC_SELECTOR_REFERENCES_"); Entry->setSection("__DATA, __objc_selrefs, literal_pointers, no_dead_strip"); - UsedGlobals.push_back(Entry); + CGM.AddUsedGlobal(Entry); } - + return Builder.CreateLoad(Entry, false, "tmp"); } /// EmitObjCIvarAssign - Code gen for assigning to a __strong object. -/// objc_assign_ivar (id src, id *dst) +/// objc_assign_ivar (id src, id *dst, ptrdiff_t) /// void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dst) -{ + llvm::Value *src, + llvm::Value *dst, + llvm::Value *ivarOffset) { const llvm::Type * SrcTy = src->getType(); if (!isa(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); @@ -5267,8 +5288,8 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy); - CGF.Builder.CreateCall2(ObjCTypes.getGcAssignIvarFn(), - src, dst, "assignivar"); + CGF.Builder.CreateCall3(ObjCTypes.getGcAssignIvarFn(), + src, dst, ivarOffset); return; } @@ -5276,15 +5297,14 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, /// objc_assign_strongCast (id src, id *dst) /// void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign( - CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dst) -{ + CodeGen::CodeGenFunction &CGF, + llvm::Value *src, llvm::Value *dst) { const llvm::Type * SrcTy = src->getType(); if (!isa(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy) - : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy)); + : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy)); src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); @@ -5294,16 +5314,31 @@ void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign( return; } +void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable( + CodeGen::CodeGenFunction &CGF, + llvm::Value *DestPtr, + llvm::Value *SrcPtr, + QualType Ty) { + // Get size info for this aggregate. + std::pair TypeInfo = CGM.getContext().getTypeInfo(Ty); + unsigned long size = TypeInfo.first/8; + SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy); + DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy); + llvm::Value *N = llvm::ConstantInt::get(ObjCTypes.LongTy, size); + CGF.Builder.CreateCall3(ObjCTypes.GcMemmoveCollectableFn(), + DestPtr, SrcPtr, N); + return; +} + /// EmitObjCWeakRead - Code gen for loading value of a __weak /// object: objc_read_weak (id *src) /// llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead( - CodeGen::CodeGenFunction &CGF, - llvm::Value *AddrWeakObj) -{ + CodeGen::CodeGenFunction &CGF, + llvm::Value *AddrWeakObj) { const llvm::Type* DestTy = - cast(AddrWeakObj->getType())->getElementType(); - AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy); + cast(AddrWeakObj->getType())->getElementType(); + AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy); llvm::Value *read_weak = CGF.Builder.CreateCall(ObjCTypes.getGcReadWeakFn(), AddrWeakObj, "weakread"); read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy); @@ -5314,8 +5349,7 @@ llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead( /// objc_assign_weak (id src, id *dst) /// void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dst) -{ + llvm::Value *src, llvm::Value *dst) { const llvm::Type * SrcTy = src->getType(); if (!isa(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); @@ -5335,8 +5369,7 @@ void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, /// objc_assign_global (id src, id *dst) /// void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dst) -{ + llvm::Value *src, llvm::Value *dst) { const llvm::Type * SrcTy = src->getType(); if (!isa(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); @@ -5352,7 +5385,7 @@ void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, return; } -void +void CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, const Stmt &S) { bool isTry = isa(S); @@ -5369,7 +5402,7 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // @synchronized are illegal & this will dominate uses. llvm::Value *SyncArg = 0; if (!isTry) { - SyncArg = + SyncArg = CGF.EmitScalarExpr(cast(S).getSynchExpr()); SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy); CGF.Builder.CreateCall(ObjCTypes.getSyncEnterFn(), SyncArg); @@ -5382,20 +5415,20 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.setInvokeDest(TryHandler); CGF.EmitBlock(TryBlock); - CGF.EmitStmt(isTry ? cast(S).getTryBody() - : cast(S).getSynchBody()); + CGF.EmitStmt(isTry ? cast(S).getTryBody() + : cast(S).getSynchBody()); CGF.EmitBranchThroughCleanup(FinallyEnd); - + // Emit the exception handler. CGF.EmitBlock(TryHandler); - llvm::Value *llvm_eh_exception = + llvm::Value *llvm_eh_exception = CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception); - llvm::Value *llvm_eh_selector_i64 = - CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector_i64); - llvm::Value *llvm_eh_typeid_for_i64 = - CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for_i64); + llvm::Value *llvm_eh_selector = + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector); + llvm::Value *llvm_eh_typeid_for = + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); llvm::Value *RethrowPtr = CGF.CreateTempAlloca(Exc->getType(), "_rethrow"); @@ -5422,40 +5455,42 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, break; } - if (CGF.getContext().isObjCIdType(CatchDecl->getType()) || + if (CatchDecl->getType()->isObjCIdType() || CatchDecl->getType()->isObjCQualifiedIdType()) { - llvm::Value *IDEHType = + llvm::Value *IDEHType = CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id"); if (!IDEHType) - IDEHType = - new llvm::GlobalVariable(ObjCTypes.EHTypeTy, false, + IDEHType = + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, + false, llvm::GlobalValue::ExternalLinkage, - 0, "OBJC_EHTYPE_id", &CGM.getModule()); + 0, "OBJC_EHTYPE_id"); SelectorArgs.push_back(IDEHType); - HasCatchAll = true; - break; - } - - // All other types should be Objective-C interface pointer types. - const PointerType *PT = CatchDecl->getType()->getAsPointerType(); - assert(PT && "Invalid @catch type."); - const ObjCInterfaceType *IT = - PT->getPointeeType()->getAsObjCInterfaceType(); - assert(IT && "Invalid @catch type."); - llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false); - SelectorArgs.push_back(EHType); + } else { + // All other types should be Objective-C interface pointer types. + const ObjCObjectPointerType *PT = + CatchDecl->getType()->getAs(); + assert(PT && "Invalid @catch type."); + const ObjCInterfaceType *IT = PT->getInterfaceType(); + assert(IT && "Invalid @catch type."); + llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false); + SelectorArgs.push_back(EHType); + } } } } // We use a cleanup unless there was already a catch all. if (!HasCatchAll) { - SelectorArgs.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, 0)); + // Even though this is a cleanup, treat it as a catch all to avoid the C++ + // personality behavior of terminating the process if only cleanups are + // found in the exception handling stack. + SelectorArgs.push_back(llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy)); Handlers.push_back(std::make_pair((const ParmVarDecl*) 0, (const Stmt*) 0)); } - - llvm::Value *Selector = - CGF.Builder.CreateCall(llvm_eh_selector_i64, + + llvm::Value *Selector = + CGF.Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(), SelectorArgs.end(), "selector"); for (unsigned i = 0, e = Handlers.size(); i != e; ++i) { @@ -5470,8 +5505,8 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, llvm::BasicBlock *Match = CGF.createBasicBlock("match"); Next = CGF.createBasicBlock("catch.next"); - llvm::Value *Id = - CGF.Builder.CreateCall(llvm_eh_typeid_for_i64, + llvm::Value *Id = + CGF.Builder.CreateCall(llvm_eh_typeid_for, CGF.Builder.CreateBitCast(SelectorArgs[i+2], ObjCTypes.Int8PtrTy)); CGF.Builder.CreateCondBr(CGF.Builder.CreateICmpEQ(Selector, Id), @@ -5479,25 +5514,25 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.EmitBlock(Match); } - + if (CatchBody) { llvm::BasicBlock *MatchEnd = CGF.createBasicBlock("match.end"); llvm::BasicBlock *MatchHandler = CGF.createBasicBlock("match.handler"); // Cleanups must call objc_end_catch. - // + // // FIXME: It seems incorrect for objc_begin_catch to be inside this // context, but this matches gcc. CGF.PushCleanupBlock(MatchEnd); CGF.setInvokeDest(MatchHandler); - - llvm::Value *ExcObject = + + llvm::Value *ExcObject = CGF.Builder.CreateCall(ObjCTypes.getObjCBeginCatchFn(), Exc); // Bind the catch parameter if it exists. if (CatchParam) { - ExcObject = - CGF.Builder.CreateBitCast(ExcObject, + ExcObject = + CGF.Builder.CreateBitCast(ExcObject, CGF.ConvertType(CatchParam->getType())); // CatchParam is a ParmVarDecl because of the grammar // construction used to handle this, but for codegen purposes @@ -5520,22 +5555,22 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, llvm::SmallVector Args; Args.push_back(Exc); Args.push_back(ObjCTypes.getEHPersonalityPtr()); - Args.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, + Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0)); - CGF.Builder.CreateCall(llvm_eh_selector_i64, Args.begin(), Args.end()); + CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); CGF.Builder.CreateStore(Exc, RethrowPtr); CGF.EmitBranchThroughCleanup(FinallyRethrow); CodeGenFunction::CleanupBlockInfo Info = CGF.PopCleanupBlock(); - + CGF.EmitBlock(MatchEnd); // Unfortunately, we also have to generate another EH frame here // in case this throws. - llvm::BasicBlock *MatchEndHandler = + llvm::BasicBlock *MatchEndHandler = CGF.createBasicBlock("match.end.handler"); llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); - CGF.Builder.CreateInvoke(ObjCTypes.getObjCEndCatchFn(), + CGF.Builder.CreateInvoke(ObjCTypes.getObjCEndCatchFn(), Cont, MatchEndHandler, Args.begin(), Args.begin()); @@ -5552,9 +5587,9 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, Args.clear(); Args.push_back(Exc); Args.push_back(ObjCTypes.getEHPersonalityPtr()); - Args.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, + Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0)); - CGF.Builder.CreateCall(llvm_eh_selector_i64, Args.begin(), Args.end()); + CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); CGF.Builder.CreateStore(Exc, RethrowPtr); CGF.EmitBranchThroughCleanup(FinallyRethrow); @@ -5576,7 +5611,7 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.EmitBlock(FinallyBlock); if (isTry) { - if (const ObjCAtFinallyStmt* FinallyStmt = + if (const ObjCAtFinallyStmt* FinallyStmt = cast(S).getFinallyStmt()) CGF.EmitStmt(FinallyStmt->getFinallyBody()); } else { @@ -5594,26 +5629,26 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.EmitBranch(FinallyEnd); CGF.EmitBlock(FinallyRethrow); - CGF.Builder.CreateCall(ObjCTypes.getUnwindResumeOrRethrowFn(), + CGF.Builder.CreateCall(ObjCTypes.getUnwindResumeOrRethrowFn(), CGF.Builder.CreateLoad(RethrowPtr)); CGF.Builder.CreateUnreachable(); - + CGF.EmitBlock(FinallyEnd); } /// EmitThrowStmt - Generate code for a throw statement. void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S) { - llvm::Value *Exception; + llvm::Value *Exception; if (const Expr *ThrowExpr = S.getThrowExpr()) { Exception = CGF.EmitScalarExpr(ThrowExpr); } else { - assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) && + assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) && "Unexpected rethrow outside @catch block."); Exception = CGF.ObjCEHValueStack.back(); } - llvm::Value *ExceptionAsObject = + llvm::Value *ExceptionAsObject = CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy, "tmp"); llvm::BasicBlock *InvokeDest = CGF.getInvokeDest(); if (InvokeDest) { @@ -5623,7 +5658,7 @@ void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, &ExceptionAsObject, &ExceptionAsObject + 1); CGF.EmitBlock(Cont); } else - CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), ExceptionAsObject); + CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), ExceptionAsObject); CGF.Builder.CreateUnreachable(); // Clear the insertion point to indicate we are in unreachable code. @@ -5631,7 +5666,7 @@ void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, } llvm::Value * -CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, +CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, bool ForDefinition) { llvm::GlobalVariable * &Entry = EHTypeReferences[ID->getIdentifier()]; @@ -5644,44 +5679,44 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, // If this type (or a super class) has the __objc_exception__ // attribute, emit an external reference. if (hasObjCExceptionAttribute(CGM.getContext(), ID)) - return Entry = - new llvm::GlobalVariable(ObjCTypes.EHTypeTy, false, + return Entry = + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, false, llvm::GlobalValue::ExternalLinkage, - 0, - (std::string("OBJC_EHTYPE_$_") + - ID->getIdentifier()->getName()), - &CGM.getModule()); + 0, + (std::string("OBJC_EHTYPE_$_") + + ID->getIdentifier()->getName())); } - + // Otherwise we need to either make a new entry or fill in the // initializer. assert((!Entry || !Entry->hasInitializer()) && "Duplicate EHType definition"); std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString()); std::string VTableName = "objc_ehtype_vtable"; - llvm::GlobalVariable *VTableGV = + llvm::GlobalVariable *VTableGV = CGM.getModule().getGlobalVariable(VTableName); if (!VTableGV) - VTableGV = new llvm::GlobalVariable(ObjCTypes.Int8PtrTy, false, + VTableGV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.Int8PtrTy, + false, llvm::GlobalValue::ExternalLinkage, - 0, VTableName, &CGM.getModule()); + 0, VTableName); - llvm::Value *VTableIdx = llvm::ConstantInt::get(llvm::Type::Int32Ty, 2); + llvm::Value *VTableIdx = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 2); std::vector Values(3); Values[0] = llvm::ConstantExpr::getGetElementPtr(VTableGV, &VTableIdx, 1); Values[1] = GetClassName(ID->getIdentifier()); Values[2] = GetClassGlobal(ClassName); - llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.EHTypeTy, Values); + llvm::Constant *Init = + llvm::ConstantStruct::get(ObjCTypes.EHTypeTy, Values); if (Entry) { Entry->setInitializer(Init); } else { - Entry = new llvm::GlobalVariable(ObjCTypes.EHTypeTy, false, + Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, false, llvm::GlobalValue::WeakAnyLinkage, - Init, - (std::string("OBJC_EHTYPE_$_") + - ID->getIdentifier()->getName()), - &CGM.getModule()); + Init, + (std::string("OBJC_EHTYPE_$_") + + ID->getIdentifier()->getName())); } if (CGM.getLangOptions().getVisibilityMode() == LangOptions::Hidden) @@ -5697,7 +5732,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, return Entry; } - + /* *** */ CodeGen::CGObjCRuntime * diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index 0f9cf0606d36..6b4556239723 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -86,7 +86,7 @@ protected: llvm::Value *BaseValue, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers, - llvm::Value *Offset); + llvm::Value *Offset); public: virtual ~CGObjCRuntime(); @@ -95,16 +95,13 @@ public: /// this compilation unit with the runtime library. virtual llvm::Function *ModuleInitFunction() = 0; - /// Add metadata globals to the 'used' globals for final output. - virtual void MergeMetadataGlobals(std::vector &UsedArray) = 0; - /// Get a selector for the specified name and type values. The /// return value should have the LLVM type for pointer-to /// ASTContext::getObjCSelType(). virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel) = 0; - /// Get a typed selector. + /// Get a typed selector. virtual llvm::Value *GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl *Method) = 0; @@ -117,20 +114,26 @@ public: /// Generate a class stucture for this class. virtual void GenerateClass(const ObjCImplementationDecl *OID) = 0; - - /// Generate an Objective-C message send operation. - virtual CodeGen::RValue + + /// Generate an Objective-C message send operation. + /// + /// \param Method - The method being called, this may be null if synthesizing + /// a property setter or getter. + virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, llvm::Value *Receiver, bool IsClassMessage, const CallArgList &CallArgs, - const ObjCMethodDecl *Method=0) = 0; + const ObjCMethodDecl *Method = 0) = 0; /// Generate an Objective-C message send operation to the super /// class initiated in a method for Class and with the given Self /// object. + /// + /// \param Method - The method being called, this may be null if synthesizing + /// a property setter or getter. virtual CodeGen::RValue GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, QualType ResultType, @@ -139,41 +142,42 @@ public: bool isCategoryImpl, llvm::Value *Self, bool IsClassMessage, - const CallArgList &CallArgs) = 0; + const CallArgList &CallArgs, + const ObjCMethodDecl *Method = 0) = 0; /// Emit the code to return the named protocol as an object, as in a /// @protocol expression. virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder, const ObjCProtocolDecl *OPD) = 0; - /// Generate the named protocol. Protocols contain method metadata but no - /// implementations. + /// Generate the named protocol. Protocols contain method metadata but no + /// implementations. virtual void GenerateProtocol(const ObjCProtocolDecl *OPD) = 0; /// Generate a function preamble for a method with the specified - /// types. + /// types. // FIXME: Current this just generates the Function definition, but really this // should also be generating the loads of the parameters, as the runtime // should have full control over how parameters are passed. - virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, + virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD) = 0; /// Return the runtime function for getting properties. virtual llvm::Constant *GetPropertyGetFunction() = 0; - + /// Return the runtime function for setting properties. virtual llvm::Constant *GetPropertySetFunction() = 0; /// GetClass - Return a reference to the class for the given /// interface decl. - virtual llvm::Value *GetClass(CGBuilderTy &Builder, + virtual llvm::Value *GetClass(CGBuilderTy &Builder, const ObjCInterfaceDecl *OID) = 0; /// EnumerationMutationFunction - Return the function that's called by the /// compiler when a mutation is detected during foreach iteration. virtual llvm::Constant *EnumerationMutationFunction() = 0; - + virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, const Stmt &S) = 0; virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, @@ -185,10 +189,11 @@ public: virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest) = 0; virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dest) = 0; + llvm::Value *src, llvm::Value *dest, + llvm::Value *ivarOffset) = 0; virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest) = 0; - + virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, QualType ObjectTy, llvm::Value *BaseValue, @@ -197,9 +202,13 @@ public: virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF, const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar) = 0; + virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, + llvm::Value *DestPtr, + llvm::Value *SrcPtr, + QualType Ty) = 0; }; -/// Creates an instance of an Objective-C runtime class. +/// Creates an instance of an Objective-C runtime class. //TODO: This should include some way of selecting which runtime to target. CGObjCRuntime *CreateGNUObjCRuntime(CodeGenModule &CGM); CGObjCRuntime *CreateMacObjCRuntime(CodeGenModule &CGM); diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp new file mode 100644 index 000000000000..7baf69d87689 --- /dev/null +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -0,0 +1,386 @@ +//===--- CGRecordLayoutBuilder.cpp - Record builder helper ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a helper class used to build CGRecordLayout objects and LLVM types. +// +//===----------------------------------------------------------------------===// + +#include "CGRecordLayoutBuilder.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Expr.h" +#include "clang/AST/RecordLayout.h" +#include "CodeGenTypes.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Target/TargetData.h" + + +using namespace clang; +using namespace CodeGen; + +void CGRecordLayoutBuilder::Layout(const RecordDecl *D) { + Alignment = Types.getContext().getASTRecordLayout(D).getAlignment() / 8; + Packed = D->hasAttr(); + + if (D->isUnion()) { + LayoutUnion(D); + return; + } + + if (LayoutFields(D)) + return; + + // We weren't able to layout the struct. Try again with a packed struct + Packed = true; + AlignmentAsLLVMStruct = 1; + NextFieldOffsetInBytes = 0; + FieldTypes.clear(); + LLVMFields.clear(); + LLVMBitFields.clear(); + + LayoutFields(D); +} + +void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D, + uint64_t FieldOffset) { + uint64_t FieldSize = + D->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue(); + + if (FieldSize == 0) + return; + + uint64_t NextFieldOffset = NextFieldOffsetInBytes * 8; + unsigned NumBytesToAppend; + + if (FieldOffset < NextFieldOffset) { + assert(BitsAvailableInLastField && "Bitfield size mismatch!"); + assert(NextFieldOffsetInBytes && "Must have laid out at least one byte!"); + + // The bitfield begins in the previous bit-field. + NumBytesToAppend = + llvm::RoundUpToAlignment(FieldSize - BitsAvailableInLastField, 8) / 8; + } else { + assert(FieldOffset % 8 == 0 && "Field offset not aligned correctly"); + + // Append padding if necessary. + AppendBytes((FieldOffset - NextFieldOffset) / 8); + + NumBytesToAppend = + llvm::RoundUpToAlignment(FieldSize, 8) / 8; + + assert(NumBytesToAppend && "No bytes to append!"); + } + + const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType()); + uint64_t TypeSizeInBits = getTypeSizeInBytes(Ty) * 8; + + LLVMBitFields.push_back(LLVMBitFieldInfo(D, FieldOffset / TypeSizeInBits, + FieldOffset % TypeSizeInBits, + FieldSize)); + + AppendBytes(NumBytesToAppend); + + AlignmentAsLLVMStruct = std::max(AlignmentAsLLVMStruct, getTypeAlignment(Ty)); + + BitsAvailableInLastField = + NextFieldOffsetInBytes * 8 - (FieldOffset + FieldSize); +} + +bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D, + uint64_t FieldOffset) { + // If the field is packed, then we need a packed struct. + if (!Packed && D->hasAttr()) + return false; + + if (D->isBitField()) { + // We must use packed structs for unnamed bit fields since they + // don't affect the struct alignment. + if (!Packed && !D->getDeclName()) + return false; + + LayoutBitField(D, FieldOffset); + return true; + } + + assert(FieldOffset % 8 == 0 && "FieldOffset is not on a byte boundary!"); + uint64_t FieldOffsetInBytes = FieldOffset / 8; + + const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType()); + unsigned TypeAlignment = getTypeAlignment(Ty); + + // If the type alignment is larger then the struct alignment, we must use + // a packed struct. + if (TypeAlignment > Alignment) { + assert(!Packed && "Alignment is wrong even with packed struct!"); + return false; + } + + if (const RecordType *RT = D->getType()->getAs()) { + const RecordDecl *RD = cast(RT->getDecl()); + if (const PragmaPackAttr *PPA = RD->getAttr()) { + if (PPA->getAlignment() != TypeAlignment * 8 && !Packed) + return false; + } + } + + // Round up the field offset to the alignment of the field type. + uint64_t AlignedNextFieldOffsetInBytes = + llvm::RoundUpToAlignment(NextFieldOffsetInBytes, TypeAlignment); + + if (FieldOffsetInBytes < AlignedNextFieldOffsetInBytes) { + assert(!Packed && "Could not place field even with packed struct!"); + return false; + } + + if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) { + // Even with alignment, the field offset is not at the right place, + // insert padding. + uint64_t PaddingInBytes = FieldOffsetInBytes - NextFieldOffsetInBytes; + + AppendBytes(PaddingInBytes); + } + + // Now append the field. + LLVMFields.push_back(LLVMFieldInfo(D, FieldTypes.size())); + AppendField(FieldOffsetInBytes, Ty); + + return true; +} + +void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { + assert(D->isUnion() && "Can't call LayoutUnion on a non-union record!"); + + const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D); + + const llvm::Type *Ty = 0; + uint64_t Size = 0; + unsigned Align = 0; + + unsigned FieldNo = 0; + for (RecordDecl::field_iterator Field = D->field_begin(), + FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { + assert(Layout.getFieldOffset(FieldNo) == 0 && + "Union field offset did not start at the beginning of record!"); + + if (Field->isBitField()) { + uint64_t FieldSize = + Field->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue(); + + // Ignore zero sized bit fields. + if (FieldSize == 0) + continue; + + // Add the bit field info. + Types.addBitFieldInfo(*Field, 0, 0, FieldSize); + } else + Types.addFieldInfo(*Field, 0); + + const llvm::Type *FieldTy = + Types.ConvertTypeForMemRecursive(Field->getType()); + unsigned FieldAlign = Types.getTargetData().getABITypeAlignment(FieldTy); + uint64_t FieldSize = Types.getTargetData().getTypeAllocSize(FieldTy); + + if (FieldAlign < Align) + continue; + + if (FieldAlign > Align || FieldSize > Size) { + Ty = FieldTy; + Align = FieldAlign; + Size = FieldSize; + } + } + + // Now add our field. + if (Ty) { + AppendField(0, Ty); + + if (getTypeAlignment(Ty) > Layout.getAlignment() / 8) { + // We need a packed struct. + Packed = true; + Align = 1; + } + } + + // Append tail padding. + if (Layout.getSize() / 8 > Size) + AppendPadding(Layout.getSize() / 8, Align); +} + +bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { + assert(!D->isUnion() && "Can't call LayoutFields on a union!"); + assert(Alignment && "Did not set alignment!"); + + const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D); + + unsigned FieldNo = 0; + + for (RecordDecl::field_iterator Field = D->field_begin(), + FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { + if (!LayoutField(*Field, Layout.getFieldOffset(FieldNo))) { + assert(!Packed && + "Could not layout fields even with a packed LLVM struct!"); + return false; + } + } + + // Append tail padding if necessary. + AppendTailPadding(Layout.getSize()); + + return true; +} + +void CGRecordLayoutBuilder::AppendTailPadding(uint64_t RecordSize) { + assert(RecordSize % 8 == 0 && "Invalid record size!"); + + uint64_t RecordSizeInBytes = RecordSize / 8; + assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!"); + + unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes; + AppendBytes(NumPadBytes); +} + +void CGRecordLayoutBuilder::AppendField(uint64_t FieldOffsetInBytes, + const llvm::Type *FieldTy) { + AlignmentAsLLVMStruct = std::max(AlignmentAsLLVMStruct, + getTypeAlignment(FieldTy)); + + uint64_t FieldSizeInBytes = getTypeSizeInBytes(FieldTy); + + FieldTypes.push_back(FieldTy); + + NextFieldOffsetInBytes = FieldOffsetInBytes + FieldSizeInBytes; + BitsAvailableInLastField = 0; +} + +void +CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes, + const llvm::Type *FieldTy) { + AppendPadding(FieldOffsetInBytes, getTypeAlignment(FieldTy)); +} + +void CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes, + unsigned FieldAlignment) { + assert(NextFieldOffsetInBytes <= FieldOffsetInBytes && + "Incorrect field layout!"); + + // Round up the field offset to the alignment of the field type. + uint64_t AlignedNextFieldOffsetInBytes = + llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment); + + if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) { + // Even with alignment, the field offset is not at the right place, + // insert padding. + uint64_t PaddingInBytes = FieldOffsetInBytes - NextFieldOffsetInBytes; + + AppendBytes(PaddingInBytes); + } +} + +void CGRecordLayoutBuilder::AppendBytes(uint64_t NumBytes) { + if (NumBytes == 0) + return; + + const llvm::Type *Ty = llvm::Type::getInt8Ty(Types.getLLVMContext()); + if (NumBytes > 1) + Ty = llvm::ArrayType::get(Ty, NumBytes); + + // Append the padding field + AppendField(NextFieldOffsetInBytes, Ty); +} + +unsigned CGRecordLayoutBuilder::getTypeAlignment(const llvm::Type *Ty) const { + if (Packed) + return 1; + + return Types.getTargetData().getABITypeAlignment(Ty); +} + +uint64_t CGRecordLayoutBuilder::getTypeSizeInBytes(const llvm::Type *Ty) const { + return Types.getTargetData().getTypeAllocSize(Ty); +} + +void CGRecordLayoutBuilder::CheckForMemberPointer(const FieldDecl *FD) { + // This record already contains a member pointer. + if (ContainsMemberPointer) + 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; + } + +} + +static const CXXMethodDecl *GetKeyFunction(const RecordDecl *D) { + const CXXRecordDecl *RD = dyn_cast(D); + if (!RD || !RD->isDynamicClass()) + return 0; + + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + if (MD->isPure()) + continue; + + if (MD->getBody()) + continue; + + // We found it. + return MD; + } + + return 0; +} + +CGRecordLayout * +CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types, + const RecordDecl *D) { + CGRecordLayoutBuilder Builder(Types); + + Builder.Layout(D); + + const llvm::Type *Ty = llvm::StructType::get(Types.getLLVMContext(), + Builder.FieldTypes, + Builder.Packed); + assert(Types.getContext().getASTRecordLayout(D).getSize() / 8 == + Types.getTargetData().getTypeAllocSize(Ty) && + "Type size mismatch!"); + + // Add all the field numbers. + for (unsigned i = 0, e = Builder.LLVMFields.size(); i != e; ++i) { + const FieldDecl *FD = Builder.LLVMFields[i].first; + unsigned FieldNo = Builder.LLVMFields[i].second; + + Types.addFieldInfo(FD, FieldNo); + } + + // Add bitfield info. + for (unsigned i = 0, e = Builder.LLVMBitFields.size(); i != e; ++i) { + const LLVMBitFieldInfo &Info = Builder.LLVMBitFields[i]; + + Types.addBitFieldInfo(Info.FD, Info.FieldNo, Info.Start, Info.Size); + } + + const CXXMethodDecl *KeyFunction = GetKeyFunction(D); + + return new CGRecordLayout(Ty, Builder.ContainsMemberPointer, KeyFunction); +} diff --git a/lib/CodeGen/CGRecordLayoutBuilder.h b/lib/CodeGen/CGRecordLayoutBuilder.h new file mode 100644 index 000000000000..d1a13aa29711 --- /dev/null +++ b/lib/CodeGen/CGRecordLayoutBuilder.h @@ -0,0 +1,134 @@ +//===--- CGRecordLayoutBuilder.h - Record builder helper --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a helper class used to build CGRecordLayout objects and LLVM types. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_CGRECORDLAYOUTBUILDER_H +#define CLANG_CODEGEN_CGRECORDLAYOUTBUILDER_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataTypes.h" +#include + +namespace llvm { + class Type; +} + +namespace clang { + class FieldDecl; + class RecordDecl; + +namespace CodeGen { + class CGRecordLayout; + class CodeGenTypes; + +class CGRecordLayoutBuilder { + CodeGenTypes &Types; + + /// 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; + + /// Alignment - Contains the alignment of the RecordDecl. + unsigned Alignment; + + /// AlignmentAsLLVMStruct - Will contain the maximum alignment of all the + /// LLVM types. + unsigned AlignmentAsLLVMStruct; + + /// BitsAvailableInLastField - If a bit field spans only part of a LLVM field, + /// this will have the number of bits still available in the field. + char BitsAvailableInLastField; + + /// NextFieldOffsetInBytes - Holds the next field offset in bytes. + uint64_t NextFieldOffsetInBytes; + + /// FieldTypes - Holds the LLVM types that the struct is created from. + std::vector FieldTypes; + + /// LLVMFieldInfo - Holds a field and its corresponding LLVM field number. + typedef std::pair LLVMFieldInfo; + llvm::SmallVector LLVMFields; + + /// LLVMBitFieldInfo - Holds location and size information about a bit field. + struct LLVMBitFieldInfo { + LLVMBitFieldInfo(const FieldDecl *FD, unsigned FieldNo, unsigned Start, + unsigned Size) + : FD(FD), FieldNo(FieldNo), Start(Start), Size(Size) { } + + const FieldDecl *FD; + + unsigned FieldNo; + unsigned Start; + unsigned Size; + }; + llvm::SmallVector LLVMBitFields; + + CGRecordLayoutBuilder(CodeGenTypes &Types) + : Types(Types), Packed(false), ContainsMemberPointer(false) + , Alignment(0), AlignmentAsLLVMStruct(1) + , BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { } + + /// Layout - Will layout a RecordDecl. + void Layout(const RecordDecl *D); + + /// LayoutUnion - Will layout a union RecordDecl. + void LayoutUnion(const RecordDecl *D); + + /// LayoutField - try to layout all fields in the record decl. + /// Returns false if the operation failed because the struct is not packed. + bool LayoutFields(const RecordDecl *D); + + /// LayoutField - layout a single field. Returns false if the operation failed + /// because the current struct is not packed. + bool LayoutField(const FieldDecl *D, uint64_t FieldOffset); + + /// LayoutBitField - layout a single bit field. + void LayoutBitField(const FieldDecl *D, uint64_t FieldOffset); + + /// AppendField - Appends a field with the given offset and type. + void AppendField(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy); + + /// AppendPadding - Appends enough padding bytes so that the total struct + /// size matches the alignment of the passed in type. + void AppendPadding(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy); + + /// AppendPadding - Appends enough padding bytes so that the total + /// struct size is a multiple of the field alignment. + void AppendPadding(uint64_t FieldOffsetInBytes, unsigned FieldAlignment); + + /// AppendBytes - Append a given number of bytes to the record. + void AppendBytes(uint64_t NumBytes); + + /// AppendTailPadding - Append enough tail padding so that the type will have + /// the passed size. + void AppendTailPadding(uint64_t RecordSize); + + 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); + +public: + /// ComputeLayout - Return the right record layout for a given record decl. + static CGRecordLayout *ComputeLayout(CodeGenTypes &Types, + const RecordDecl *D); +}; + +} // end namespace CodeGen +} // end namespace clang + + +#endif diff --git a/lib/CodeGen/CGRtti.cpp b/lib/CodeGen/CGRtti.cpp new file mode 100644 index 000000000000..7bc774fce75b --- /dev/null +++ b/lib/CodeGen/CGRtti.cpp @@ -0,0 +1,47 @@ +//===--- CGCXXRtti.cpp - Emit LLVM Code for C++ RTTI descriptors ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with C++ code generation of RTTI descriptors. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenModule.h" +using namespace clang; +using namespace CodeGen; + +llvm::Constant *CodeGenModule::GenerateRtti(const CXXRecordDecl *RD) { + llvm::Type *Ptr8Ty; + Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); + llvm::Constant *Rtti = llvm::Constant::getNullValue(Ptr8Ty); + + if (!getContext().getLangOptions().Rtti) + return Rtti; + + llvm::SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + mangleCXXRtti(getMangleContext(), RD, Out); + + llvm::GlobalVariable::LinkageTypes linktype; + linktype = llvm::GlobalValue::WeakAnyLinkage; + std::vector info; + // assert(0 && "FIXME: implement rtti descriptor"); + // FIXME: descriptor + info.push_back(llvm::Constant::getNullValue(Ptr8Ty)); + // assert(0 && "FIXME: implement rtti ts"); + // FIXME: TS + info.push_back(llvm::Constant::getNullValue(Ptr8Ty)); + + llvm::Constant *C; + llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, info.size()); + C = llvm::ConstantArray::get(type, info); + Rtti = new llvm::GlobalVariable(getModule(), type, true, linktype, C, + Out.str()); + Rtti = llvm::ConstantExpr::getBitCast(Rtti, Ptr8Ty); + return Rtti; +} diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index b67996c67630..f58b57926787 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -43,13 +43,24 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { if (EmitSimpleStmt(S)) return; - // If we happen to be at an unreachable point just create a dummy - // basic block to hold the code. We could change parts of irgen to - // simply not generate this code, but this situation is rare and - // probably not worth the effort. - // FIXME: Verify previous performance/effort claim. - EnsureInsertPoint(); - + // Check if we are generating unreachable code. + if (!HaveInsertPoint()) { + // If so, and the statement doesn't contain a label, then we do not need to + // generate actual code. This is safe because (1) the current point is + // unreachable, so we don't need to execute the code, and (2) we've already + // handled the statements which update internal data structures (like the + // local variable map) which could be used by subsequent statements. + if (!ContainsLabel(S)) { + // Verify that any decl statements were handled as simple, they may be in + // scope of subsequent reachable statements. + assert(!isa(*S) && "Unexpected DeclStmt!"); + return; + } + + // Otherwise, make a new block to hold the code. + EnsureInsertPoint(); + } + // Generate a stoppoint if we are emitting debug info. EmitStopPoint(S); @@ -57,29 +68,37 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { default: // Must be an expression in a stmt context. Emit the value (to get // side-effects) and ignore the result. - if (const Expr *E = dyn_cast(S)) { - EmitAnyExpr(E, 0, false, true); - } else { + if (!isa(S)) ErrorUnsupported(S, "statement"); + + EmitAnyExpr(cast(S), 0, false, true); + + // Expression emitters don't handle unreachable blocks yet, so look for one + // explicitly here. This handles the common case of a call to a noreturn + // function. + if (llvm::BasicBlock *CurBB = Builder.GetInsertBlock()) { + if (CurBB->empty() && CurBB->use_empty()) { + CurBB->eraseFromParent(); + Builder.ClearInsertionPoint(); + } } break; - case Stmt::IndirectGotoStmtClass: + case Stmt::IndirectGotoStmtClass: EmitIndirectGotoStmt(cast(*S)); break; case Stmt::IfStmtClass: EmitIfStmt(cast(*S)); break; case Stmt::WhileStmtClass: EmitWhileStmt(cast(*S)); break; case Stmt::DoStmtClass: EmitDoStmt(cast(*S)); break; case Stmt::ForStmtClass: EmitForStmt(cast(*S)); break; - + case Stmt::ReturnStmtClass: EmitReturnStmt(cast(*S)); break; - case Stmt::DeclStmtClass: EmitDeclStmt(cast(*S)); break; case Stmt::SwitchStmtClass: EmitSwitchStmt(cast(*S)); break; case Stmt::AsmStmtClass: EmitAsmStmt(cast(*S)); break; case Stmt::ObjCAtTryStmtClass: EmitObjCAtTryStmt(cast(*S)); - break; + break; case Stmt::ObjCAtCatchStmtClass: assert(0 && "@catch statements should be handled by EmitObjCAtTryStmt"); break; @@ -92,9 +111,13 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { case Stmt::ObjCAtSynchronizedStmtClass: EmitObjCAtSynchronizedStmt(cast(*S)); break; - case Stmt::ObjCForCollectionStmtClass: + case Stmt::ObjCForCollectionStmtClass: EmitObjCForCollectionStmt(cast(*S)); break; + + case Stmt::CXXTryStmtClass: + EmitCXXTryStmt(cast(*S)); + break; } } @@ -103,6 +126,7 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S) { default: return false; case Stmt::NullStmtClass: break; case Stmt::CompoundStmtClass: EmitCompoundStmt(cast(*S)); break; + case Stmt::DeclStmtClass: EmitDeclStmt(cast(*S)); break; case Stmt::LabelStmtClass: EmitLabelStmt(cast(*S)); break; case Stmt::GotoStmtClass: EmitGotoStmt(cast(*S)); break; case Stmt::BreakStmtClass: EmitBreakStmt(cast(*S)); break; @@ -121,41 +145,42 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, llvm::Value *AggLoc, bool isAggVol) { PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),S.getLBracLoc(), "LLVM IR generation of compound statement ('{}')"); - + CGDebugInfo *DI = getDebugInfo(); if (DI) { +#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN + DI->setLocation(S.getLBracLoc()); + DI->EmitRegionStart(CurFn, Builder); +#else EnsureInsertPoint(); DI->setLocation(S.getLBracLoc()); - // FIXME: The llvm backend is currently not ready to deal with region_end - // for block scoping. In the presence of always_inline functions it gets so - // confused that it doesn't emit any debug info. Just disable this for now. - //DI->EmitRegionStart(CurFn, Builder); +#endif } // Keep track of the current cleanup stack depth. size_t CleanupStackDepth = CleanupEntries.size(); bool OldDidCallStackSave = DidCallStackSave; DidCallStackSave = false; - + for (CompoundStmt::const_body_iterator I = S.body_begin(), E = S.body_end()-GetLast; I != E; ++I) EmitStmt(*I); if (DI) { +#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN + DI->setLocation(S.getLBracLoc()); + DI->EmitRegionEnd(CurFn, Builder); +#else EnsureInsertPoint(); - DI->setLocation(S.getRBracLoc()); - - // FIXME: The llvm backend is currently not ready to deal with region_end - // for block scoping. In the presence of always_inline functions it gets so - // confused that it doesn't emit any debug info. Just disable this for now. - //DI->EmitRegionEnd(CurFn, Builder); + DI->setLocation(S.getLBracLoc()); +#endif } RValue RV; - if (!GetLast) + if (!GetLast) RV = RValue::get(0); else { - // We have to special case labels here. They are statements, but when put + // We have to special case labels here. They are statements, but when put // at the end of a statement expression, they yield the value of their // subexpression. Handle this by walking through all labels we encounter, // emitting them before we evaluate the subexpr. @@ -164,22 +189,22 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, EmitLabel(*LS); LastStmt = LS->getSubStmt(); } - + EnsureInsertPoint(); - + RV = EmitAnyExpr(cast(LastStmt), AggLoc); } DidCallStackSave = OldDidCallStackSave; - + EmitCleanupBlocks(CleanupStackDepth); - + return RV; } void CodeGenFunction::SimplifyForwardingBlocks(llvm::BasicBlock *BB) { llvm::BranchInst *BI = dyn_cast(BB->getTerminator()); - + // If there is a cleanup stack, then we it isn't worth trying to // simplify this block (we would need to remove it from the scope map // and cleanup entry). @@ -215,7 +240,7 @@ void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) { CleanupEntries.back().Blocks.push_back(BB); } } - + CurFn->getBasicBlockList().push_back(BB); Builder.SetInsertPoint(BB); } @@ -257,24 +282,31 @@ void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) { EmitBranchThroughCleanup(getBasicBlockForLabel(S.getLabel())); } + void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) { // Emit initial switch which will be patched up later by // EmitIndirectSwitches(). We need a default dest, so we use the // current BB, but this is overwritten. llvm::Value *V = Builder.CreatePtrToInt(EmitScalarExpr(S.getTarget()), - llvm::Type::Int32Ty, + llvm::Type::getInt32Ty(VMContext), "addr"); - llvm::SwitchInst *I = Builder.CreateSwitch(V, Builder.GetInsertBlock()); - IndirectSwitches.push_back(I); + llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); + - // Clear the insertion point to indicate we are in unreachable code. - Builder.ClearInsertionPoint(); + // Get the basic block for the indirect goto. + llvm::BasicBlock *IndGotoBB = GetIndirectGotoBlock(); + + // The first instruction in the block has to be the PHI for the switch dest, + // add an entry for this branch. + cast(IndGotoBB->begin())->addIncoming(V, CurBB); + + EmitBranch(IndGotoBB); } void CodeGenFunction::EmitIfStmt(const IfStmt &S) { // C99 6.8.4.1: The first substatement is executed if the expression compares // unequal to 0. The condition must be a scalar type. - + // If the condition constant folds and can be elided, try to avoid emitting // the condition and the dead arm of the if/else. if (int Cond = ConstantFoldsToSimpleInteger(S.getCond())) { @@ -282,7 +314,7 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) { const Stmt *Executed = S.getThen(), *Skipped = S.getElse(); if (Cond == -1) // Condition false? std::swap(Executed, Skipped); - + // If the skipped block has no labels in it, just emit the executed block. // This avoids emitting dead code and simplifies the CFG substantially. if (!ContainsLabel(Skipped)) { @@ -300,19 +332,19 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) { if (S.getElse()) ElseBlock = createBasicBlock("if.else"); EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock); - + // Emit the 'then' code. EmitBlock(ThenBlock); EmitStmt(S.getThen()); EmitBranch(ContBlock); - + // Emit the 'else' code if present. if (const Stmt *Else = S.getElse()) { EmitBlock(ElseBlock); EmitStmt(Else); EmitBranch(ContBlock); } - + // Emit the continuation block for code after the if. EmitBlock(ContBlock, true); } @@ -330,7 +362,7 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) { // Store the blocks to use for break and continue. BreakContinueStack.push_back(BreakContinue(ExitBlock, LoopHeader)); - + // Evaluate the conditional in the while header. C99 6.8.5.1: The // evaluation of the controlling expression takes place before each // execution of the loop body. @@ -339,23 +371,23 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) { // while(1) is common, avoid extra exit blocks. Be sure // to correctly handle break/continue though. bool EmitBoolCondBranch = true; - if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) + if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) if (C->isOne()) EmitBoolCondBranch = false; - + // As long as the condition is true, go to the loop body. if (EmitBoolCondBranch) Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock); - + // Emit the loop body. EmitBlock(LoopBody); EmitStmt(S.getBody()); - BreakContinueStack.pop_back(); - + BreakContinueStack.pop_back(); + // Cycle to the condition. EmitBranch(LoopHeader); - + // Emit the exit block. EmitBlock(ExitBlock, true); @@ -373,20 +405,20 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) { EmitBlock(LoopBody); llvm::BasicBlock *DoCond = createBasicBlock("do.cond"); - + // Store the blocks to use for break and continue. BreakContinueStack.push_back(BreakContinue(AfterDo, DoCond)); - + // Emit the body of the loop into the block. EmitStmt(S.getBody()); - + BreakContinueStack.pop_back(); - + EmitBlock(DoCond); - + // C99 6.8.5.2: "The evaluation of the controlling expression takes place // after each execution of the loop body." - + // Evaluate the conditional in the while header. // C99 6.8.5p2/p4: The first substatement is executed if the expression // compares unequal to 0. The condition must be a scalar type. @@ -395,14 +427,14 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) { // "do {} while (0)" is common in macros, avoid extra blocks. Be sure // to correctly handle break/continue though. bool EmitBoolCondBranch = true; - if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) + if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) if (C->isZero()) EmitBoolCondBranch = false; // As long as the condition is true, iterate the loop. if (EmitBoolCondBranch) Builder.CreateCondBr(BoolCondVal, LoopBody, AfterDo); - + // Emit the exit block. EmitBlock(AfterDo); @@ -431,41 +463,54 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { if (S.getCond()) { // As long as the condition is true, iterate the loop. llvm::BasicBlock *ForBody = createBasicBlock("for.body"); - + // C99 6.8.5p2/p4: The first substatement is executed if the expression // compares unequal to 0. The condition must be a scalar type. EmitBranchOnBoolExpr(S.getCond(), ForBody, AfterFor); - - EmitBlock(ForBody); + + EmitBlock(ForBody); } else { // Treat it as a non-zero constant. Don't even create a new block for the // body, just fall into it. } - // If the for loop doesn't have an increment we can just use the + // If the for loop doesn't have an increment we can just use the // condition as the continue block. llvm::BasicBlock *ContinueBlock; if (S.getInc()) ContinueBlock = createBasicBlock("for.inc"); else - ContinueBlock = CondBlock; - + ContinueBlock = CondBlock; + // Store the blocks to use for break and continue. BreakContinueStack.push_back(BreakContinue(AfterFor, ContinueBlock)); // If the condition is true, execute the body of the for stmt. +#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN + CGDebugInfo *DI = getDebugInfo(); + if (DI) { + DI->setLocation(S.getSourceRange().getBegin()); + DI->EmitRegionStart(CurFn, Builder); + } +#endif EmitStmt(S.getBody()); BreakContinueStack.pop_back(); - + // If there is an increment, emit it next. if (S.getInc()) { EmitBlock(ContinueBlock); EmitStmt(S.getInc()); } - + // Finally, branch back up to the condition for the next iteration. EmitBranch(CondBlock); +#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN + if (DI) { + DI->setLocation(S.getSourceRange().getEnd()); + DI->EmitRegionEnd(CurFn, Builder); + } +#endif // Emit the fall-through block. EmitBlock(AfterFor, true); @@ -488,7 +533,7 @@ void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) { void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { // Emit the result value, even if unused, to evalute the side effects. const Expr *RV = S.getRetValue(); - + // FIXME: Clean this up by using an LValue for ReturnTemp, // EmitStoreThroughLValue, and EmitAnyExpr. if (!ReturnValue) { @@ -514,6 +559,13 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { } void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) { + // As long as debug info is modeled with instructions, we have to ensure we + // have a place to insert here and write the stop point here. + if (getDebugInfo()) { + EnsureInsertPoint(); + EmitStopPoint(&S); + } + for (DeclStmt::const_decl_iterator I = S.decl_begin(), E = S.decl_end(); I != E; ++I) EmitDecl(**I); @@ -570,12 +622,12 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) { if (Range.ult(llvm::APInt(Range.getBitWidth(), 64))) { // Range is small enough to add multiple switch instruction cases. for (unsigned i = 0, e = Range.getZExtValue() + 1; i != e; ++i) { - SwitchInsn->addCase(llvm::ConstantInt::get(LHS), CaseDest); + SwitchInsn->addCase(llvm::ConstantInt::get(VMContext, LHS), CaseDest); LHS++; } return; - } - + } + // The range is too big. Emit "if" condition into a new block, // making sure to save and restore the current insertion point. llvm::BasicBlock *RestoreBB = Builder.GetInsertBlock(); @@ -590,11 +642,12 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) { Builder.SetInsertPoint(CaseRangeBlock); // Emit range check. - llvm::Value *Diff = - Builder.CreateSub(SwitchInsn->getCondition(), llvm::ConstantInt::get(LHS), - "tmp"); - llvm::Value *Cond = - Builder.CreateICmpULE(Diff, llvm::ConstantInt::get(Range), "tmp"); + llvm::Value *Diff = + Builder.CreateSub(SwitchInsn->getCondition(), + llvm::ConstantInt::get(VMContext, LHS), "tmp"); + llvm::Value *Cond = + Builder.CreateICmpULE(Diff, + llvm::ConstantInt::get(VMContext, Range), "tmp"); Builder.CreateCondBr(Cond, CaseDest, FalseDest); // Restore the appropriate insertion point. @@ -609,12 +662,12 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) { EmitCaseStmtRange(S); return; } - + EmitBlock(createBasicBlock("sw.bb")); llvm::BasicBlock *CaseDest = Builder.GetInsertBlock(); llvm::APSInt CaseVal = S.getLHS()->EvaluateAsInt(getContext()); - SwitchInsn->addCase(llvm::ConstantInt::get(CaseVal), CaseDest); - + SwitchInsn->addCase(llvm::ConstantInt::get(VMContext, CaseVal), CaseDest); + // Recursively emitting the statement is acceptable, but is not wonderful for // code where we have many case statements nested together, i.e.: // case 1: @@ -631,18 +684,18 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) { while (NextCase && NextCase->getRHS() == 0) { CurCase = NextCase; CaseVal = CurCase->getLHS()->EvaluateAsInt(getContext()); - SwitchInsn->addCase(llvm::ConstantInt::get(CaseVal), CaseDest); + SwitchInsn->addCase(llvm::ConstantInt::get(VMContext, CaseVal), CaseDest); NextCase = dyn_cast(CurCase->getSubStmt()); } - + // Normal default recursion for non-cases. EmitStmt(CurCase->getSubStmt()); } void CodeGenFunction::EmitDefaultStmt(const DefaultStmt &S) { llvm::BasicBlock *DefaultBlock = SwitchInsn->getDefaultDest(); - assert(DefaultBlock->empty() && + assert(DefaultBlock->empty() && "EmitDefaultStmt: Default block already defined?"); EmitBlock(DefaultBlock); EmitStmt(S.getSubStmt()); @@ -678,13 +731,13 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { // Emit switch body. EmitStmt(S.getBody()); - + BreakContinueStack.pop_back(); // Update the default block in case explicit case range tests have // been chained on top. SwitchInsn->setSuccessor(0, CaseRangeBlock); - + // If a default was never emitted then reroute any jumps to it and // discard. if (!DefaultBlock->getParent()) { @@ -703,7 +756,7 @@ static std::string SimplifyConstraint(const char *Constraint, TargetInfo &Target, llvm::SmallVectorImpl *OutCons=0) { std::string Result; - + while (*Constraint) { switch (*Constraint) { default: @@ -721,7 +774,7 @@ SimplifyConstraint(const char *Constraint, TargetInfo &Target, assert(OutCons && "Must pass output names to constraints with a symbolic name"); unsigned Index; - bool result = Target.resolveSymbolicName(Constraint, + bool result = Target.resolveSymbolicName(Constraint, &(*OutCons)[0], OutCons->size(), Index); assert(result && "Could not resolve symbolic name"); result=result; @@ -729,10 +782,10 @@ SimplifyConstraint(const char *Constraint, TargetInfo &Target, break; } } - + Constraint++; } - + return Result; } @@ -741,9 +794,9 @@ llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S, const Expr *InputExpr, std::string &ConstraintStr) { llvm::Value *Arg; - if (Info.allowsRegister() || !Info.allowsMemory()) { + if (Info.allowsRegister() || !Info.allowsMemory()) { const llvm::Type *Ty = ConvertType(InputExpr->getType()); - + if (Ty->isSingleValueType()) { Arg = EmitScalarExpr(InputExpr); } else { @@ -752,9 +805,9 @@ llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S, uint64_t Size = CGM.getTargetData().getTypeSizeInBits(Ty); if (Size <= 64 && llvm::isPowerOf2_64(Size)) { - Ty = llvm::IntegerType::get(Size); + Ty = llvm::IntegerType::get(VMContext, Size); Ty = llvm::PointerType::getUnqual(Ty); - + Arg = Builder.CreateLoad(Builder.CreateBitCast(Dest.getAddress(), Ty)); } else { Arg = Dest.getAddress(); @@ -767,7 +820,7 @@ llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S, Arg = Dest.getAddress(); ConstraintStr += '*'; } - + return Arg; } @@ -777,7 +830,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { llvm::SmallVector Pieces; unsigned DiagOffs; S.AnalyzeAsmString(Pieces, getContext(), DiagOffs); - + // Assemble the pieces into the final asm string. std::string AsmString; for (unsigned i = 0, e = Pieces.size(); i != e; ++i) { @@ -789,19 +842,19 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { AsmString += "${" + llvm::utostr(Pieces[i].getOperandNo()) + ':' + Pieces[i].getModifier() + '}'; } - + // Get all the output and input constraints together. llvm::SmallVector OutputConstraintInfos; llvm::SmallVector InputConstraintInfos; - for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) { + 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; OutputConstraintInfos.push_back(Info); - } - + } + for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) { TargetInfo::ConstraintInfo Info(S.getInputConstraint(i), S.getInputName(i)); @@ -811,9 +864,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { assert(result && "Failed to parse input constraint"); InputConstraintInfos.push_back(Info); } - + std::string Constraints; - + std::vector ResultRegDests; std::vector ResultRegQualTys; std::vector ResultRegTypes; @@ -826,16 +879,16 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { std::vector InOutArgs; std::vector InOutArgTypes; - for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) { + for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) { TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i]; // Simplify the output constraint. std::string OutputConstraint(S.getOutputConstraint(i)); OutputConstraint = SimplifyConstraint(OutputConstraint.c_str() + 1, Target); - + const Expr *OutExpr = S.getOutputExpr(i); OutExpr = OutExpr->IgnoreParenNoopCasts(getContext()); - + LValue Dest = EmitLValue(OutExpr); if (!Constraints.empty()) Constraints += ','; @@ -848,7 +901,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { ResultRegDests.push_back(Dest); ResultRegTypes.push_back(ConvertTypeForMem(OutExpr->getType())); ResultTruncRegTypes.push_back(ResultRegTypes.back()); - + // If this output is tied to an input, and if the input is larger, then // we need to set the actual result type of the inline asm node to be the // same as the input type. @@ -861,30 +914,29 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { break; } assert(InputNo != S.getNumInputs() && "Didn't find matching input!"); - + QualType InputTy = S.getInputExpr(InputNo)->getType(); QualType OutputTy = OutExpr->getType(); - + uint64_t InputSize = getContext().getTypeSize(InputTy); if (getContext().getTypeSize(OutputTy) < InputSize) { // Form the asm to return the value as a larger integer type. - ResultRegTypes.back() = llvm::IntegerType::get((unsigned)InputSize); + ResultRegTypes.back() = llvm::IntegerType::get(VMContext, (unsigned)InputSize); } } - } else { ArgTypes.push_back(Dest.getAddress()->getType()); Args.push_back(Dest.getAddress()); Constraints += "=*"; Constraints += OutputConstraint; } - + if (Info.isReadWrite()) { InOutConstraints += ','; const Expr *InputExpr = S.getOutputExpr(i); llvm::Value *Arg = EmitAsmInput(S, Info, InputExpr, InOutConstraints); - + if (Info.allowsRegister()) InOutConstraints += llvm::utostr(i); else @@ -894,9 +946,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { InOutArgs.push_back(Arg); } } - + unsigned NumConstraints = S.getNumOutputs() + S.getNumInputs(); - + for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) { const Expr *InputExpr = S.getInputExpr(i); @@ -904,14 +956,14 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { if (!Constraints.empty()) Constraints += ','; - + // Simplify the input constraint. std::string InputConstraint(S.getInputConstraint(i)); InputConstraint = SimplifyConstraint(InputConstraint.c_str(), Target, &OutputConstraintInfos); llvm::Value *Arg = EmitAsmInput(S, Info, InputExpr, Constraints); - + // If this input argument is tied to a larger output result, extend the // input to be the same size as the output. The LLVM backend wants to see // the input and output of a matching constraint be the same size. Note @@ -921,46 +973,46 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { unsigned Output = Info.getTiedOperand(); QualType OutputTy = S.getOutputExpr(Output)->getType(); QualType InputTy = InputExpr->getType(); - + if (getContext().getTypeSize(OutputTy) > getContext().getTypeSize(InputTy)) { // Use ptrtoint as appropriate so that we can do our extension. if (isa(Arg->getType())) Arg = Builder.CreatePtrToInt(Arg, - llvm::IntegerType::get(LLVMPointerWidth)); + llvm::IntegerType::get(VMContext, LLVMPointerWidth)); unsigned OutputSize = (unsigned)getContext().getTypeSize(OutputTy); - Arg = Builder.CreateZExt(Arg, llvm::IntegerType::get(OutputSize)); + Arg = Builder.CreateZExt(Arg, llvm::IntegerType::get(VMContext, OutputSize)); } } - - + + ArgTypes.push_back(Arg->getType()); Args.push_back(Arg); Constraints += InputConstraint; } - + // Append the "input" part of inout constraints last. for (unsigned i = 0, e = InOutArgs.size(); i != e; i++) { ArgTypes.push_back(InOutArgTypes[i]); Args.push_back(InOutArgs[i]); } Constraints += InOutConstraints; - + // Clobbers for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) { std::string Clobber(S.getClobber(i)->getStrData(), S.getClobber(i)->getByteLength()); Clobber = Target.getNormalizedGCCRegisterName(Clobber.c_str()); - + if (i != 0 || NumConstraints != 0) Constraints += ','; - + Constraints += "~{"; Constraints += Clobber; Constraints += '}'; } - + // Add machine specific clobbers std::string MachineClobbers = Target.getClobbers(); if (!MachineClobbers.empty()) { @@ -971,22 +1023,22 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { const llvm::Type *ResultType; if (ResultRegTypes.empty()) - ResultType = llvm::Type::VoidTy; + ResultType = llvm::Type::getVoidTy(VMContext); else if (ResultRegTypes.size() == 1) ResultType = ResultRegTypes[0]; else - ResultType = llvm::StructType::get(ResultRegTypes); - - const llvm::FunctionType *FTy = + ResultType = llvm::StructType::get(VMContext, ResultRegTypes); + + const llvm::FunctionType *FTy = llvm::FunctionType::get(ResultType, ArgTypes, false); - - llvm::InlineAsm *IA = - llvm::InlineAsm::get(FTy, AsmString, Constraints, + + llvm::InlineAsm *IA = + llvm::InlineAsm::get(FTy, AsmString, Constraints, S.isVolatile() || S.getNumOutputs() == 0); llvm::CallInst *Result = Builder.CreateCall(IA, Args.begin(), Args.end()); Result->addAttribute(~0, llvm::Attribute::NoUnwind); - - + + // Extract all of the register value results from the asm. std::vector RegResults; if (ResultRegTypes.size() == 1) { @@ -997,10 +1049,10 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { RegResults.push_back(Tmp); } } - + for (unsigned i = 0, e = RegResults.size(); i != e; ++i) { llvm::Value *Tmp = RegResults[i]; - + // If the result type of the LLVM IR asm doesn't match the result type of // the expression, do the conversion. if (ResultRegTypes[i] != ResultTruncRegTypes[i]) { @@ -1008,14 +1060,14 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // Truncate the integer result to the right size, note that // ResultTruncRegTypes can be a pointer. uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy); - Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get((unsigned)ResSize)); - + Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get(VMContext, (unsigned)ResSize)); + if (Tmp->getType() != TruncTy) { assert(isa(TruncTy)); Tmp = Builder.CreateIntToPtr(Tmp, TruncTy); } } - + EmitStoreThroughLValue(RValue::get(Tmp), ResultRegDests[i], ResultRegQualTys[i]); } diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h index 820e1bd6c3ec..2a06f51f6685 100644 --- a/lib/CodeGen/CGValue.h +++ b/lib/CodeGen/CGValue.h @@ -24,7 +24,7 @@ namespace llvm { namespace clang { class ObjCPropertyRefExpr; - class ObjCKVCRefExpr; + class ObjCImplicitSetterGetterRefExpr; namespace CodeGen { @@ -37,14 +37,14 @@ class RValue { // TODO: Encode this into the low bit of pointer for more efficient // return-by-value. enum { Scalar, Complex, Aggregate } Flavor; - + bool Volatile:1; public: - + bool isScalar() const { return Flavor == Scalar; } bool isComplex() const { return Flavor == Complex; } bool isAggregate() const { return Flavor == Aggregate; } - + bool isVolatileQualified() const { return Volatile; } /// getScalar() - Return the Value* of this scalar value. @@ -58,13 +58,13 @@ public: std::pair getComplexVal() const { return std::pair(V1, V2); } - + /// getAggregateAddr() - Return the Value* of the address of the aggregate. llvm::Value *getAggregateAddr() const { assert(isAggregate() && "Not an aggregate!"); return V1; } - + static RValue get(llvm::Value *V) { RValue ER; ER.V1 = V; @@ -106,7 +106,7 @@ public: /// bitrange. class LValue { // FIXME: alignment? - + enum { Simple, // This is a normal l-value, use getAddress(). VectorElt, // This is a vector element l-value (V[i]), use getVector* @@ -118,21 +118,15 @@ class LValue { // use getKVCRefExpr } LVType; - enum ObjCType { - None = 0, // object with no gc attribute. - Weak, // __weak object expression - Strong // __strong object expression - }; - llvm::Value *V; - + union { // Index into a vector subscript: V[i] llvm::Value *VectorIdx; // ExtVector element subset: V.xyx llvm::Constant *VectorElts; - + // BitField start bit and size struct { unsigned short StartBit; @@ -143,16 +137,18 @@ class LValue { // Obj-C property reference expression const ObjCPropertyRefExpr *PropertyRefExpr; // ObjC 'implicit' property reference expression - const ObjCKVCRefExpr *KVCRefExpr; + const ObjCImplicitSetterGetterRefExpr *KVCRefExpr; }; - bool Volatile:1; - // FIXME: set but never used, what effect should it have? - bool Restrict:1; + // 'const' is unused here + Qualifiers Quals; // objective-c's ivar bool Ivar:1; + // objective-c's ivar is an array + bool ObjIsArray:1; + // LValue is non-gc'able for any reason, including being a parameter or local // variable. bool NonGC: 1; @@ -160,21 +156,17 @@ class LValue { // Lvalue is a global reference of an objective-c object bool GlobalObjCRef : 1; - // objective-c's gc attributes - unsigned ObjCType : 2; - - - + Expr *BaseIvarExp; private: - static void SetQualifiers(unsigned Qualifiers, LValue& R) { - R.Volatile = (Qualifiers&QualType::Volatile)!=0; - R.Restrict = (Qualifiers&QualType::Restrict)!=0; + void SetQualifiers(Qualifiers Quals) { + this->Quals = Quals; + // FIXME: Convenient place to set objc flags to 0. This should really be // done in a user-defined constructor instead. - R.ObjCType = None; - R.Ivar = R.NonGC = R.GlobalObjCRef = false; + this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false; + this->BaseIvarExp = 0; } - + public: bool isSimple() const { return LVType == Simple; } bool isVectorElt() const { return LVType == VectorElt; } @@ -183,39 +175,38 @@ public: bool isPropertyRef() const { return LVType == PropertyRef; } bool isKVCRef() const { return LVType == KVCRef; } - bool isVolatileQualified() const { return Volatile; } - bool isRestrictQualified() const { return Restrict; } - unsigned getQualifiers() const { - return (Volatile ? QualType::Volatile : 0) | - (Restrict ? QualType::Restrict : 0); + bool isVolatileQualified() const { return Quals.hasVolatile(); } + bool isRestrictQualified() const { return Quals.hasRestrict(); } + unsigned getVRQualifiers() const { + return Quals.getCVRQualifiers() & ~Qualifiers::Const; } - + bool isObjCIvar() const { return Ivar; } + bool isObjCArray() const { return ObjIsArray; } bool isNonGC () const { return NonGC; } bool isGlobalObjCRef() const { return GlobalObjCRef; } - bool isObjCWeak() const { return ObjCType == Weak; } - bool isObjCStrong() const { return ObjCType == Strong; } + bool isObjCWeak() const { return Quals.getObjCGCAttr() == Qualifiers::Weak; } + bool isObjCStrong() const { return Quals.getObjCGCAttr() == Qualifiers::Strong; } + Expr *getBaseIvarExp() const { return BaseIvarExp; } + void setBaseIvarExp(Expr *V) { BaseIvarExp = V; } + + unsigned getAddressSpace() const { return Quals.getAddressSpace(); } + static void SetObjCIvar(LValue& R, bool iValue) { R.Ivar = iValue; } - + static void SetObjCArray(LValue& R, bool iValue) { + R.ObjIsArray = iValue; + } static void SetGlobalObjCRef(LValue& R, bool iValue) { R.GlobalObjCRef = iValue; } - + static void SetObjCNonGC(LValue& R, bool iValue) { R.NonGC = iValue; } - static void SetObjCType(QualType::GCAttrTypes GCAttrs, LValue& R) { - if (GCAttrs == QualType::Weak) - R.ObjCType = Weak; - else if (GCAttrs == QualType::Strong) - R.ObjCType = Strong; - else - R.ObjCType = None; - } - + // simple lvalue llvm::Value *getAddress() const { assert(isSimple()); return V; } // vector elt lvalue @@ -248,51 +239,49 @@ public: } // 'implicit' property ref lvalue - const ObjCKVCRefExpr *getKVCRefExpr() const { + const ObjCImplicitSetterGetterRefExpr *getKVCRefExpr() const { assert(isKVCRef()); return KVCRefExpr; } - static LValue MakeAddr(llvm::Value *V, unsigned Qualifiers, - QualType::GCAttrTypes GCAttrs = QualType::GCNone) { + static LValue MakeAddr(llvm::Value *V, Qualifiers Quals) { LValue R; R.LVType = Simple; R.V = V; - SetQualifiers(Qualifiers,R); - SetObjCType(GCAttrs, R); + R.SetQualifiers(Quals); return R; } - + static LValue MakeVectorElt(llvm::Value *Vec, llvm::Value *Idx, - unsigned Qualifiers) { + unsigned CVR) { LValue R; R.LVType = VectorElt; R.V = Vec; R.VectorIdx = Idx; - SetQualifiers(Qualifiers,R); + R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); return R; } - + static LValue MakeExtVectorElt(llvm::Value *Vec, llvm::Constant *Elts, - unsigned Qualifiers) { + unsigned CVR) { LValue R; R.LVType = ExtVectorElt; R.V = Vec; R.VectorElts = Elts; - SetQualifiers(Qualifiers,R); + R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); return R; } static LValue MakeBitfield(llvm::Value *V, unsigned short StartBit, unsigned short Size, bool IsSigned, - unsigned Qualifiers) { + unsigned CVR) { LValue R; R.LVType = BitField; R.V = V; R.BitfieldData.StartBit = StartBit; R.BitfieldData.Size = Size; R.BitfieldData.IsSigned = IsSigned; - SetQualifiers(Qualifiers,R); + R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); return R; } @@ -300,19 +289,20 @@ public: // the lvalue. However, this complicates the code a bit, and I haven't figured // out how to make it go wrong yet. static LValue MakePropertyRef(const ObjCPropertyRefExpr *E, - unsigned Qualifiers) { + unsigned CVR) { LValue R; R.LVType = PropertyRef; R.PropertyRefExpr = E; - SetQualifiers(Qualifiers,R); + R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); return R; } - - static LValue MakeKVCRef(const ObjCKVCRefExpr *E, unsigned Qualifiers) { + + static LValue MakeKVCRef(const ObjCImplicitSetterGetterRefExpr *E, + unsigned CVR) { LValue R; R.LVType = KVCRef; R.KVCRefExpr = E; - SetQualifiers(Qualifiers,R); + R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); return R; } }; diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp new file mode 100644 index 000000000000..41f7eefbe82b --- /dev/null +++ b/lib/CodeGen/CGVtable.cpp @@ -0,0 +1,557 @@ +//===--- CGVtable.cpp - Emit LLVM Code for C++ vtables --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with C++ code generation of virtual tables. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenModule.h" +#include "CodeGenFunction.h" + +#include "clang/AST/RecordLayout.h" + +using namespace clang; +using namespace CodeGen; + +class VtableBuilder { +public: + /// Index_t - Vtable index type. + typedef uint64_t Index_t; +private: + std::vector &methods; + std::vector submethods; + llvm::Type *Ptr8Ty; + /// Class - The most derived class that this vtable is being built for. + const CXXRecordDecl *Class; + /// BLayout - Layout for the most derived class that this vtable is being + /// built for. + const ASTRecordLayout &BLayout; + llvm::SmallSet IndirectPrimary; + llvm::SmallSet SeenVBase; + llvm::Constant *rtti; + llvm::LLVMContext &VMContext; + CodeGenModule &CGM; // Per-module state. + /// Index - Maps a method decl into a vtable index. Useful for virtual + /// dispatch codegen. + llvm::DenseMap Index; + llvm::DenseMap VCall; + llvm::DenseMap VCallOffset; + llvm::DenseMap VBIndex; + typedef std::pair CallOffset; + typedef llvm::DenseMap Thunks_t; + Thunks_t Thunks; + typedef llvm::DenseMap, + CanQualType> > CovariantThunks_t; + CovariantThunks_t CovariantThunks; + std::vector VCalls; + typedef CXXRecordDecl::method_iterator method_iter; + // FIXME: Linkage should follow vtable + const bool Extern; + const uint32_t LLVMPointerWidth; + Index_t extra; +public: + VtableBuilder(std::vector &meth, + const CXXRecordDecl *c, + CodeGenModule &cgm) + : methods(meth), Class(c), BLayout(cgm.getContext().getASTRecordLayout(c)), + rtti(cgm.GenerateRtti(c)), VMContext(cgm.getModule().getContext()), + CGM(cgm), Extern(true), + LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) { + Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); + } + + llvm::DenseMap &getIndex() { return Index; } + llvm::DenseMap &getVBIndex() + { return VBIndex; } + + llvm::Constant *wrap(Index_t i) { + llvm::Constant *m; + m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i); + return llvm::ConstantExpr::getIntToPtr(m, Ptr8Ty); + } + + llvm::Constant *wrap(llvm::Constant *m) { + return llvm::ConstantExpr::getBitCast(m, Ptr8Ty); + } + + void GenerateVBaseOffsets(std::vector &offsets, + const CXXRecordDecl *RD, uint64_t Offset, + bool updateVBIndex, Index_t current_vbindex) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast(i->getType()->getAs()->getDecl()); + Index_t next_vbindex = current_vbindex; + if (i->isVirtual() && !SeenVBase.count(Base)) { + SeenVBase.insert(Base); + int64_t BaseOffset = -(Offset/8) + BLayout.getVBaseClassOffset(Base)/8; + llvm::Constant *m = wrap(BaseOffset); + m = wrap((0?700:0) + BaseOffset); + if (updateVBIndex) { + next_vbindex = (ssize_t)(-(offsets.size()*LLVMPointerWidth/8) + - 3*LLVMPointerWidth/8); + VBIndex[Base] = next_vbindex; + } + offsets.push_back(m); + } + // We also record offsets for non-virtual bases to closest enclosing + // virtual base. We do this so that we don't have to search + // for the nearst virtual base class when generating thunks. + if (updateVBIndex && VBIndex.count(Base) == 0) + VBIndex[Base] = next_vbindex; + GenerateVBaseOffsets(offsets, Base, Offset, updateVBIndex, next_vbindex); + } + } + + void StartNewTable() { + SeenVBase.clear(); + } + + Index_t VBlookup(CXXRecordDecl *D, CXXRecordDecl *B); + + /// getVbaseOffset - Returns the index into the vtable for the virtual base + /// offset for the given (B) virtual base of the derived class D. + Index_t getVbaseOffset(QualType qB, QualType qD) { + qD = qD->getAs()->getPointeeType(); + qB = qB->getAs()->getPointeeType(); + CXXRecordDecl *D = cast(qD->getAs()->getDecl()); + CXXRecordDecl *B = cast(qB->getAs()->getDecl()); + if (D != Class) + return VBlookup(D, B); + llvm::DenseMap::iterator i; + i = VBIndex.find(B); + if (i != VBIndex.end()) + return i->second; + + assert(false && "FIXME: Base not found"); + return 0; + } + + bool OverrideMethod(const CXXMethodDecl *MD, llvm::Constant *m, + bool MorallyVirtual, Index_t Offset) { + typedef CXXMethodDecl::method_iterator meth_iter; + + // FIXME: Don't like the nested loops. For very large inheritance + // heirarchies we could have a table on the side with the final overridder + // and just replace each instance of an overridden method once. Would be + // nice to measure the cost/benefit on real code. + + for (meth_iter mi = MD->begin_overridden_methods(), + e = MD->end_overridden_methods(); + mi != e; ++mi) { + const CXXMethodDecl *OMD = *mi; + llvm::Constant *om; + om = CGM.GetAddrOfFunction(OMD, Ptr8Ty); + om = llvm::ConstantExpr::getBitCast(om, Ptr8Ty); + + for (Index_t i = 0, e = submethods.size(); + i != e; ++i) { + // FIXME: begin_overridden_methods might be too lax, covariance */ + if (submethods[i] != om) + continue; + QualType nc_oret = OMD->getType()->getAs()->getResultType(); + CanQualType oret = CGM.getContext().getCanonicalType(nc_oret); + QualType nc_ret = MD->getType()->getAs()->getResultType(); + CanQualType ret = CGM.getContext().getCanonicalType(nc_ret); + CallOffset ReturnOffset = std::make_pair(0, 0); + if (oret != ret) { + // FIXME: calculate offsets for covariance + Index_t nv = 0; + if (CovariantThunks.count(OMD)) { + oret = CovariantThunks[OMD].second; + CovariantThunks.erase(OMD); + } + ReturnOffset = std::make_pair(nv, getVbaseOffset(oret, ret)); + } + Index[MD] = i; + submethods[i] = m; + + Thunks.erase(OMD); + if (MorallyVirtual) { + Index_t &idx = VCall[OMD]; + if (idx == 0) { + VCallOffset[MD] = Offset/8; + idx = VCalls.size()+1; + VCalls.push_back(0); + } else { + VCallOffset[MD] = VCallOffset[OMD]; + VCalls[idx-1] = -VCallOffset[OMD] + Offset/8; + } + VCall[MD] = idx; + CallOffset ThisOffset; + // FIXME: calculate non-virtual offset + ThisOffset = std::make_pair(0, -((idx+extra+2)*LLVMPointerWidth/8)); + if (ReturnOffset.first || ReturnOffset.second) + CovariantThunks[MD] = std::make_pair(std::make_pair(ThisOffset, + ReturnOffset), + oret); + else + Thunks[MD] = ThisOffset; + return true; + } + + // FIXME: finish off + int64_t O = VCallOffset[OMD] - Offset/8; + if (O || ReturnOffset.first || ReturnOffset.second) { + CallOffset ThisOffset = std::make_pair(O, 0); + + if (ReturnOffset.first || ReturnOffset.second) + CovariantThunks[MD] = std::make_pair(std::make_pair(ThisOffset, + ReturnOffset), + oret); + else + Thunks[MD] = ThisOffset; + } + return true; + } + } + + return false; + } + + void InstallThunks() { + for (Thunks_t::iterator i = Thunks.begin(), e = Thunks.end(); + i != e; ++i) { + const CXXMethodDecl *MD = i->first; + Index_t idx = Index[MD]; + Index_t nv_O = i->second.first; + Index_t v_O = i->second.second; + submethods[idx] = CGM.BuildThunk(MD, Extern, nv_O, v_O); + } + Thunks.clear(); + for (CovariantThunks_t::iterator i = CovariantThunks.begin(), + e = CovariantThunks.end(); + i != e; ++i) { + const CXXMethodDecl *MD = i->first; + Index_t idx = Index[MD]; + Index_t nv_t = i->second.first.first.first; + Index_t v_t = i->second.first.first.second; + Index_t nv_r = i->second.first.second.first; + Index_t v_r = i->second.first.second.second; + submethods[idx] = CGM.BuildCovariantThunk(MD, Extern, nv_t, v_t, nv_r, + v_r); + } + CovariantThunks.clear(); + } + + void OverrideMethods(std::vector > *Path, bool MorallyVirtual) { + for (std::vector >::reverse_iterator i =Path->rbegin(), + e = Path->rend(); i != e; ++i) { + const CXXRecordDecl *RD = i->first; + int64_t Offset = i->second; + for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; + ++mi) { + if (!mi->isVirtual()) + continue; + + const CXXMethodDecl *MD = *mi; + llvm::Constant *m = 0; + if (const CXXDestructorDecl *Dtor = dyn_cast(MD)) + m = wrap(CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete)); + else { + const FunctionProtoType *FPT = + MD->getType()->getAs(); + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + + m = wrap(CGM.GetAddrOfFunction(MD, Ty)); + } + + OverrideMethod(MD, m, MorallyVirtual, Offset); + } + } + } + + void AddMethod(const CXXMethodDecl *MD, bool MorallyVirtual, Index_t Offset) { + llvm::Constant *m = 0; + if (const CXXDestructorDecl *Dtor = dyn_cast(MD)) + m = wrap(CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete)); + else { + const FunctionProtoType *FPT = MD->getType()->getAs(); + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + + m = wrap(CGM.GetAddrOfFunction(MD, Ty)); + } + + // If we can find a previously allocated slot for this, reuse it. + if (OverrideMethod(MD, m, MorallyVirtual, Offset)) + return; + + // else allocate a new slot. + Index[MD] = submethods.size(); + submethods.push_back(m); + if (MorallyVirtual) { + VCallOffset[MD] = Offset/8; + Index_t &idx = VCall[MD]; + // Allocate the first one, after that, we reuse the previous one. + if (idx == 0) { + idx = VCalls.size()+1; + VCalls.push_back(0); + } + } + } + + void AddMethods(const CXXRecordDecl *RD, bool MorallyVirtual, + Index_t Offset) { + for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; + ++mi) + if (mi->isVirtual()) + AddMethod(*mi, MorallyVirtual, Offset); + } + + void NonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout, + const CXXRecordDecl *PrimaryBase, + bool PrimaryBaseWasVirtual, bool MorallyVirtual, + int64_t Offset) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + if (i->isVirtual()) + continue; + const CXXRecordDecl *Base = + cast(i->getType()->getAs()->getDecl()); + if (Base != PrimaryBase || PrimaryBaseWasVirtual) { + uint64_t o = Offset + Layout.getBaseClassOffset(Base); + StartNewTable(); + std::vector > S; + S.push_back(std::make_pair(RD, Offset)); + GenerateVtableForBase(Base, MorallyVirtual, o, false, &S); + } + } + } + + Index_t end(const CXXRecordDecl *RD, std::vector &offsets, + const ASTRecordLayout &Layout, + const CXXRecordDecl *PrimaryBase, + bool PrimaryBaseWasVirtual, bool MorallyVirtual, + int64_t Offset, bool ForVirtualBase) { + StartNewTable(); + extra = 0; + // FIXME: Cleanup. + if (!ForVirtualBase) { + // then virtual base offsets... + for (std::vector::reverse_iterator i = offsets.rbegin(), + e = offsets.rend(); i != e; ++i) + methods.push_back(*i); + } + + // The vcalls come first... + for (std::vector::reverse_iterator i=VCalls.rbegin(), + e=VCalls.rend(); + i != e; ++i) + methods.push_back(wrap((0?600:0) + *i)); + VCalls.clear(); + + if (ForVirtualBase) { + // then virtual base offsets... + for (std::vector::reverse_iterator i = offsets.rbegin(), + e = offsets.rend(); i != e; ++i) + methods.push_back(*i); + } + + methods.push_back(wrap(-(Offset/8))); + methods.push_back(rtti); + Index_t AddressPoint = methods.size(); + + InstallThunks(); + methods.insert(methods.end(), submethods.begin(), submethods.end()); + submethods.clear(); + + // and then the non-virtual bases. + NonVirtualBases(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, + MorallyVirtual, Offset); + return AddressPoint; + } + + void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset) { + if (!RD->isDynamicClass()) + return; + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); + + // vtables are composed from the chain of primaries. + if (PrimaryBase) { + if (PrimaryBaseWasVirtual) + IndirectPrimary.insert(PrimaryBase); + Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset); + } + + // And add the virtuals for the class to the primary vtable. + AddMethods(RD, MorallyVirtual, Offset); + } + + int64_t GenerateVtableForBase(const CXXRecordDecl *RD, + bool MorallyVirtual = false, int64_t Offset = 0, + bool ForVirtualBase = false, + std::vector > *Path = 0) { + if (!RD->isDynamicClass()) + return 0; + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); + + std::vector offsets; + extra = 0; + GenerateVBaseOffsets(offsets, RD, Offset, !ForVirtualBase, 0); + if (ForVirtualBase) + extra = offsets.size(); + + // vtables are composed from the chain of primaries. + if (PrimaryBase) { + if (PrimaryBaseWasVirtual) + IndirectPrimary.insert(PrimaryBase); + Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset); + } + + // And add the virtuals for the class to the primary vtable. + AddMethods(RD, MorallyVirtual, Offset); + + if (Path) + OverrideMethods(Path, MorallyVirtual); + + return end(RD, offsets, Layout, PrimaryBase, PrimaryBaseWasVirtual, + MorallyVirtual, Offset, ForVirtualBase); + } + + void GenerateVtableForVBases(const CXXRecordDecl *RD, + int64_t Offset = 0, + std::vector > *Path = 0) { + bool alloc = false; + if (Path == 0) { + alloc = true; + Path = new std::vector >; + } + // FIXME: We also need to override using all paths to a virtual base, + // right now, we just process the first path + Path->push_back(std::make_pair(RD, Offset)); + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast(i->getType()->getAs()->getDecl()); + if (i->isVirtual() && !IndirectPrimary.count(Base)) { + // Mark it so we don't output it twice. + IndirectPrimary.insert(Base); + StartNewTable(); + int64_t BaseOffset = BLayout.getVBaseClassOffset(Base); + GenerateVtableForBase(Base, true, BaseOffset, true, Path); + } + int64_t BaseOffset = Offset; + if (i->isVirtual()) + BaseOffset = BLayout.getVBaseClassOffset(Base); + if (Base->getNumVBases()) + GenerateVtableForVBases(Base, BaseOffset, Path); + } + Path->pop_back(); + if (alloc) + delete Path; + } +}; + + +VtableBuilder::Index_t VtableBuilder::VBlookup(CXXRecordDecl *D, + CXXRecordDecl *B) { + return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B); +} + +int64_t CGVtableInfo::getMethodVtableIndex(const CXXMethodDecl *MD) { + MD = MD->getCanonicalDecl(); + + MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(MD); + if (I != MethodVtableIndices.end()) + return I->second; + + const CXXRecordDecl *RD = MD->getParent(); + + std::vector methods; + // FIXME: This seems expensive. Can we do a partial job to get + // just this data. + VtableBuilder b(methods, RD, CGM); + b.GenerateVtableForBase(RD); + b.GenerateVtableForVBases(RD); + + MethodVtableIndices.insert(b.getIndex().begin(), + b.getIndex().end()); + + I = MethodVtableIndices.find(MD); + assert(I != MethodVtableIndices.end() && "Did not find index!"); + return I->second; +} + +int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, + const CXXRecordDecl *VBase) { + ClassPairTy ClassPair(RD, VBase); + + VirtualBaseClassIndiciesTy::iterator I = + VirtualBaseClassIndicies.find(ClassPair); + if (I != VirtualBaseClassIndicies.end()) + return I->second; + + std::vector methods; + // FIXME: This seems expensive. Can we do a partial job to get + // just this data. + VtableBuilder b(methods, RD, CGM); + b.GenerateVtableForBase(RD); + b.GenerateVtableForVBases(RD); + + for (llvm::DenseMap::iterator I = + b.getVBIndex().begin(), E = b.getVBIndex().end(); I != E; ++I) { + // Insert all types. + ClassPairTy ClassPair(RD, I->first); + + VirtualBaseClassIndicies.insert(std::make_pair(ClassPair, I->second)); + } + + I = VirtualBaseClassIndicies.find(ClassPair); + assert(I != VirtualBaseClassIndicies.end() && "Did not find index!"); + + return I->second; +} + +llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) { + llvm::SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + mangleCXXVtable(CGM.getMangleContext(), RD, Out); + + llvm::GlobalVariable::LinkageTypes linktype; + linktype = llvm::GlobalValue::WeakAnyLinkage; + std::vector methods; + llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); + int64_t AddressPoint; + + VtableBuilder b(methods, RD, CGM); + + // First comes the vtables for all the non-virtual bases... + AddressPoint = b.GenerateVtableForBase(RD); + + // then the vtables for all the virtual bases. + b.GenerateVtableForVBases(RD); + + llvm::Constant *C; + llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, methods.size()); + C = llvm::ConstantArray::get(type, methods); + llvm::Value *vtable = new llvm::GlobalVariable(CGM.getModule(), type, true, + linktype, C, Out.str()); + vtable = Builder.CreateBitCast(vtable, Ptr8Ty); + vtable = Builder.CreateGEP(vtable, + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), + AddressPoint*LLVMPointerWidth/8)); + return vtable; +} diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h new file mode 100644 index 000000000000..69fb1f100599 --- /dev/null +++ b/lib/CodeGen/CGVtable.h @@ -0,0 +1,61 @@ +//===--- CGVtable.h - Emit LLVM Code for C++ vtables ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with C++ code generation of virtual tables. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_CGVTABLE_H +#define CLANG_CODEGEN_CGVTABLE_H + +#include "llvm/ADT/DenseMap.h" + +namespace clang { + class CXXMethodDecl; + class CXXRecordDecl; + +namespace CodeGen { + class CodeGenModule; + +class CGVtableInfo { + CodeGenModule &CGM; + + /// MethodVtableIndices - Contains the index (relative to the vtable address + /// point) where the function pointer for a virtual function is stored. + typedef llvm::DenseMap MethodVtableIndicesTy; + MethodVtableIndicesTy MethodVtableIndices; + + typedef std::pair ClassPairTy; + + /// VirtualBaseClassIndicies - Contains the index into the vtable where the + /// offsets for virtual bases of a class are stored. + typedef llvm::DenseMap VirtualBaseClassIndiciesTy; + VirtualBaseClassIndiciesTy VirtualBaseClassIndicies; +public: + CGVtableInfo(CodeGenModule &CGM) + : CGM(CGM) { } + + /// getMethodVtableIndex - Return the index (relative to the vtable address + /// point) where the function pointer for the given virtual function is + /// stored. + int64_t getMethodVtableIndex(const CXXMethodDecl *MD); + + /// getVirtualBaseOffsetIndex - Return the index (relative to the vtable + /// address point) where the offset of the virtual base that contains the + /// given Base is stored, otherwise, if no virtual base contains the given + /// class, return 0. Base must be a virtual base class or an unambigious + /// base. + int64_t getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, + const CXXRecordDecl *VBase); +}; + +} +} +#endif diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index c206a3bdd208..2f46313c9c20 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -1,22 +1,27 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangCodeGen - CGBuiltin.cpp CGBlocks.cpp - CGCall.cpp + CGBuiltin.cpp CGCXX.cpp + CGCXXClass.cpp + CGCXXExpr.cpp CGCXXTemp.cpp + CGCall.cpp CGDebugInfo.cpp CGDecl.cpp + CGExpr.cpp CGExprAgg.cpp CGExprComplex.cpp CGExprConstant.cpp - CGExpr.cpp CGExprScalar.cpp CGObjC.cpp CGObjCGNU.cpp CGObjCMac.cpp + CGRecordLayoutBuilder.cpp + CGRtti.cpp CGStmt.cpp + CGVtable.cpp CodeGenFunction.cpp CodeGenModule.cpp CodeGenTypes.cpp diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index c3f9364e7ae4..5206f447f8d0 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -19,15 +19,16 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" -#include "llvm/Support/CFG.h" #include "llvm/Target/TargetData.h" using namespace clang; using namespace CodeGen; -CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) +CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) : BlockFunction(cgm, *this, Builder), CGM(cgm), Target(CGM.getContext().Target), - DebugInfo(0), SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0), + Builder(cgm.getModule().getContext()), + DebugInfo(0), IndirectGotoSwitch(0), + SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0), CXXThisDecl(0) { LLVMIntTy = ConvertType(getContext().IntTy); LLVMPointerWidth = Target.getPointerWidth(0); @@ -41,7 +42,7 @@ ASTContext &CodeGenFunction::getContext() const { llvm::BasicBlock *CodeGenFunction::getBasicBlockForLabel(const LabelStmt *S) { llvm::BasicBlock *&BB = LabelMap[S]; if (BB) return BB; - + // Create, but don't insert, the new block. return BB = createBasicBlock(S->getName()); } @@ -66,11 +67,8 @@ const llvm::Type *CodeGenFunction::ConvertType(QualType T) { } bool CodeGenFunction::hasAggregateLLVMType(QualType T) { - // FIXME: Use positive checks instead of negative ones to be more robust in - // the face of extension. - return !T->hasPointerRepresentation() &&!T->isRealType() && - !T->isVoidType() && !T->isVectorType() && !T->isFunctionType() && - !T->isBlockPointerType(); + return T->isRecordType() || T->isArrayType() || T->isAnyComplexType() || + T->isMemberFunctionPointerType(); } void CodeGenFunction::EmitReturnBlock() { @@ -81,11 +79,12 @@ void CodeGenFunction::EmitReturnBlock() { if (CurBB) { assert(!CurBB->getTerminator() && "Unexpected terminated block."); - // We have a valid insert point, reuse it if there are no explicit - // jumps to the return block. - if (ReturnBlock->use_empty()) + // We have a valid insert point, reuse it if it is empty or there are no + // explicit jumps to the return block. + if (CurBB->empty() || ReturnBlock->use_empty()) { + ReturnBlock->replaceAllUsesWith(CurBB); delete ReturnBlock; - else + } else EmitBlock(ReturnBlock); return; } @@ -94,7 +93,7 @@ void CodeGenFunction::EmitReturnBlock() { // branch then we can just put the code in that block instead. This // cleans up functions which started with a unified return block. if (ReturnBlock->hasOneUse()) { - llvm::BranchInst *BI = + llvm::BranchInst *BI = dyn_cast(*ReturnBlock->use_begin()); if (BI && BI->isUnconditional() && BI->getSuccessor(0) == ReturnBlock) { // Reset insertion point and delete the branch. @@ -113,17 +112,14 @@ void CodeGenFunction::EmitReturnBlock() { } void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { - // Finish emission of indirect switches. - EmitIndirectSwitches(); - assert(BreakContinueStack.empty() && "mismatched push/pop in break/continue stack!"); assert(BlockScopes.empty() && "did not remove all blocks from block scope map!"); assert(CleanupEntries.empty() && "mismatched push/pop in cleanup stack!"); - - // Emit function epilog (to return). + + // Emit function epilog (to return). EmitReturnBlock(); // Emit debug descriptor for function end. @@ -140,10 +136,12 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { Ptr->eraseFromParent(); } -void CodeGenFunction::StartFunction(const Decl *D, QualType RetTy, +void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, llvm::Function *Fn, const FunctionArgList &Args, SourceLocation StartLoc) { + const Decl *D = GD.getDecl(); + DidCallStackSave = false; CurCodeDecl = CurFuncDecl = D; FnRetTy = RetTy; @@ -155,28 +153,31 @@ void CodeGenFunction::StartFunction(const Decl *D, QualType RetTy, // Create a marker to make it easy to insert allocas into the entryblock // later. Don't create this with the builder, because we don't want it // folded. - llvm::Value *Undef = llvm::UndefValue::get(llvm::Type::Int32Ty); - AllocaInsertPt = new llvm::BitCastInst(Undef, llvm::Type::Int32Ty, "", + llvm::Value *Undef = llvm::UndefValue::get(llvm::Type::getInt32Ty(VMContext)); + AllocaInsertPt = new llvm::BitCastInst(Undef, + llvm::Type::getInt32Ty(VMContext), "", EntryBB); if (Builder.isNamePreserving()) AllocaInsertPt->setName("allocapt"); - + ReturnBlock = createBasicBlock("return"); ReturnValue = 0; if (!RetTy->isVoidType()) ReturnValue = CreateTempAlloca(ConvertType(RetTy), "retval"); - + Builder.SetInsertPoint(EntryBB); - + // Emit subprogram debug descriptor. // FIXME: The cast here is a huge hack. if (CGDebugInfo *DI = getDebugInfo()) { DI->setLocation(StartLoc); - if (const FunctionDecl *FD = dyn_cast(D)) { - DI->EmitFunctionStart(CGM.getMangledName(FD), RetTy, CurFn, Builder); + if (isa(D)) { + DI->EmitFunctionStart(CGM.getMangledName(GD), RetTy, CurFn, Builder); } else { // Just use LLVM function name. - DI->EmitFunctionStart(Fn->getName().c_str(), + + // FIXME: Remove unnecessary conversion to std::string when API settles. + DI->EmitFunctionStart(std::string(Fn->getName()).c_str(), RetTy, CurFn, Builder); } } @@ -184,7 +185,7 @@ void CodeGenFunction::StartFunction(const Decl *D, QualType RetTy, // FIXME: Leaked. CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args); EmitFunctionProlog(*CurFnInfo, CurFn, Args); - + // If any of the arguments have a variably modified type, make sure to // emit the type size. for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); @@ -196,40 +197,96 @@ void CodeGenFunction::StartFunction(const Decl *D, QualType RetTy, } } -void CodeGenFunction::GenerateCode(const FunctionDecl *FD, +void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { + const FunctionDecl *FD = cast(GD.getDecl()); + // Check if we should generate debug info for this function. - if (CGM.getDebugInfo() && !FD->hasAttr()) + if (CGM.getDebugInfo() && !FD->hasAttr()) DebugInfo = CGM.getDebugInfo(); - + FunctionArgList Args; - + if (const CXXMethodDecl *MD = dyn_cast(FD)) { if (MD->isInstance()) { // Create the implicit 'this' decl. // FIXME: I'm not entirely sure I like using a fake decl just for code // generation. Maybe we can come up with a better way? CXXThisDecl = ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), - &getContext().Idents.get("this"), + &getContext().Idents.get("this"), MD->getThisType(getContext())); Args.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType())); } } - + if (FD->getNumParams()) { - const FunctionProtoType* FProto = FD->getType()->getAsFunctionProtoType(); + const FunctionProtoType* FProto = FD->getType()->getAs(); assert(FProto && "Function def must have prototype!"); for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) - Args.push_back(std::make_pair(FD->getParamDecl(i), + Args.push_back(std::make_pair(FD->getParamDecl(i), FProto->getArgType(i))); } // FIXME: Support CXXTryStmt here, too. if (const CompoundStmt *S = FD->getCompoundBody()) { - StartFunction(FD, FD->getResultType(), Fn, Args, S->getLBracLoc()); + StartFunction(GD, FD->getResultType(), Fn, Args, S->getLBracLoc()); + const CXXDestructorDecl *DD = dyn_cast(FD); + llvm::BasicBlock *DtorEpilogue = 0; + if (DD) { + DtorEpilogue = createBasicBlock("dtor.epilogue"); + + PushCleanupBlock(DtorEpilogue); + } + + if (const CXXConstructorDecl *CD = dyn_cast(FD)) + EmitCtorPrologue(CD, GD.getCtorType()); EmitStmt(S); + + if (DD) { + CleanupBlockInfo Info = PopCleanupBlock(); + + assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!"); + EmitBlock(DtorEpilogue); + EmitDtorEpilogue(DD, GD.getDtorType()); + + if (Info.SwitchBlock) + EmitBlock(Info.SwitchBlock); + if (Info.EndBlock) + EmitBlock(Info.EndBlock); + } FinishFunction(S->getRBracLoc()); + } else if (FD->isImplicit()) { + const CXXRecordDecl *ClassDecl = + cast(FD->getDeclContext()); + (void) ClassDecl; + if (const CXXConstructorDecl *CD = dyn_cast(FD)) { + // FIXME: For C++0x, we want to look for implicit *definitions* of + // these special member functions, rather than implicit *declarations*. + if (CD->isCopyConstructor(getContext())) { + assert(!ClassDecl->hasUserDeclaredCopyConstructor() && + "Cannot synthesize a non-implicit copy constructor"); + SynthesizeCXXCopyConstructor(CD, GD.getCtorType(), Fn, Args); + } else if (CD->isDefaultConstructor()) { + assert(!ClassDecl->hasUserDeclaredConstructor() && + "Cannot synthesize a non-implicit default constructor."); + SynthesizeDefaultConstructor(CD, GD.getCtorType(), Fn, Args); + } else { + assert(false && "Implicit constructor cannot be synthesized"); + } + } else if (const CXXDestructorDecl *CD = dyn_cast(FD)) { + assert(!ClassDecl->hasUserDeclaredDestructor() && + "Cannot synthesize a non-implicit destructor"); + SynthesizeDefaultDestructor(CD, GD.getDtorType(), Fn, Args); + } else if (const CXXMethodDecl *MD = dyn_cast(FD)) { + assert(MD->isCopyAssignment() && + !ClassDecl->hasUserDeclaredCopyAssignment() && + "Cannot synthesize a method that is not an implicit-defined " + "copy constructor"); + SynthesizeCXXCopyAssignment(MD, Fn, Args); + } else { + assert(false && "Cannot synthesize unknown implicit function"); + } } // Destroy the 'this' declaration. @@ -243,27 +300,27 @@ void CodeGenFunction::GenerateCode(const FunctionDecl *FD, bool CodeGenFunction::ContainsLabel(const Stmt *S, bool IgnoreCaseStmts) { // Null statement, not a label! if (S == 0) return false; - + // If this is a label, we have to emit the code, consider something like: // if (0) { ... foo: bar(); } goto foo; if (isa(S)) return true; - + // If this is a case/default statement, and we haven't seen a switch, we have // to emit the code. if (isa(S) && !IgnoreCaseStmts) return true; - + // If this is a switch statement, we want to ignore cases below it. if (isa(S)) IgnoreCaseStmts = true; - + // Scan subexpressions for verboten labels. for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); I != E; ++I) if (ContainsLabel(*I, IgnoreCaseStmts)) return true; - + return false; } @@ -276,13 +333,13 @@ int CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond) { // FIXME: Rename and handle conversion of other evaluatable things // to bool. Expr::EvalResult Result; - if (!Cond->Evaluate(Result, getContext()) || !Result.Val.isInt() || + if (!Cond->Evaluate(Result, getContext()) || !Result.Val.isInt() || Result.HasSideEffects) return 0; // Not foldable, not integer or not fully evaluatable. - + if (CodeGenFunction::ContainsLabel(Cond)) return 0; // Contains a label. - + return Result.Val.getInt().getBoolValue() ? 1 : -1; } @@ -296,7 +353,7 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *FalseBlock) { if (const ParenExpr *PE = dyn_cast(Cond)) return EmitBranchOnBoolExpr(PE->getSubExpr(), TrueBlock, FalseBlock); - + if (const BinaryOperator *CondBOp = dyn_cast(Cond)) { // Handle X && Y in a condition. if (CondBOp->getOpcode() == BinaryOperator::LAnd) { @@ -306,20 +363,20 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond, // br(1 && X) -> br(X). return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock); } - + // If we have "X && 1", simplify the code to use an uncond branch. // "X && 0" would have been constant folded to 0. if (ConstantFoldsToSimpleInteger(CondBOp->getRHS()) == 1) { // br(X && 1) -> br(X). return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock); } - + // Emit the LHS as a conditional. If the LHS conditional is false, we // want to jump to the FalseBlock. llvm::BasicBlock *LHSTrue = createBasicBlock("land.lhs.true"); EmitBranchOnBoolExpr(CondBOp->getLHS(), LHSTrue, FalseBlock); EmitBlock(LHSTrue); - + EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock); return; } else if (CondBOp->getOpcode() == BinaryOperator::LOr) { @@ -329,31 +386,31 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond, // br(0 || X) -> br(X). return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock); } - + // If we have "X || 0", simplify the code to use an uncond branch. // "X || 1" would have been constant folded to 1. if (ConstantFoldsToSimpleInteger(CondBOp->getRHS()) == -1) { // br(X || 0) -> br(X). return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock); } - + // Emit the LHS as a conditional. If the LHS conditional is true, we // want to jump to the TrueBlock. llvm::BasicBlock *LHSFalse = createBasicBlock("lor.lhs.false"); EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, LHSFalse); EmitBlock(LHSFalse); - + EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock); return; } } - + if (const UnaryOperator *CondUOp = dyn_cast(Cond)) { // br(!x, t, f) -> br(x, f, t) if (CondUOp->getOpcode() == UnaryOperator::LNot) return EmitBranchOnBoolExpr(CondUOp->getSubExpr(), FalseBlock, TrueBlock); } - + if (const ConditionalOperator *CondOp = dyn_cast(Cond)) { // Handle ?: operator. @@ -376,15 +433,6 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond, Builder.CreateCondBr(CondV, TrueBlock, FalseBlock); } -/// getCGRecordLayout - Return record layout info. -const CGRecordLayout *CodeGenFunction::getCGRecordLayout(CodeGenTypes &CGT, - QualType Ty) { - const RecordType *RTy = Ty->getAsRecordType(); - assert (RTy && "Unexpected type. RecordType expected here."); - - return CGT.getCGRecordLayout(RTy->getDecl()); -} - /// ErrorUnsupported - Print out an error that codegen doesn't support the /// specified stmt yet. void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type, @@ -392,13 +440,8 @@ void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type, CGM.ErrorUnsupported(S, Type, OmitOnError); } -unsigned CodeGenFunction::GetIDForAddrOfLabel(const LabelStmt *L) { - // Use LabelIDs.size() as the new ID if one hasn't been assigned. - return LabelIDs.insert(std::make_pair(L, LabelIDs.size())).first->second; -} - void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty) { - const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext); if (DestPtr->getType() != BP) DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp"); @@ -408,93 +451,141 @@ void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty) { // Don't bother emitting a zero-byte memset. if (TypeInfo.first == 0) return; - + // FIXME: Handle variable sized types. - const llvm::Type *IntPtr = llvm::IntegerType::get(LLVMPointerWidth); + const llvm::Type *IntPtr = llvm::IntegerType::get(VMContext, + LLVMPointerWidth); Builder.CreateCall4(CGM.getMemSetFn(), DestPtr, - llvm::ConstantInt::getNullValue(llvm::Type::Int8Ty), + llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)), // TypeInfo.first describes size in bits. llvm::ConstantInt::get(IntPtr, TypeInfo.first/8), - llvm::ConstantInt::get(llvm::Type::Int32Ty, + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), TypeInfo.second/8)); } -void CodeGenFunction::EmitIndirectSwitches() { - llvm::BasicBlock *Default; +unsigned CodeGenFunction::GetIDForAddrOfLabel(const LabelStmt *L) { + // Use LabelIDs.size()+1 as the new ID if one hasn't been assigned. + unsigned &Entry = LabelIDs[L]; + if (Entry) return Entry; + + Entry = LabelIDs.size(); + + // If this is the first "address taken" of a label and the indirect goto has + // already been seen, add this to it. + if (IndirectGotoSwitch) { + // If this is the first address-taken label, set it as the default dest. + if (Entry == 1) + IndirectGotoSwitch->setSuccessor(0, getBasicBlockForLabel(L)); + else { + // Otherwise add it to the switch as a new dest. + const llvm::IntegerType *Int32Ty = llvm::Type::getInt32Ty(VMContext); + IndirectGotoSwitch->addCase(llvm::ConstantInt::get(Int32Ty, Entry), + getBasicBlockForLabel(L)); + } + } - if (IndirectSwitches.empty()) - return; + return Entry; +} + +llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() { + // If we already made the switch stmt for indirect goto, return its block. + if (IndirectGotoSwitch) return IndirectGotoSwitch->getParent(); + + EmitBlock(createBasicBlock("indirectgoto")); + + // Create the PHI node that indirect gotos will add entries to. + llvm::Value *DestVal = + Builder.CreatePHI(llvm::Type::getInt32Ty(VMContext), "indirect.goto.dest"); + + // Create the switch instruction. For now, set the insert block to this block + // which will be fixed as labels are added. + IndirectGotoSwitch = Builder.CreateSwitch(DestVal, Builder.GetInsertBlock()); + + // Clear the insertion point to indicate we are in unreachable code. + Builder.ClearInsertionPoint(); + // If we already have labels created, add them. if (!LabelIDs.empty()) { - Default = getBasicBlockForLabel(LabelIDs.begin()->first); + // Invert LabelID's so that the order is determinstic. + std::vector AddrTakenLabelsByID; + AddrTakenLabelsByID.resize(LabelIDs.size()); + + for (std::map::iterator + LI = LabelIDs.begin(), LE = LabelIDs.end(); LI != LE; ++LI) { + assert(LI->second-1 < AddrTakenLabelsByID.size() && + "Numbering inconsistent"); + AddrTakenLabelsByID[LI->second-1] = LI->first; + } + + // Set the default entry as the first block. + IndirectGotoSwitch->setSuccessor(0, + getBasicBlockForLabel(AddrTakenLabelsByID[0])); + + const llvm::IntegerType *Int32Ty = llvm::Type::getInt32Ty(VMContext); + + // FIXME: The iteration order of this is nondeterminstic! + for (unsigned i = 1, e = AddrTakenLabelsByID.size(); i != e; ++i) + IndirectGotoSwitch->addCase(llvm::ConstantInt::get(Int32Ty, i+1), + getBasicBlockForLabel(AddrTakenLabelsByID[i])); } else { - // No possible targets for indirect goto, just emit an infinite - // loop. - Default = createBasicBlock("indirectgoto.loop", CurFn); - llvm::BranchInst::Create(Default, Default); + // Otherwise, create a dead block and set it as the default dest. This will + // be removed by the optimizers after the indirect goto is set up. + llvm::BasicBlock *Dummy = createBasicBlock("indgoto.dummy"); + EmitBlock(Dummy); + IndirectGotoSwitch->setSuccessor(0, Dummy); + Builder.CreateUnreachable(); + Builder.ClearInsertionPoint(); } - for (std::vector::iterator i = IndirectSwitches.begin(), - e = IndirectSwitches.end(); i != e; ++i) { - llvm::SwitchInst *I = *i; - - I->setSuccessor(0, Default); - for (std::map::iterator LI = LabelIDs.begin(), - LE = LabelIDs.end(); LI != LE; ++LI) { - I->addCase(llvm::ConstantInt::get(llvm::Type::Int32Ty, - LI->second), - getBasicBlockForLabel(LI->first)); - } - } + return IndirectGotoSwitch->getParent(); } -llvm::Value *CodeGenFunction::GetVLASize(const VariableArrayType *VAT) -{ - llvm::Value *&SizeEntry = VLASizeMap[VAT]; - +llvm::Value *CodeGenFunction::GetVLASize(const VariableArrayType *VAT) { + llvm::Value *&SizeEntry = VLASizeMap[VAT->getSizeExpr()]; + assert(SizeEntry && "Did not emit size for type"); return SizeEntry; } -llvm::Value *CodeGenFunction::EmitVLASize(QualType Ty) -{ +llvm::Value *CodeGenFunction::EmitVLASize(QualType Ty) { assert(Ty->isVariablyModifiedType() && "Must pass variably modified type to EmitVLASizes!"); - + + EnsureInsertPoint(); + if (const VariableArrayType *VAT = getContext().getAsVariableArrayType(Ty)) { - llvm::Value *&SizeEntry = VLASizeMap[VAT]; - + llvm::Value *&SizeEntry = VLASizeMap[VAT->getSizeExpr()]; + if (!SizeEntry) { + const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); + // Get the element size; - llvm::Value *ElemSize; - QualType ElemTy = VAT->getElementType(); - - const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); - + llvm::Value *ElemSize; if (ElemTy->isVariableArrayType()) ElemSize = EmitVLASize(ElemTy); - else { + else ElemSize = llvm::ConstantInt::get(SizeTy, getContext().getTypeSize(ElemTy) / 8); - } - + llvm::Value *NumElements = EmitScalarExpr(VAT->getSizeExpr()); NumElements = Builder.CreateIntCast(NumElements, SizeTy, false, "tmp"); - + SizeEntry = Builder.CreateMul(ElemSize, NumElements); } - + return SizeEntry; - } else if (const ArrayType *AT = dyn_cast(Ty)) { + } + + if (const ArrayType *AT = dyn_cast(Ty)) { EmitVLASize(AT->getElementType()); - } else if (const PointerType *PT = Ty->getAsPointerType()) - EmitVLASize(PT->getPointeeType()); - else { - assert(0 && "unknown VM type!"); + return 0; } - + + const PointerType *PT = Ty->getAs(); + assert(PT && "unknown VM type!"); + EmitVLASize(PT->getPointeeType()); return 0; } @@ -505,32 +596,29 @@ llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) { return EmitLValue(E).getAddress(); } -void CodeGenFunction::PushCleanupBlock(llvm::BasicBlock *CleanupBlock) -{ +void CodeGenFunction::PushCleanupBlock(llvm::BasicBlock *CleanupBlock) { CleanupEntries.push_back(CleanupEntry(CleanupBlock)); } -void CodeGenFunction::EmitCleanupBlocks(size_t OldCleanupStackSize) -{ - assert(CleanupEntries.size() >= OldCleanupStackSize && +void CodeGenFunction::EmitCleanupBlocks(size_t OldCleanupStackSize) { + assert(CleanupEntries.size() >= OldCleanupStackSize && "Cleanup stack mismatch!"); - + while (CleanupEntries.size() > OldCleanupStackSize) EmitCleanupBlock(); } -CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() -{ +CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() { CleanupEntry &CE = CleanupEntries.back(); - + llvm::BasicBlock *CleanupBlock = CE.CleanupBlock; - + std::vector Blocks; std::swap(Blocks, CE.Blocks); - + std::vector BranchFixups; std::swap(BranchFixups, CE.BranchFixups); - + CleanupEntries.pop_back(); // Check if any branch fixups pointed to the scope we just popped. If so, @@ -538,12 +626,12 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() for (size_t i = 0, e = BranchFixups.size(); i != e; ++i) { llvm::BasicBlock *Dest = BranchFixups[i]->getSuccessor(0); BlockScopeMap::iterator I = BlockScopes.find(Dest); - + if (I == BlockScopes.end()) continue; - + assert(I->second <= CleanupEntries.size() && "Invalid branch fixup!"); - + if (I->second == CleanupEntries.size()) { // We don't need to do this branch fixup. BranchFixups[i] = BranchFixups.back(); @@ -553,32 +641,32 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() continue; } } - + llvm::BasicBlock *SwitchBlock = 0; llvm::BasicBlock *EndBlock = 0; if (!BranchFixups.empty()) { SwitchBlock = createBasicBlock("cleanup.switch"); EndBlock = createBasicBlock("cleanup.end"); - + llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); - + Builder.SetInsertPoint(SwitchBlock); - llvm::Value *DestCodePtr = CreateTempAlloca(llvm::Type::Int32Ty, + llvm::Value *DestCodePtr = CreateTempAlloca(llvm::Type::getInt32Ty(VMContext), "cleanup.dst"); llvm::Value *DestCode = Builder.CreateLoad(DestCodePtr, "tmp"); - + // Create a switch instruction to determine where to jump next. - llvm::SwitchInst *SI = Builder.CreateSwitch(DestCode, EndBlock, + llvm::SwitchInst *SI = Builder.CreateSwitch(DestCode, EndBlock, BranchFixups.size()); // Restore the current basic block (if any) if (CurBB) { Builder.SetInsertPoint(CurBB); - + // If we had a current basic block, we also need to emit an instruction // to initialize the cleanup destination. - Builder.CreateStore(llvm::Constant::getNullValue(llvm::Type::Int32Ty), + Builder.CreateStore(llvm::Constant::getNullValue(llvm::Type::getInt32Ty(VMContext)), DestCodePtr); } else Builder.ClearInsertionPoint(); @@ -586,39 +674,39 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() for (size_t i = 0, e = BranchFixups.size(); i != e; ++i) { llvm::BranchInst *BI = BranchFixups[i]; llvm::BasicBlock *Dest = BI->getSuccessor(0); - + // Fixup the branch instruction to point to the cleanup block. BI->setSuccessor(0, CleanupBlock); - + if (CleanupEntries.empty()) { llvm::ConstantInt *ID; - + // Check if we already have a destination for this block. if (Dest == SI->getDefaultDest()) - ID = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); + ID = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0); else { ID = SI->findCaseDest(Dest); if (!ID) { // No code found, get a new unique one by using the number of // switch successors. - ID = llvm::ConstantInt::get(llvm::Type::Int32Ty, + ID = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), SI->getNumSuccessors()); SI->addCase(ID, Dest); } } - + // Store the jump destination before the branch instruction. new llvm::StoreInst(ID, DestCodePtr, BI); } else { // We need to jump through another cleanup block. Create a pad block // with a branch instruction that jumps to the final destination and // add it as a branch fixup to the current cleanup scope. - + // Create the pad block. llvm::BasicBlock *CleanupPad = createBasicBlock("cleanup.pad", CurFn); // Create a unique case ID. - llvm::ConstantInt *ID = llvm::ConstantInt::get(llvm::Type::Int32Ty, + llvm::ConstantInt *ID = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), SI->getNumSuccessors()); // Store the jump destination before the branch instruction. @@ -626,89 +714,86 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() // Add it as the destination. SI->addCase(ID, CleanupPad); - + // Create the branch to the final destination. llvm::BranchInst *BI = llvm::BranchInst::Create(Dest); CleanupPad->getInstList().push_back(BI); - + // And add it as a branch fixup. CleanupEntries.back().BranchFixups.push_back(BI); } } } - + // Remove all blocks from the block scope map. for (size_t i = 0, e = Blocks.size(); i != e; ++i) { assert(BlockScopes.count(Blocks[i]) && "Did not find block in scope map!"); - + BlockScopes.erase(Blocks[i]); } - + return CleanupBlockInfo(CleanupBlock, SwitchBlock, EndBlock); } -void CodeGenFunction::EmitCleanupBlock() -{ +void CodeGenFunction::EmitCleanupBlock() { CleanupBlockInfo Info = PopCleanupBlock(); - + llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); - if (CurBB && !CurBB->getTerminator() && + if (CurBB && !CurBB->getTerminator() && Info.CleanupBlock->getNumUses() == 0) { CurBB->getInstList().splice(CurBB->end(), Info.CleanupBlock->getInstList()); delete Info.CleanupBlock; - } else + } else EmitBlock(Info.CleanupBlock); - + if (Info.SwitchBlock) EmitBlock(Info.SwitchBlock); if (Info.EndBlock) EmitBlock(Info.EndBlock); } -void CodeGenFunction::AddBranchFixup(llvm::BranchInst *BI) -{ - assert(!CleanupEntries.empty() && +void CodeGenFunction::AddBranchFixup(llvm::BranchInst *BI) { + assert(!CleanupEntries.empty() && "Trying to add branch fixup without cleanup block!"); - + // FIXME: We could be more clever here and check if there's already a branch // fixup for this destination and recycle it. CleanupEntries.back().BranchFixups.push_back(BI); } -void CodeGenFunction::EmitBranchThroughCleanup(llvm::BasicBlock *Dest) -{ +void CodeGenFunction::EmitBranchThroughCleanup(llvm::BasicBlock *Dest) { if (!HaveInsertPoint()) return; - + llvm::BranchInst* BI = Builder.CreateBr(Dest); - + Builder.ClearInsertionPoint(); - + // The stack is empty, no need to do any cleanup. if (CleanupEntries.empty()) return; - + if (!Dest->getParent()) { // We are trying to branch to a block that hasn't been inserted yet. AddBranchFixup(BI); return; } - + BlockScopeMap::iterator I = BlockScopes.find(Dest); if (I == BlockScopes.end()) { // We are trying to jump to a block that is outside of any cleanup scope. AddBranchFixup(BI); return; } - + assert(I->second < CleanupEntries.size() && "Trying to branch into cleanup region"); - + if (I->second == CleanupEntries.size() - 1) { // We have a branch to a block in the same scope. return; } - + AddBranchFixup(BI); } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 72c4aa4a658a..722d002c19f5 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -22,6 +22,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Support/ValueHandle.h" #include +#include "CodeGenModule.h" #include "CGBlocks.h" #include "CGBuilder.h" #include "CGCall.h" @@ -30,6 +31,7 @@ namespace llvm { class BasicBlock; + class LLVMContext; class Module; class SwitchInst; class Value; @@ -38,6 +40,7 @@ namespace llvm { namespace clang { class ASTContext; class CXXDestructorDecl; + class CXXTryStmt; class Decl; class EnumConstantDecl; class FunctionDecl; @@ -145,7 +148,11 @@ public: ~CleanupScope() { CGF.PushCleanupBlock(CleanupBB); - CGF.Builder.SetInsertPoint(CurBB); + // FIXME: This is silly, move this into the builder. + if (CurBB) + CGF.Builder.SetInsertPoint(CurBB); + else + CGF.Builder.ClearInsertionPoint(); } }; @@ -160,20 +167,20 @@ public: /// this behavior for branches? void EmitBranchThroughCleanup(llvm::BasicBlock *Dest); - /// PushConditionalTempDestruction - Should be called before a conditional + /// PushConditionalTempDestruction - Should be called before a conditional /// part of an expression is emitted. For example, before the RHS of the /// expression below is emitted: - /// + /// /// b && f(T()); /// /// This is used to make sure that any temporaryes created in the conditional /// branch are only destroyed if the branch is taken. void PushConditionalTempDestruction(); - - /// PopConditionalTempDestruction - Should be called after a conditional + + /// PopConditionalTempDestruction - Should be called after a conditional /// part of an expression has been emitted. void PopConditionalTempDestruction(); - + private: CGDebugInfo* DebugInfo; @@ -182,10 +189,12 @@ private: /// labels inside getIDForAddrOfLabel(). std::map LabelIDs; - /// IndirectSwitches - Record the list of switches for indirect - /// gotos. Emission of the actual switching code needs to be delayed until all - /// AddrLabelExprs have been seen. - std::vector IndirectSwitches; + /// IndirectGotoSwitch - The first time an indirect goto is seen we create a + /// block with the switch for the indirect gotos. Every time we see the + /// address of a label taken, we add the label to the indirect goto. Every + /// subsequent indirect goto is codegen'd as a jump to the + /// IndirectGotoSwitch's basic block. + llvm::SwitchInst *IndirectGotoSwitch; /// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C /// decls. @@ -218,9 +227,12 @@ private: llvm::BasicBlock *InvokeDest; // VLASizeMap - This keeps track of the associated size for each VLA type. + // We track this by the size expression rather than the type itself because + // in certain situations, like a const qualifier applied to an VLA typedef, + // multiple VLA types can share the same size expression. // FIXME: Maybe this could be a stack of maps that is pushed/popped as we // enter/leave scopes. - llvm::DenseMap VLASizeMap; + llvm::DenseMap VLASizeMap; /// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid /// calling llvm.stacksave for multiple VLAs in the same scope. @@ -252,36 +264,46 @@ private: /// CXXThisDecl - When parsing an C++ function, this will hold the implicit /// 'this' declaration. ImplicitParamDecl *CXXThisDecl; - + /// CXXLiveTemporaryInfo - Holds information about a live C++ temporary. struct CXXLiveTemporaryInfo { /// Temporary - The live temporary. const CXXTemporary *Temporary; - + /// ThisPtr - The pointer to the temporary. llvm::Value *ThisPtr; - + /// DtorBlock - The destructor block. llvm::BasicBlock *DtorBlock; - + /// CondPtr - If this is a conditional temporary, this is the pointer to /// the condition variable that states whether the destructor should be /// called or not. llvm::Value *CondPtr; - + CXXLiveTemporaryInfo(const CXXTemporary *temporary, llvm::Value *thisptr, llvm::BasicBlock *dtorblock, llvm::Value *condptr) - : Temporary(temporary), ThisPtr(thisptr), DtorBlock(dtorblock), + : Temporary(temporary), ThisPtr(thisptr), DtorBlock(dtorblock), CondPtr(condptr) { } }; - + llvm::SmallVector LiveTemporaries; - /// ConditionalTempDestructionStack - Contains the number of live temporaries + /// ConditionalTempDestructionStack - Contains the number of live temporaries /// when PushConditionalTempDestruction was called. This is used so that /// we know how many temporaries were created by a certain expression. llvm::SmallVector ConditionalTempDestructionStack; + + + /// ByrefValueInfoMap - For each __block variable, contains a pair of the LLVM + /// type as well as the field number that contains the actual data. + llvm::DenseMap > ByRefValueInfo; + + /// getByrefValueFieldNumber - Given a declaration, returns the LLVM field + /// number that holds the value. + unsigned getByRefValueLLVMField(const ValueDecl *VD) const; public: CodeGenFunction(CodeGenModule &cgm); @@ -292,6 +314,8 @@ public: llvm::BasicBlock *getInvokeDest() { return InvokeDest; } void setInvokeDest(llvm::BasicBlock *B) { InvokeDest = B; } + llvm::LLVMContext &getLLVMContext() { return VMContext; } + //===--------------------------------------------------------------------===// // Objective-C //===--------------------------------------------------------------------===// @@ -332,12 +356,10 @@ public: llvm::Value *LoadBlockStruct(); llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E); + const llvm::Type *BuildByRefType(const ValueDecl *D); - const llvm::Type *BuildByRefType(QualType Ty, uint64_t Align); - - void GenerateCode(const FunctionDecl *FD, - llvm::Function *Fn); - void StartFunction(const Decl *D, QualType RetTy, + void GenerateCode(GlobalDecl GD, llvm::Function *Fn); + void StartFunction(GlobalDecl GD, QualType RetTy, llvm::Function *Fn, const FunctionArgList &Args, SourceLocation StartLoc); @@ -350,6 +372,44 @@ public: /// legal to call this function even if there is no current insertion point. void FinishFunction(SourceLocation EndLoc=SourceLocation()); + /// GenerateVtable - Generate the vtable for the given type. + llvm::Value *GenerateVtable(const CXXRecordDecl *RD); + + /// GenerateThunk - Generate a thunk for the given method + llvm::Constant *GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD, + bool Extern, int64_t nv, int64_t v); + llvm::Constant *GenerateCovariantThunk(llvm::Function *Fn, + const CXXMethodDecl *MD, bool Extern, + int64_t nv_t, int64_t v_t, + int64_t nv_r, int64_t v_r); + + void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type); + + void SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, + CXXCtorType Type, + llvm::Function *Fn, + const FunctionArgList &Args); + + void SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD, + llvm::Function *Fn, + const FunctionArgList &Args); + + void SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor, + CXXCtorType Type, + llvm::Function *Fn, + const FunctionArgList &Args); + + void SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor, + CXXDtorType Type, + llvm::Function *Fn, + const FunctionArgList &Args); + + /// EmitDtorEpilogue - Emit all code that comes at the end of class's + /// destructor. This is to call destructors on members and base classes + /// in reverse order of their construction. + void EmitDtorEpilogue(const CXXDestructorDecl *Dtor, + CXXDtorType Type); + /// EmitFunctionProlog - Emit the target specific LLVM code to load the /// arguments for the given function. This is also responsible for naming the /// LLVM function arguments. @@ -380,9 +440,9 @@ public: llvm::Function *Parent=0, llvm::BasicBlock *InsertBefore=0) { #ifdef NDEBUG - return llvm::BasicBlock::Create("", Parent, InsertBefore); + return llvm::BasicBlock::Create(VMContext, "", Parent, InsertBefore); #else - return llvm::BasicBlock::Create(Name, Parent, InsertBefore); + return llvm::BasicBlock::Create(VMContext, Name, Parent, InsertBefore); #endif } @@ -439,6 +499,12 @@ public: // Helpers //===--------------------------------------------------------------------===// + Qualifiers MakeQualifiers(QualType T) { + Qualifiers Quals = T.getQualifiers(); + Quals.setObjCGCAttr(getContext().getObjCGCAttrKind(T)); + return Quals; + } + /// CreateTempAlloca - This creates a alloca and inserts it into the entry /// block. llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty, @@ -455,7 +521,8 @@ public: /// /// \param IgnoreResult - True if the resulting value isn't used. RValue EmitAnyExpr(const Expr *E, llvm::Value *AggLoc = 0, - bool isAggLocVolatile = false, bool IgnoreResult = false); + bool IsAggLocVolatile = false, bool IgnoreResult = false, + bool IsInitializer = false); // EmitVAListRef - Emit a "reference" to a va_list; this is either the address // or the value of the expression, depending on how va_list is defined. @@ -463,8 +530,8 @@ public: /// EmitAnyExprToTemp - Similary to EmitAnyExpr(), however, the result will /// always be accessible even if no aggregate location is provided. - RValue EmitAnyExprToTemp(const Expr *E, llvm::Value *AggLoc = 0, - bool isAggLocVolatile = false); + RValue EmitAnyExprToTemp(const Expr *E, bool IsAggLocVolatile = false, + bool IsInitializer = false); /// EmitAggregateCopy - Emit an aggrate copy. /// @@ -479,9 +546,6 @@ public: /// then reuse it. void StartBlock(const char *N); - /// getCGRecordLayout - Return record layout info. - const CGRecordLayout *getCGRecordLayout(CodeGenTypes &CGT, QualType RTy); - /// GetAddrOfStaticLocalVar - Return the address of a static local variable. llvm::Constant *GetAddrOfStaticLocalVar(const VarDecl *BVD); @@ -493,6 +557,7 @@ public: static unsigned getAccessedFieldNo(unsigned Idx, const llvm::Constant *Elts); unsigned GetIDForAddrOfLabel(const LabelStmt *L); + llvm::BasicBlock *GetIndirectGotoBlock(); /// EmitMemSetToZero - Generate code to memset a value of the given type to 0. void EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty); @@ -506,6 +571,8 @@ public: // EmitVLASize - Generate code for any VLA size expressions that might occur // in a variably modified type. If Ty is a VLA, will return the value that // corresponds to the size in bytes of the VLA type. Will return 0 otherwise. + /// + /// This function can be called with a null (unreachable) insert point. llvm::Value *EmitVLASize(QualType Ty); // GetVLASize - Returns an LLVM value that corresponds to the size in bytes @@ -515,27 +582,87 @@ public: /// LoadCXXThis - Load the value of 'this'. This function is only valid while /// generating code for an C++ member function. llvm::Value *LoadCXXThis(); + + /// GetAddressCXXOfBaseClass - 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 *GetAddressCXXOfBaseClass(llvm::Value *BaseValue, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl, + bool NullCheckValue); - void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type, + llvm::Value * + GetVirtualCXXBaseClassOffset(llvm::Value *This, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl); + + void EmitClassAggrMemberwiseCopy(llvm::Value *DestValue, + llvm::Value *SrcValue, + const ArrayType *Array, + const CXXRecordDecl *BaseClassDecl, + QualType Ty); + + void EmitClassAggrCopyAssignment(llvm::Value *DestValue, + llvm::Value *SrcValue, + const ArrayType *Array, + const CXXRecordDecl *BaseClassDecl, + QualType Ty); + + void EmitClassMemberwiseCopy(llvm::Value *DestValue, llvm::Value *SrcValue, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl, + QualType Ty); + + void EmitClassCopyAssignment(llvm::Value *DestValue, llvm::Value *SrcValue, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl, + QualType Ty); + + void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd); + void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, + const ConstantArrayType *ArrayTy, + llvm::Value *ArrayPtr); + void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, + llvm::Value *NumElements, + llvm::Value *ArrayPtr); + + void EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, + const ArrayType *Array, + llvm::Value *This); + void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type, llvm::Value *This); - + void PushCXXTemporary(const CXXTemporary *Temporary, llvm::Value *Ptr); void PopCXXTemporary(); - + llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E); - + void EmitCXXDeleteExpr(const CXXDeleteExpr *E); + //===--------------------------------------------------------------------===// // Declaration Emission //===--------------------------------------------------------------------===// + /// EmitDecl - Emit a declaration. + /// + /// This function can be called with a null (unreachable) insert point. void EmitDecl(const Decl &D); + + /// EmitBlockVarDecl - Emit a block variable declaration. + /// + /// This function can be called with a null (unreachable) insert point. void EmitBlockVarDecl(const VarDecl &D); + + /// EmitLocalBlockVarDecl - Emit a local block variable declaration. + /// + /// This function can be called with a null (unreachable) insert point. void EmitLocalBlockVarDecl(const VarDecl &D); + void EmitStaticBlockVarDecl(const VarDecl &D); /// EmitParmDecl - Emit a ParmVarDecl or an ImplicitParamDecl. @@ -593,6 +720,8 @@ public: void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S); void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S); + void EmitCXXTryStmt(const CXXTryStmt &S); + //===--------------------------------------------------------------------===// // LValue Expression Emission //===--------------------------------------------------------------------===// @@ -685,7 +814,7 @@ public: LValue EmitExtVectorElementExpr(const ExtVectorElementExpr *E); LValue EmitMemberExpr(const MemberExpr *E); LValue EmitCompoundLiteralLValue(const CompoundLiteralExpr *E); - LValue EmitConditionalOperator(const ConditionalOperator *E); + LValue EmitConditionalOperatorLValue(const ConditionalOperator *E); LValue EmitCastLValue(const CastExpr *E); llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface, @@ -704,11 +833,12 @@ public: LValue EmitCXXConditionDeclLValue(const CXXConditionDeclExpr *E); LValue EmitCXXConstructLValue(const CXXConstructExpr *E); LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E); + LValue EmitCXXExprWithTemporariesLValue(const CXXExprWithTemporaries *E); LValue EmitObjCMessageExprLValue(const ObjCMessageExpr *E); LValue EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E); LValue EmitObjCPropertyRefLValue(const ObjCPropertyRefExpr *E); - LValue EmitObjCKVCRefLValue(const ObjCKVCRefExpr *E); + LValue EmitObjCKVCRefLValue(const ObjCImplicitSetterGetterRefExpr *E); LValue EmitObjCSuperExprLValue(const ObjCSuperExpr *E); LValue EmitStmtExprLValue(const StmtExpr *E); @@ -727,24 +857,28 @@ public: llvm::Value *Callee, const CallArgList &Args, const Decl *TargetDecl = 0); - + RValue EmitCall(llvm::Value *Callee, QualType FnType, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd, const Decl *TargetDecl = 0); RValue EmitCallExpr(const CallExpr *E); - + + llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *&This, + const llvm::Type *Ty); RValue EmitCXXMemberCall(const CXXMethodDecl *MD, llvm::Value *Callee, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd); RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E); + RValue EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E); RValue EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, const CXXMethodDecl *MD); + - RValue EmitBuiltinExpr(const FunctionDecl *FD, + RValue EmitBuiltinExpr(const FunctionDecl *FD, unsigned BuiltinID, const CallExpr *E); RValue EmitBlockCallExpr(const CallExpr *E); @@ -772,8 +906,9 @@ 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); - + RValue EmitReferenceBindingToExpr(const Expr* E, QualType DestType, + bool IsInitializer = false); + //===--------------------------------------------------------------------===// // Expression Emission //===--------------------------------------------------------------------===// @@ -782,7 +917,7 @@ public: /// EmitScalarExpr - Emit the computation of the specified expression of LLVM /// scalar type, returning the result. - llvm::Value *EmitScalarExpr(const Expr *E , bool IgnoreResultAssign=false); + llvm::Value *EmitScalarExpr(const Expr *E , bool IgnoreResultAssign = false); /// EmitScalarConversion - Emit a conversion from the specified type to the /// specified destination type, both of which are LLVM scalar types. @@ -800,7 +935,13 @@ public: /// aggregate type. The result is computed into DestPtr. Note that if /// DestPtr is null, the value of the aggregate expression is not needed. void EmitAggExpr(const Expr *E, llvm::Value *DestPtr, bool VolatileDest, - bool IgnoreResult = false); + bool IgnoreResult = false, bool IsInitializer = false, + bool RequiresGCollection = false); + + /// EmitGCMemmoveCollectable - Emit special API for structs with object + /// pointers. + void EmitGCMemmoveCollectable(llvm::Value *DestPtr, llvm::Value *SrcPtr, + QualType Ty); /// EmitComplexExpr - Emit the computation of the specified expression of /// complex type, returning the result. @@ -827,17 +968,33 @@ public: llvm::GlobalValue::LinkageTypes Linkage); - /// GenerateStaticCXXBlockVarDecl - Create the initializer for a C++ + /// EmitStaticCXXBlockVarDeclInit - Create the initializer for a C++ /// runtime initialized static block var decl. - void GenerateStaticCXXBlockVarDeclInit(const VarDecl &D, - llvm::GlobalVariable *GV); + void EmitStaticCXXBlockVarDeclInit(const VarDecl &D, + llvm::GlobalVariable *GV); + + /// EmitCXXGlobalVarDeclInit - Create the initializer for a C++ + /// variable with global storage. + void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::Constant *DeclPtr); + + /// EmitCXXGlobalDtorRegistration - Emits a call to register the global ptr + /// with the C++ runtime so that its destructor will be called at exit. + void EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor, + llvm::Constant *DeclPtr); + + /// GenerateCXXGlobalInitFunc - Generates code for initializing global + /// variables. + void GenerateCXXGlobalInitFunc(llvm::Function *Fn, + const VarDecl **Decls, + unsigned NumDecls); void EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E); - + RValue EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E, - llvm::Value *AggLoc = 0, - bool isAggLocVolatile = false); - + llvm::Value *AggLoc = 0, + bool IsAggLocVolatile = false, + bool IsInitializer = false); + //===--------------------------------------------------------------------===// // Internal Helpers //===--------------------------------------------------------------------===// @@ -860,10 +1017,6 @@ public: llvm::BasicBlock *FalseBlock); private: - /// EmitIndirectSwitches - Emit code for all of the switch - /// instructions in IndirectSwitches. - void EmitIndirectSwitches(); - void EmitReturnOfRValue(RValue RV, QualType Ty); /// ExpandTypeFromArgs - Reconstruct a structure of type \arg Ty @@ -882,7 +1035,7 @@ private: void ExpandTypeToArgs(QualType Ty, RValue Src, llvm::SmallVector &Args); - llvm::Value* EmitAsmInput(const AsmStmt &S, + llvm::Value* EmitAsmInput(const AsmStmt &S, const TargetInfo::ConstraintInfo &Info, const Expr *InputExpr, std::string &ConstraintStr); @@ -895,9 +1048,9 @@ private: /// EmitCallArg - Emit a single call argument. RValue EmitCallArg(const Expr *E, QualType ArgType); - + /// EmitCallArgs - Emit call arguments for a function. - /// The CallArgTypeInfo parameter is used for iterating over the known + /// The CallArgTypeInfo parameter is used for iterating over the known /// argument types of the function being called. template void EmitCallArgs(CallArgList& Args, const T* CallArgTypeInfo, @@ -912,21 +1065,21 @@ private: QualType ArgType = *I; assert(getContext().getCanonicalType(ArgType.getNonReferenceType()). - getTypePtr() == - getContext().getCanonicalType(Arg->getType()).getTypePtr() && + getTypePtr() == + getContext().getCanonicalType(Arg->getType()).getTypePtr() && "type mismatch in call argument!"); - - Args.push_back(std::make_pair(EmitCallArg(*Arg, ArgType), + + Args.push_back(std::make_pair(EmitCallArg(*Arg, ArgType), ArgType)); } - - // Either we've emitted all the call args, or we have a call to a + + // Either we've emitted all the call args, or we have a call to a // variadic function. - assert((Arg == ArgEnd || CallArgTypeInfo->isVariadic()) && + assert((Arg == ArgEnd || CallArgTypeInfo->isVariadic()) && "Extra arguments in non-variadic function!"); - + } - + // If we still have any arguments, emit them using the type of the argument. for (; Arg != ArgEnd; ++Arg) { QualType ArgType = Arg->getType(); @@ -935,7 +1088,7 @@ private: } } }; - + } // end namespace CodeGen } // end namespace clang diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index d88a37a45b23..36ad7f514ec8 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -39,8 +39,10 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CompileOptions &compileOpts, Diagnostic &diags) : BlockModule(C, M, TD, Types, *this), Context(C), Features(C.getLangOptions()), CompileOpts(compileOpts), TheModule(M), - TheTargetData(TD), Diags(diags), Types(C, M, TD), Runtime(0), - MemCpyFn(0), MemMoveFn(0), MemSetFn(0), CFConstantStringClassRef(0) { + TheTargetData(TD), Diags(diags), Types(C, M, TD), MangleCtx(C), + VtableInfo(*this), Runtime(0), + MemCpyFn(0), MemMoveFn(0), MemSetFn(0), CFConstantStringClassRef(0), + VMContext(M.getContext()) { if (!Features.ObjC1) Runtime = 0; @@ -61,6 +63,9 @@ CodeGenModule::~CodeGenModule() { } void CodeGenModule::Release() { + // We need to call this first because it can add deferred declarations. + EmitCXXGlobalInitFunc(); + EmitDeferred(); if (Runtime) if (llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction()) @@ -77,7 +82,7 @@ void CodeGenModule::ErrorUnsupported(const Stmt *S, const char *Type, bool OmitOnError) { if (OmitOnError && getDiags().hasErrorOccurred()) return; - unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Error, + unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Error, "cannot compile this %0 yet"); std::string Msg = Type; getDiags().Report(Context.getFullLoc(S->getLocStart()), DiagID) @@ -90,13 +95,13 @@ void CodeGenModule::ErrorUnsupported(const Decl *D, const char *Type, bool OmitOnError) { if (OmitOnError && getDiags().hasErrorOccurred()) return; - unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Error, + unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Error, "cannot compile this %0 yet"); std::string Msg = Type; getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID) << Msg; } -LangOptions::VisibilityMode +LangOptions::VisibilityMode CodeGenModule::getDeclVisibilityMode(const Decl *D) const { if (const VarDecl *VD = dyn_cast(D)) if (VD->getStorageClass() == VarDecl::PrivateExtern) @@ -105,7 +110,7 @@ CodeGenModule::getDeclVisibilityMode(const Decl *D) const { if (const VisibilityAttr *attr = D->getAttr()) { switch (attr->getVisibility()) { default: assert(0 && "Unknown visibility!"); - case VisibilityAttr::DefaultVisibility: + case VisibilityAttr::DefaultVisibility: return LangOptions::Default; case VisibilityAttr::HiddenVisibility: return LangOptions::Hidden; @@ -117,7 +122,7 @@ CodeGenModule::getDeclVisibilityMode(const Decl *D) const { return getLangOptions().getVisibilityMode(); } -void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV, +void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV, const Decl *D) const { // Internal definitions always have default visibility. if (GV->hasLocalLinkage()) { @@ -137,13 +142,13 @@ void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV, } const char *CodeGenModule::getMangledName(const GlobalDecl &GD) { - const NamedDecl *ND = GD.getDecl(); - + const NamedDecl *ND = cast(GD.getDecl()); + if (const CXXConstructorDecl *D = dyn_cast(ND)) return getMangledCXXCtorName(D, GD.getCtorType()); if (const CXXDestructorDecl *D = dyn_cast(ND)) return getMangledCXXDtorName(D, GD.getDtorType()); - + return getMangledName(ND); } @@ -159,10 +164,10 @@ const char *CodeGenModule::getMangledName(const NamedDecl *ND) { assert(ND->getIdentifier() && "Attempt to mangle unnamed decl."); return ND->getNameAsCString(); } - + llvm::SmallString<256> Name; llvm::raw_svector_ostream Out(Name); - if (!mangleName(ND, Context, Out)) { + if (!mangleName(getMangleContext(), ND, Out)) { assert(ND->getIdentifier() && "Attempt to mangle unnamed decl."); return ND->getNameAsCString(); } @@ -174,7 +179,7 @@ const char *CodeGenModule::getMangledName(const NamedDecl *ND) { const char *CodeGenModule::UniqueMangledName(const char *NameStart, const char *NameEnd) { assert(*(NameEnd - 1) == '\0' && "Mangled name must be null terminated!"); - + return MangledNames.GetOrCreateValue(NameStart, NameEnd).getKeyData(); } @@ -195,32 +200,32 @@ void CodeGenModule::AddGlobalDtor(llvm::Function * Dtor, int Priority) { void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) { // Ctor function type is void()*. llvm::FunctionType* CtorFTy = - llvm::FunctionType::get(llvm::Type::VoidTy, + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), std::vector(), false); llvm::Type *CtorPFTy = llvm::PointerType::getUnqual(CtorFTy); // Get the type of a ctor entry, { i32, void ()* }. - llvm::StructType* CtorStructTy = - llvm::StructType::get(llvm::Type::Int32Ty, + llvm::StructType* CtorStructTy = + llvm::StructType::get(VMContext, llvm::Type::getInt32Ty(VMContext), llvm::PointerType::getUnqual(CtorFTy), NULL); // Construct the constructor and destructor arrays. std::vector Ctors; for (CtorList::const_iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) { std::vector S; - S.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, I->second, false)); + S.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + I->second, false)); S.push_back(llvm::ConstantExpr::getBitCast(I->first, CtorPFTy)); Ctors.push_back(llvm::ConstantStruct::get(CtorStructTy, S)); } if (!Ctors.empty()) { llvm::ArrayType *AT = llvm::ArrayType::get(CtorStructTy, Ctors.size()); - new llvm::GlobalVariable(AT, false, + new llvm::GlobalVariable(TheModule, AT, false, llvm::GlobalValue::AppendingLinkage, llvm::ConstantArray::get(AT, Ctors), - GlobalName, - &TheModule); + GlobalName); } } @@ -233,67 +238,56 @@ void CodeGenModule::EmitAnnotations() { llvm::ConstantArray::get(llvm::ArrayType::get(Annotations[0]->getType(), Annotations.size()), Annotations); - llvm::GlobalValue *gv = - new llvm::GlobalVariable(Array->getType(), false, - llvm::GlobalValue::AppendingLinkage, Array, - "llvm.global.annotations", &TheModule); + llvm::GlobalValue *gv = + new llvm::GlobalVariable(TheModule, Array->getType(), false, + llvm::GlobalValue::AppendingLinkage, Array, + "llvm.global.annotations"); gv->setSection("llvm.metadata"); } static CodeGenModule::GVALinkage -GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, +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; + // 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 && - (FD->getPrimaryTemplate() || FD->getInstantiatedFromMemberFunction()) && - !FD->isExplicitSpecialization()) + FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) External = CodeGenModule::GVA_TemplateInstantiation; - + if (const CXXMethodDecl *MD = dyn_cast(FD)) { // C++ member functions defined inside the class are always inline. if (MD->isInline() || !MD->isOutOfLine()) return CodeGenModule::GVA_CXXInline; - + return External; } - + // "static" functions get internal linkage. if (FD->getStorageClass() == FunctionDecl::Static) return CodeGenModule::GVA_Internal; if (!FD->isInline()) return External; - - // If the inline function explicitly has the GNU inline attribute on it, or if - // this is C89 mode, we use to GNU semantics. - if (!Features.C99 && !Features.CPlusPlus) { - // extern inline in GNU mode is like C99 inline. - if (FD->getStorageClass() == FunctionDecl::Extern) - return CodeGenModule::GVA_C99Inline; - // Normal inline is a strong symbol. - return CodeGenModule::GVA_StrongExternal; - } else if (FD->hasActiveGNUInlineAttribute(Context)) { - // GCC in C99 mode seems to use a different decision-making - // process for extern inline, which factors in previous - // declarations. - if (FD->isExternGNUInline(Context)) - return CodeGenModule::GVA_C99Inline; - // Normal inline is a strong symbol. - return External; - } - // The definition of inline changes based on the language. Note that we - // have already handled "static inline" above, with the GVA_Internal case. - if (Features.CPlusPlus) // inline and extern inline. - return CodeGenModule::GVA_CXXInline; - - assert(Features.C99 && "Must be in C99 mode if not in C89 or C++ mode"); - if (FD->isC99InlineDefinition()) + if (!Features.CPlusPlus || FD->hasAttr()) { + // GNU or C99 inline semantics. Determine whether this symbol should be + // externally visible. + if (FD->isInlineDefinitionExternallyVisible()) + return External; + + // C99 inline semantics, where the symbol is not externally visible. return CodeGenModule::GVA_C99Inline; + } - return CodeGenModule::GVA_StrongExternal; + // C++ inline semantics + assert(Features.CPlusPlus && "Must be in C++ mode"); + return CodeGenModule::GVA_CXXInline; } /// SetFunctionDefinitionAttributes - Set attributes for a global. @@ -332,35 +326,35 @@ void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D, } void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D, - const CGFunctionInfo &Info, + const CGFunctionInfo &Info, llvm::Function *F) { + unsigned CallingConv; AttributeListType AttributeList; - ConstructAttributeList(Info, D, AttributeList); - + ConstructAttributeList(Info, D, AttributeList, CallingConv); F->setAttributes(llvm::AttrListPtr::get(AttributeList.begin(), - AttributeList.size())); - - // Set the appropriate calling convention for the Function. - if (D->hasAttr()) - F->setCallingConv(llvm::CallingConv::X86_FastCall); - - if (D->hasAttr()) - F->setCallingConv(llvm::CallingConv::X86_StdCall); + AttributeList.size())); + F->setCallingConv(static_cast(CallingConv)); } void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F) { if (!Features.Exceptions && !Features.ObjCNonFragileABI) - F->addFnAttr(llvm::Attribute::NoUnwind); + F->addFnAttr(llvm::Attribute::NoUnwind); if (D->hasAttr()) F->addFnAttr(llvm::Attribute::AlwaysInline); - - if (D->hasAttr()) + + if (D->hasAttr()) F->addFnAttr(llvm::Attribute::NoInline); + + if (const AlignedAttr *AA = D->getAttr()) + F->setAlignment(AA->getAlignment()/8); + // C++ ABI requires 2-byte alignment for member functions. + if (F->getAlignment() < 2 && isa(D)) + F->setAlignment(2); } -void CodeGenModule::SetCommonAttributes(const Decl *D, +void CodeGenModule::SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV) { setGlobalVisibility(GV, D); @@ -387,19 +381,19 @@ void CodeGenModule::SetFunctionAttributes(const FunctionDecl *FD, bool IsIncompleteFunction) { if (!IsIncompleteFunction) SetLLVMFunctionAttributes(FD, getTypes().getFunctionInfo(FD), F); - + // Only a few attributes are set on declarations; these may later be // overridden by a definition. - + if (FD->hasAttr()) { F->setLinkage(llvm::Function::DLLImportLinkage); - } else if (FD->hasAttr() || + } else if (FD->hasAttr() || FD->hasAttr()) { // "extern_weak" is overloaded in LLVM; we probably should have - // separate linkage types for this. + // separate linkage types for this. F->setLinkage(llvm::Function::ExternalWeakLinkage); } else { - F->setLinkage(llvm::Function::ExternalLinkage); + F->setLinkage(llvm::Function::ExternalLinkage); } if (const SectionAttr *SA = FD->getAttr()) @@ -407,39 +401,36 @@ void CodeGenModule::SetFunctionAttributes(const FunctionDecl *FD, } void CodeGenModule::AddUsedGlobal(llvm::GlobalValue *GV) { - assert(!GV->isDeclaration() && + assert(!GV->isDeclaration() && "Only globals with definition can force usage."); LLVMUsed.push_back(GV); } void CodeGenModule::EmitLLVMUsed() { // Don't create llvm.used if there is no need. - // FIXME. Runtime indicates that there might be more 'used' symbols; but not - // necessariy. So, this test is not accurate for emptiness. - if (LLVMUsed.empty() && !Runtime) + if (LLVMUsed.empty()) return; - llvm::Type *i8PTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); - + const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext); + // Convert LLVMUsed to what ConstantArray needs. std::vector UsedArray; UsedArray.resize(LLVMUsed.size()); for (unsigned i = 0, e = LLVMUsed.size(); i != e; ++i) { - UsedArray[i] = - llvm::ConstantExpr::getBitCast(cast(&*LLVMUsed[i]), i8PTy); + UsedArray[i] = + llvm::ConstantExpr::getBitCast(cast(&*LLVMUsed[i]), + i8PTy); } - - if (Runtime) - Runtime->MergeMetadataGlobals(UsedArray); + if (UsedArray.empty()) return; llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, UsedArray.size()); - - llvm::GlobalVariable *GV = - new llvm::GlobalVariable(ATy, false, + + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(getModule(), ATy, false, llvm::GlobalValue::AppendingLinkage, llvm::ConstantArray::get(ATy, UsedArray), - "llvm.used", &getModule()); + "llvm.used"); GV->setSection("llvm.metadata"); } @@ -458,59 +449,60 @@ void CodeGenModule::EmitDeferred() { // just ignore the deferred decl. llvm::GlobalValue *CGRef = GlobalDeclMap[getMangledName(D)]; assert(CGRef && "Deferred decl wasn't referenced?"); - + if (!CGRef->isDeclaration()) continue; - + // Otherwise, emit the definition and move on to the next one. EmitGlobalDefinition(D); } } -/// EmitAnnotateAttr - Generate the llvm::ConstantStruct which contains the +/// EmitAnnotateAttr - Generate the llvm::ConstantStruct which contains the /// annotation information for a given GlobalValue. The annotation struct is -/// {i8 *, i8 *, i8 *, i32}. The first field is a constant expression, the -/// GlobalValue being annotated. The second field is the constant string -/// created from the AnnotateAttr's annotation. The third field is a constant +/// {i8 *, i8 *, i8 *, i32}. The first field is a constant expression, the +/// GlobalValue being annotated. The second field is the constant string +/// created from the AnnotateAttr's annotation. The third field is a constant /// string containing the name of the translation unit. The fourth field is /// the line number in the file of the annotated value declaration. /// /// FIXME: this does not unique the annotation string constants, as llvm-gcc /// appears to. /// -llvm::Constant *CodeGenModule::EmitAnnotateAttr(llvm::GlobalValue *GV, +llvm::Constant *CodeGenModule::EmitAnnotateAttr(llvm::GlobalValue *GV, const AnnotateAttr *AA, unsigned LineNo) { llvm::Module *M = &getModule(); // get [N x i8] constants for the annotation string, and the filename string // which are the 2nd and 3rd elements of the global annotation structure. - const llvm::Type *SBP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); - llvm::Constant *anno = llvm::ConstantArray::get(AA->getAnnotation(), true); - llvm::Constant *unit = llvm::ConstantArray::get(M->getModuleIdentifier(), + const llvm::Type *SBP = llvm::Type::getInt8PtrTy(VMContext); + llvm::Constant *anno = llvm::ConstantArray::get(VMContext, + AA->getAnnotation(), true); + llvm::Constant *unit = llvm::ConstantArray::get(VMContext, + M->getModuleIdentifier(), true); // Get the two global values corresponding to the ConstantArrays we just // created to hold the bytes of the strings. - const char *StringPrefix = getContext().Target.getStringSymbolPrefix(true); - llvm::GlobalValue *annoGV = - new llvm::GlobalVariable(anno->getType(), false, - llvm::GlobalValue::InternalLinkage, anno, - GV->getName() + StringPrefix, M); + llvm::GlobalValue *annoGV = + new llvm::GlobalVariable(*M, anno->getType(), false, + llvm::GlobalValue::PrivateLinkage, anno, + GV->getName()); // translation unit name string, emitted into the llvm.metadata section. llvm::GlobalValue *unitGV = - new llvm::GlobalVariable(unit->getType(), false, - llvm::GlobalValue::InternalLinkage, unit, - StringPrefix, M); + new llvm::GlobalVariable(*M, unit->getType(), false, + llvm::GlobalValue::PrivateLinkage, unit, + ".str"); // Create the ConstantStruct for the global annotation. llvm::Constant *Fields[4] = { llvm::ConstantExpr::getBitCast(GV, SBP), llvm::ConstantExpr::getBitCast(annoGV, SBP), llvm::ConstantExpr::getBitCast(unitGV, SBP), - llvm::ConstantInt::get(llvm::Type::Int32Ty, LineNo) + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), LineNo) }; - return llvm::ConstantStruct::get(Fields, 4, false); + return llvm::ConstantStruct::get(VMContext, Fields, 4, false); } bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { @@ -521,12 +513,12 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { if (const FunctionDecl *FD = dyn_cast(Global)) { // Constructors and destructors should never be deferred. - if (FD->hasAttr() || + if (FD->hasAttr() || FD->hasAttr()) return false; GVALinkage Linkage = GetLinkageForFunction(getContext(), FD, Features); - + // static, static inline, always_inline, and extern inline functions can // always be deferred. Normal inline functions can be deferred in C99/C++. if (Linkage == GVA_Internal || Linkage == GVA_C99Inline || @@ -534,16 +526,27 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { return true; return false; } - + const VarDecl *VD = cast(Global); assert(VD->isFileVarDecl() && "Invalid decl"); + // We never want to defer structs that have non-trivial constructors or + // destructors. + + // FIXME: Handle references. + if (const RecordType *RT = VD->getType()->getAs()) { + if (const CXXRecordDecl *RD = dyn_cast(RT->getDecl())) { + if (!RD->hasTrivialConstructor() || !RD->hasTrivialDestructor()) + return false; + } + } + return VD->getStorageClass() == VarDecl::Static; } void CodeGenModule::EmitGlobal(GlobalDecl GD) { - const ValueDecl *Global = GD.getDecl(); - + const ValueDecl *Global = cast(GD.getDecl()); + // If this is an alias definition (which otherwise looks like a declaration) // emit it now. if (Global->hasAttr()) @@ -560,8 +563,8 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { // In C++, if this is marked "extern", defer code generation. if (getLangOptions().CPlusPlus && !VD->getInit() && - (VD->getStorageClass() == VarDecl::Extern || - VD->isExternC(getContext()))) + (VD->getStorageClass() == VarDecl::Extern || + VD->isExternC())) return; // In C, if this isn't a definition, defer code generation. @@ -591,8 +594,8 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { } void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { - const ValueDecl *D = GD.getDecl(); - + const ValueDecl *D = cast(GD.getDecl()); + if (const CXXConstructorDecl *CD = dyn_cast(D)) EmitCXXConstructor(CD, GD.getCtorType()); else if (const CXXDestructorDecl *DD = dyn_cast(D)) @@ -621,16 +624,16 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName, if (Entry) { if (Entry->getType()->getElementType() == Ty) return Entry; - + // Make sure the result is of the correct type. const llvm::Type *PTy = llvm::PointerType::getUnqual(Ty); return llvm::ConstantExpr::getBitCast(Entry, PTy); } - + // This is the first use or definition of a mangled name. If there is a // deferred decl with this name, remember that we need to emit it at the end // of the file. - llvm::DenseMap::iterator DDI = + llvm::DenseMap::iterator DDI = DeferredDecls.find(MangledName); if (DDI != DeferredDecls.end()) { // Move the potentially referenced deferred decl to the DeferredDeclsToEmit @@ -643,18 +646,33 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName, // top-level declarations. if (FD->isThisDeclarationADefinition() && MayDeferGeneration(FD)) DeferredDeclsToEmit.push_back(D); + // A called constructor which has no definition or declaration need be + // synthesized. + else if (const CXXConstructorDecl *CD = dyn_cast(FD)) { + const CXXRecordDecl *ClassDecl = + cast(CD->getDeclContext()); + if (CD->isCopyConstructor(getContext())) + DeferredCopyConstructorToEmit(D); + else if (!ClassDecl->hasUserDeclaredConstructor()) + DeferredDeclsToEmit.push_back(D); + } + else if (isa(FD)) + DeferredDestructorToEmit(D); + else if (const CXXMethodDecl *MD = dyn_cast(FD)) + if (MD->isCopyAssignment()) + DeferredCopyAssignmentToEmit(D); } - + // This function doesn't have a complete type (for example, the return // type is an incomplete struct). Use a fake type instead, and make // sure not to try to set attributes. bool IsIncompleteFunction = false; if (!isa(Ty)) { - Ty = llvm::FunctionType::get(llvm::Type::VoidTy, + Ty = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), std::vector(), false); IsIncompleteFunction = true; } - llvm::Function *F = llvm::Function::Create(cast(Ty), + llvm::Function *F = llvm::Function::Create(cast(Ty), llvm::Function::ExternalLinkage, "", &getModule()); F->setName(MangledName); @@ -665,6 +683,126 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName, return F; } +/// Defer definition of copy constructor(s) which need be implicitly defined. +void CodeGenModule::DeferredCopyConstructorToEmit(GlobalDecl CopyCtorDecl) { + const CXXConstructorDecl *CD = + cast(CopyCtorDecl.getDecl()); + const CXXRecordDecl *ClassDecl = cast(CD->getDeclContext()); + if (ClassDecl->hasTrivialCopyConstructor() || + ClassDecl->hasUserDeclaredCopyConstructor()) + return; + + // First make sure all direct base classes and virtual bases and non-static + // data mebers which need to have their copy constructors implicitly defined + // are defined. 12.8.p7 + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + CXXRecordDecl *BaseClassDecl + = cast(Base->getType()->getAs()->getDecl()); + if (CXXConstructorDecl *BaseCopyCtor = + BaseClassDecl->getCopyConstructor(Context, 0)) + GetAddrOfCXXConstructor(BaseCopyCtor, Ctor_Complete); + } + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + QualType FieldType = Context.getCanonicalType((*Field)->getType()); + if (const ArrayType *Array = Context.getAsArrayType(FieldType)) + FieldType = Array->getElementType(); + if (const RecordType *FieldClassType = FieldType->getAs()) { + if ((*Field)->isAnonymousStructOrUnion()) + continue; + CXXRecordDecl *FieldClassDecl + = cast(FieldClassType->getDecl()); + if (CXXConstructorDecl *FieldCopyCtor = + FieldClassDecl->getCopyConstructor(Context, 0)) + GetAddrOfCXXConstructor(FieldCopyCtor, Ctor_Complete); + } + } + DeferredDeclsToEmit.push_back(CopyCtorDecl); +} + +/// Defer definition of copy assignments which need be implicitly defined. +void CodeGenModule::DeferredCopyAssignmentToEmit(GlobalDecl CopyAssignDecl) { + const CXXMethodDecl *CD = cast(CopyAssignDecl.getDecl()); + const CXXRecordDecl *ClassDecl = cast(CD->getDeclContext()); + + if (ClassDecl->hasTrivialCopyAssignment() || + ClassDecl->hasUserDeclaredCopyAssignment()) + return; + + // First make sure all direct base classes and virtual bases and non-static + // data mebers which need to have their copy assignments implicitly defined + // are defined. 12.8.p12 + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + CXXRecordDecl *BaseClassDecl + = cast(Base->getType()->getAs()->getDecl()); + const CXXMethodDecl *MD = 0; + if (!BaseClassDecl->hasTrivialCopyAssignment() && + !BaseClassDecl->hasUserDeclaredCopyAssignment() && + BaseClassDecl->hasConstCopyAssignment(getContext(), MD)) + GetAddrOfFunction(MD, 0); + } + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + QualType FieldType = Context.getCanonicalType((*Field)->getType()); + if (const ArrayType *Array = Context.getAsArrayType(FieldType)) + FieldType = Array->getElementType(); + if (const RecordType *FieldClassType = FieldType->getAs()) { + if ((*Field)->isAnonymousStructOrUnion()) + continue; + CXXRecordDecl *FieldClassDecl + = cast(FieldClassType->getDecl()); + const CXXMethodDecl *MD = 0; + if (!FieldClassDecl->hasTrivialCopyAssignment() && + !FieldClassDecl->hasUserDeclaredCopyAssignment() && + FieldClassDecl->hasConstCopyAssignment(getContext(), MD)) + GetAddrOfFunction(MD, 0); + } + } + DeferredDeclsToEmit.push_back(CopyAssignDecl); +} + +void CodeGenModule::DeferredDestructorToEmit(GlobalDecl DtorDecl) { + const CXXDestructorDecl *DD = cast(DtorDecl.getDecl()); + const CXXRecordDecl *ClassDecl = cast(DD->getDeclContext()); + if (ClassDecl->hasTrivialDestructor() || + ClassDecl->hasUserDeclaredDestructor()) + return; + + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + CXXRecordDecl *BaseClassDecl + = cast(Base->getType()->getAs()->getDecl()); + if (const CXXDestructorDecl *BaseDtor = + BaseClassDecl->getDestructor(Context)) + GetAddrOfCXXDestructor(BaseDtor, Dtor_Complete); + } + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + QualType FieldType = Context.getCanonicalType((*Field)->getType()); + if (const ArrayType *Array = Context.getAsArrayType(FieldType)) + FieldType = Array->getElementType(); + if (const RecordType *FieldClassType = FieldType->getAs()) { + if ((*Field)->isAnonymousStructOrUnion()) + continue; + CXXRecordDecl *FieldClassDecl + = cast(FieldClassType->getDecl()); + if (const CXXDestructorDecl *FieldDtor = + FieldClassDecl->getDestructor(Context)) + GetAddrOfCXXDestructor(FieldDtor, Dtor_Complete); + } + } + DeferredDeclsToEmit.push_back(DtorDecl); +} + + /// GetAddrOfFunction - Return the address of the given function. If Ty is /// non-null, then this function will use the specified type if it has to /// create it (this occurs when we see a definition of the function). @@ -672,8 +810,8 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD, const llvm::Type *Ty) { // If there was no specific requested type, just convert it now. if (!Ty) - Ty = getTypes().ConvertType(GD.getDecl()->getType()); - return GetOrCreateLLVMFunction(getMangledName(GD.getDecl()), Ty, GD); + Ty = getTypes().ConvertType(cast(GD.getDecl())->getType()); + return GetOrCreateLLVMFunction(getMangledName(GD), Ty, GD); } /// CreateRuntimeFunction - Create a new runtime function with the specified @@ -701,15 +839,15 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName, if (Entry) { if (Entry->getType() == Ty) return Entry; - + // Make sure the result is of the correct type. return llvm::ConstantExpr::getBitCast(Entry, Ty); } - + // This is the first use or definition of a mangled name. If there is a // deferred decl with this name, remember that we need to emit it at the end // of the file. - llvm::DenseMap::iterator DDI = + llvm::DenseMap::iterator DDI = DeferredDecls.find(MangledName); if (DDI != DeferredDecls.end()) { // Move the potentially referenced deferred decl to the DeferredDeclsToEmit @@ -717,11 +855,11 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName, DeferredDeclsToEmit.push_back(DDI->second); DeferredDecls.erase(DDI); } - - llvm::GlobalVariable *GV = - new llvm::GlobalVariable(Ty->getElementType(), false, + + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(getModule(), Ty->getElementType(), false, llvm::GlobalValue::ExternalLinkage, - 0, "", &getModule(), + 0, "", 0, false, Ty->getAddressSpace()); GV->setName(MangledName); @@ -735,13 +873,13 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName, if (D->getStorageClass() == VarDecl::PrivateExtern) GV->setVisibility(llvm::GlobalValue::HiddenVisibility); - if (D->hasAttr() || + if (D->hasAttr() || D->hasAttr()) GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); GV->setThreadLocal(D->isThreadSpecified()); } - + return Entry = GV; } @@ -756,8 +894,8 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D, QualType ASTTy = D->getType(); if (Ty == 0) Ty = getTypes().ConvertTypeForMem(ASTTy); - - const llvm::PointerType *PTy = + + const llvm::PointerType *PTy = llvm::PointerType::get(Ty, ASTTy.getAddressSpace()); return GetOrCreateLLVMGlobal(getMangledName(D), PTy, D); } @@ -781,7 +919,7 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) { // later. const char *MangledName = getMangledName(D); if (GlobalDeclMap.count(MangledName) == 0) { - DeferredDecls[MangledName] = GlobalDecl(D); + DeferredDecls[MangledName] = D; return; } } @@ -793,7 +931,7 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) { void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { llvm::Constant *Init = 0; QualType ASTTy = D->getType(); - + if (D->getInit() == 0) { // This is a tentative definition; tentative definitions are // implicitly initialized with { 0 }. @@ -805,28 +943,36 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { // exists. A use may still exists, however, so we still may need // to do a RAUW. assert(!ASTTy->isIncompleteType() && "Unexpected incomplete type"); - Init = llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(ASTTy)); + Init = EmitNullConstant(D->getType()); } else { Init = EmitConstantExpr(D->getInit(), D->getType()); + if (!Init) { - ErrorUnsupported(D, "static initializer"); QualType T = D->getInit()->getType(); - Init = llvm::UndefValue::get(getTypes().ConvertType(T)); + if (getLangOptions().CPlusPlus) { + CXXGlobalInits.push_back(D); + Init = EmitNullConstant(T); + } else { + ErrorUnsupported(D, "static initializer"); + Init = llvm::UndefValue::get(getTypes().ConvertType(T)); + } } } const llvm::Type* InitType = Init->getType(); llvm::Constant *Entry = GetAddrOfGlobalVar(D, InitType); - + // Strip off a bitcast if we got one back. if (llvm::ConstantExpr *CE = dyn_cast(Entry)) { - assert(CE->getOpcode() == llvm::Instruction::BitCast); + assert(CE->getOpcode() == llvm::Instruction::BitCast || + // all zero index gep. + CE->getOpcode() == llvm::Instruction::GetElementPtr); Entry = CE->getOperand(0); } - + // Entry is now either a Function or GlobalVariable. llvm::GlobalVariable *GV = dyn_cast(Entry); - + // We have a definition after a declaration with the wrong type. // We must make a new GlobalVariable* and update everything that used OldGV // (a declaration or tentative definition) with the new GlobalVariable* @@ -839,7 +985,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { if (GV == 0 || GV->getType()->getElementType() != InitType || GV->getType()->getAddressSpace() != ASTTy.getAddressSpace()) { - + // Remove the old entry from GlobalDeclMap so that we'll create a new one. GlobalDeclMap.erase(getMangledName(D)); @@ -848,7 +994,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { GV->takeName(cast(Entry)); // Replace all uses of the old global with the new global - llvm::Constant *NewPtrForOldDecl = + llvm::Constant *NewPtrForOldDecl = llvm::ConstantExpr::getBitCast(GV, Entry->getType()); Entry->replaceAllUsesWith(NewPtrForOldDecl); @@ -863,22 +1009,38 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { } GV->setInitializer(Init); - GV->setConstant(D->getType().isConstant(Context)); + + // If it is safe to mark the global 'constant', do so now. + GV->setConstant(false); + if (D->getType().isConstant(Context)) { + // FIXME: In C++, if the variable has a non-trivial ctor/dtor or any mutable + // members, it cannot be declared "LLVM const". + GV->setConstant(true); + } + GV->setAlignment(getContext().getDeclAlignInBytes(D)); // Set the llvm linkage type as appropriate. - if (D->getStorageClass() == VarDecl::Static) + if (D->isInAnonymousNamespace()) + GV->setLinkage(llvm::Function::InternalLinkage); + else if (D->getStorageClass() == VarDecl::Static) GV->setLinkage(llvm::Function::InternalLinkage); else if (D->hasAttr()) GV->setLinkage(llvm::Function::DLLImportLinkage); else if (D->hasAttr()) GV->setLinkage(llvm::Function::DLLExportLinkage); - else if (D->hasAttr()) - GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage); - else if (!CompileOpts.NoCommon && - (!D->hasExternalStorage() && !D->getInit())) + else if (D->hasAttr()) { + if (GV->isConstant()) + GV->setLinkage(llvm::GlobalVariable::WeakODRLinkage); + else + GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage); + } else if (!CompileOpts.NoCommon && + !D->hasExternalStorage() && !D->getInit() && + !D->getAttr()) { GV->setLinkage(llvm::GlobalVariable::CommonLinkage); - else + // common vars aren't constant even if declared const. + GV->setConstant(false); + } else GV->setLinkage(llvm::GlobalVariable::ExternalLinkage); SetCommonAttributes(D, GV); @@ -904,7 +1066,7 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, // If we're redefining a global as a function, don't transform it. llvm::Function *OldFn = dyn_cast(Old); if (OldFn == 0) return; - + const llvm::Type *NewRetTy = NewFn->getReturnType(); llvm::SmallVector ArgList; @@ -914,7 +1076,7 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, unsigned OpNo = UI.getOperandNo(); llvm::CallInst *CI = dyn_cast(*UI++); if (!CI || OpNo != 0) continue; - + // If the return types don't match exactly, and if the call isn't dead, then // we can't transform this call. if (CI->getType() != NewRetTy && !CI->use_empty()) @@ -935,21 +1097,26 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, } if (DontTransform) continue; - + // Okay, we can transform this. Create the new call instruction and copy // over the required information. ArgList.append(CI->op_begin()+1, CI->op_begin()+1+ArgNo); llvm::CallInst *NewCall = llvm::CallInst::Create(NewFn, ArgList.begin(), ArgList.end(), "", CI); ArgList.clear(); - if (NewCall->getType() != llvm::Type::VoidTy) + if (!NewCall->getType()->isVoidTy()) NewCall->takeName(CI); - NewCall->setCallingConv(CI->getCallingConv()); NewCall->setAttributes(CI->getAttributes()); + NewCall->setCallingConv(CI->getCallingConv()); // Finally, remove the old call, replacing any uses with the new one. if (!CI->use_empty()) CI->replaceAllUsesWith(NewCall); + + // Copy any custom metadata attached with CI. + llvm::MetadataContext &TheMetadata = CI->getContext().getMetadata(); + TheMetadata.copyMD(CI, NewCall); + CI->eraseFromParent(); } } @@ -958,21 +1125,21 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { const llvm::FunctionType *Ty; const FunctionDecl *D = cast(GD.getDecl()); - + if (const CXXMethodDecl *MD = dyn_cast(D)) { - bool isVariadic = D->getType()->getAsFunctionProtoType()->isVariadic(); - + bool isVariadic = D->getType()->getAs()->isVariadic(); + Ty = getTypes().GetFunctionType(getTypes().getFunctionInfo(MD), isVariadic); } else { Ty = cast(getTypes().ConvertType(D->getType())); - + // As a special case, make sure that definitions of K&R function // "type foo()" aren't declared as varargs (which forces the backend // to do unnecessary work). if (D->getType()->isFunctionNoProtoType()) { assert(Ty->isVarArg() && "Didn't lower type as expected"); - // Due to stret, the lowered function could have arguments. - // Just create the same type as was lowered by ConvertType + // Due to stret, the lowered function could have arguments. + // Just create the same type as was lowered by ConvertType // but strip off the varargs bit. std::vector Args(Ty->param_begin(), Ty->param_end()); Ty = llvm::FunctionType::get(Ty->getReturnType(), Args, false); @@ -981,17 +1148,17 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { // Get or create the prototype for the function. llvm::Constant *Entry = GetAddrOfFunction(GD, Ty); - + // Strip off a bitcast if we got one back. if (llvm::ConstantExpr *CE = dyn_cast(Entry)) { assert(CE->getOpcode() == llvm::Instruction::BitCast); Entry = CE->getOperand(0); } - - + + if (cast(Entry)->getType()->getElementType() != Ty) { llvm::GlobalValue *OldFn = cast(Entry); - + // If the types mismatch then we have to rewrite the definition. assert(OldFn->isDeclaration() && "Shouldn't replace non-declaration"); @@ -1007,7 +1174,7 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { GlobalDeclMap.erase(getMangledName(D)); llvm::Function *NewFn = cast(GetAddrOfFunction(GD, Ty)); NewFn->takeName(OldFn); - + // If this is an implementation of a function without a prototype, try to // replace any existing uses of the function (which may be calls) with uses // of the new function @@ -1015,27 +1182,27 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { ReplaceUsesOfNonProtoTypeWithRealFunction(OldFn, NewFn); OldFn->removeDeadConstantUsers(); } - + // Replace uses of F with the Function we will endow with a body. if (!Entry->use_empty()) { - llvm::Constant *NewPtrForOldDecl = + llvm::Constant *NewPtrForOldDecl = llvm::ConstantExpr::getBitCast(NewFn, Entry->getType()); Entry->replaceAllUsesWith(NewPtrForOldDecl); } - + // Ok, delete the old function now, which is dead. OldFn->eraseFromParent(); - + Entry = NewFn; } - + llvm::Function *Fn = cast(Entry); CodeGenFunction(*this).GenerateCode(D, Fn); SetFunctionDefinitionAttributes(D, Fn); SetLLVMFunctionAttributesForDefinition(D, Fn); - + if (const ConstructorAttr *CA = D->getAttr()) AddGlobalCtor(Fn, CA->getPriority()); if (const DestructorAttr *DA = D->getAttr()) @@ -1047,7 +1214,7 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) { assert(AA && "Not an alias?"); 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).getName(); @@ -1062,22 +1229,22 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) { llvm::PointerType::getUnqual(DeclTy), 0); // Create the new alias itself, but don't set a name yet. - llvm::GlobalValue *GA = + llvm::GlobalValue *GA = new llvm::GlobalAlias(Aliasee->getType(), llvm::Function::ExternalLinkage, "", Aliasee, &getModule()); - + // See if there is already something with the alias' name in the module. const char *MangledName = getMangledName(D); llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName]; - + if (Entry && !Entry->isDeclaration()) { // If there is a definition in the module, then it wins over the alias. // This is dubious, but allow it to be safe. Just ignore the alias. GA->eraseFromParent(); return; } - + if (Entry) { // If there is a declaration in the module, then we had an extern followed // by the alias, as in: @@ -1086,12 +1253,12 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) { // int test6() __attribute__((alias("test7"))); // // Remove it and replace uses of it with the alias. - + Entry->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(GA, Entry->getType())); Entry->eraseFromParent(); } - + // Now we know that there is no conflict, set the name. Entry = GA; GA->setName(MangledName); @@ -1107,7 +1274,7 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) { } else { GA->setLinkage(llvm::Function::DLLExportLinkage); } - } else if (D->hasAttr() || + } else if (D->hasAttr() || D->hasAttr()) { GA->setLinkage(llvm::Function::WeakAnyLinkage); } @@ -1117,28 +1284,28 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) { /// getBuiltinLibFunction - Given a builtin id for a function like /// "__builtin_fabsf", return a Function* for "fabsf". -llvm::Value *CodeGenModule::getBuiltinLibFunction(unsigned BuiltinID) { +llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD, + unsigned BuiltinID) { assert((Context.BuiltinInfo.isLibFunction(BuiltinID) || - Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) && + Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) && "isn't a lib fn"); - + // Get the name, skip over the __builtin_ prefix (if necessary). const char *Name = Context.BuiltinInfo.GetName(BuiltinID); if (Context.BuiltinInfo.isLibFunction(BuiltinID)) Name += 10; - + // Get the type for the builtin. ASTContext::GetBuiltinTypeError Error; QualType Type = Context.GetBuiltinType(BuiltinID, Error); assert(Error == ASTContext::GE_None && "Can't get builtin type"); - const llvm::FunctionType *Ty = + const llvm::FunctionType *Ty = cast(getTypes().ConvertType(Type)); // Unique the name through the identifier table. Name = getContext().Idents.get(Name).getName(); - // FIXME: param attributes for sext/zext etc. - return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); + return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl(FD)); } llvm::Function *CodeGenModule::getIntrinsic(unsigned IID,const llvm::Type **Tys, @@ -1149,186 +1316,167 @@ llvm::Function *CodeGenModule::getIntrinsic(unsigned IID,const llvm::Type **Tys, llvm::Function *CodeGenModule::getMemCpyFn() { if (MemCpyFn) return MemCpyFn; - const llvm::Type *IntPtr = TheTargetData.getIntPtrType(); + const llvm::Type *IntPtr = TheTargetData.getIntPtrType(VMContext); return MemCpyFn = getIntrinsic(llvm::Intrinsic::memcpy, &IntPtr, 1); } llvm::Function *CodeGenModule::getMemMoveFn() { if (MemMoveFn) return MemMoveFn; - const llvm::Type *IntPtr = TheTargetData.getIntPtrType(); + const llvm::Type *IntPtr = TheTargetData.getIntPtrType(VMContext); return MemMoveFn = getIntrinsic(llvm::Intrinsic::memmove, &IntPtr, 1); } llvm::Function *CodeGenModule::getMemSetFn() { if (MemSetFn) return MemSetFn; - const llvm::Type *IntPtr = TheTargetData.getIntPtrType(); + const llvm::Type *IntPtr = TheTargetData.getIntPtrType(VMContext); return MemSetFn = getIntrinsic(llvm::Intrinsic::memset, &IntPtr, 1); } -static void appendFieldAndPadding(CodeGenModule &CGM, - std::vector& Fields, - FieldDecl *FieldD, FieldDecl *NextFieldD, - llvm::Constant* Field, - RecordDecl* RD, const llvm::StructType *STy) { - // Append the field. - Fields.push_back(Field); - - int StructFieldNo = CGM.getTypes().getLLVMFieldNo(FieldD); - - int NextStructFieldNo; - if (!NextFieldD) { - NextStructFieldNo = STy->getNumElements(); - } else { - NextStructFieldNo = CGM.getTypes().getLLVMFieldNo(NextFieldD); +static llvm::StringMapEntry & +GetConstantCFStringEntry(llvm::StringMap &Map, + const StringLiteral *Literal, + bool TargetIsLSB, + bool &IsUTF16, + unsigned &StringLength) { + unsigned NumBytes = Literal->getByteLength(); + + // Check for simple case. + if (!Literal->containsNonAsciiOrNull()) { + StringLength = NumBytes; + return Map.GetOrCreateValue(llvm::StringRef(Literal->getStrData(), + StringLength)); } - - // Append padding - for (int i = StructFieldNo + 1; i < NextStructFieldNo; i++) { - llvm::Constant *C = - llvm::Constant::getNullValue(STy->getElementType(StructFieldNo + 1)); - - Fields.push_back(C); + + // Otherwise, convert the UTF8 literals into a byte string. + llvm::SmallVector ToBuf(NumBytes); + const UTF8 *FromPtr = (UTF8 *)Literal->getStrData(); + UTF16 *ToPtr = &ToBuf[0]; + + ConversionResult Result = ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes, + &ToPtr, ToPtr + NumBytes, + strictConversion); + + // Check for conversion failure. + if (Result != conversionOK) { + // FIXME: Have Sema::CheckObjCString() validate the UTF-8 string and remove + // this duplicate code. + assert(Result == sourceIllegal && "UTF-8 to UTF-16 conversion failed"); + StringLength = NumBytes; + return Map.GetOrCreateValue(llvm::StringRef(Literal->getStrData(), + StringLength)); } + + // ConvertUTF8toUTF16 returns the length in ToPtr. + StringLength = ToPtr - &ToBuf[0]; + + // Render the UTF-16 string into a byte array and convert to the target byte + // order. + // + // FIXME: This isn't something we should need to do here. + llvm::SmallString<128> AsBytes; + AsBytes.reserve(StringLength * 2); + for (unsigned i = 0; i != StringLength; ++i) { + unsigned short Val = ToBuf[i]; + if (TargetIsLSB) { + AsBytes.push_back(Val & 0xFF); + AsBytes.push_back(Val >> 8); + } else { + AsBytes.push_back(Val >> 8); + AsBytes.push_back(Val & 0xFF); + } + } + // Append one extra null character, the second is automatically added by our + // caller. + AsBytes.push_back(0); + + IsUTF16 = true; + return Map.GetOrCreateValue(llvm::StringRef(AsBytes.data(), AsBytes.size())); } -llvm::Constant *CodeGenModule:: -GetAddrOfConstantCFString(const StringLiteral *Literal) { - std::string str; +llvm::Constant * +CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { unsigned StringLength = 0; - bool isUTF16 = false; - if (Literal->containsNonAsciiOrNull()) { - // Convert from UTF-8 to UTF-16. - llvm::SmallVector ToBuf(Literal->getByteLength()); - const UTF8 *FromPtr = (UTF8 *)Literal->getStrData(); - UTF16 *ToPtr = &ToBuf[0]; - - ConversionResult Result; - Result = ConvertUTF8toUTF16(&FromPtr, FromPtr+Literal->getByteLength(), - &ToPtr, ToPtr+Literal->getByteLength(), - strictConversion); - if (Result == conversionOK) { - // FIXME: Storing UTF-16 in a C string is a hack to test Unicode strings - // without doing more surgery to this routine. Since we aren't explicitly - // checking for endianness here, it's also a bug (when generating code for - // a target that doesn't match the host endianness). Modeling this as an - // i16 array is likely the cleanest solution. - StringLength = ToPtr-&ToBuf[0]; - str.assign((char *)&ToBuf[0], StringLength*2);// Twice as many UTF8 chars. - isUTF16 = true; - } else if (Result == sourceIllegal) { - // FIXME: Have Sema::CheckObjCString() validate the UTF-8 string. - str.assign(Literal->getStrData(), Literal->getByteLength()); - StringLength = str.length(); - } else - assert(Result == conversionOK && "UTF-8 to UTF-16 conversion failed"); - - } else { - str.assign(Literal->getStrData(), Literal->getByteLength()); - StringLength = str.length(); - } - llvm::StringMapEntry &Entry = - CFConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]); - + llvm::StringMapEntry &Entry = + GetConstantCFStringEntry(CFConstantStringMap, Literal, + getTargetData().isLittleEndian(), + isUTF16, StringLength); + if (llvm::Constant *C = Entry.getValue()) return C; - - llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty); + + llvm::Constant *Zero = + llvm::Constant::getNullValue(llvm::Type::getInt32Ty(VMContext)); llvm::Constant *Zeros[] = { Zero, Zero }; - + + // If we don't already have it, get __CFConstantStringClassReference. if (!CFConstantStringClassRef) { const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); Ty = llvm::ArrayType::get(Ty, 0); - - // FIXME: This is fairly broken if __CFConstantStringClassReference is - // already defined, in that it will get renamed and the user will most - // likely see an opaque error message. This is a general issue with relying - // on particular names. - llvm::GlobalVariable *GV = - new llvm::GlobalVariable(Ty, false, - llvm::GlobalVariable::ExternalLinkage, 0, - "__CFConstantStringClassReference", - &getModule()); - + llvm::Constant *GV = CreateRuntimeVariable(Ty, + "__CFConstantStringClassReference"); // Decay array -> ptr CFConstantStringClassRef = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); } - + QualType CFTy = getContext().getCFConstantStringType(); - RecordDecl *CFRD = CFTy->getAsRecordType()->getDecl(); - const llvm::StructType *STy = + const llvm::StructType *STy = cast(getTypes().ConvertType(CFTy)); - std::vector Fields; - RecordDecl::field_iterator Field = CFRD->field_begin(); + std::vector Fields(4); // Class pointer. - FieldDecl *CurField = *Field++; - FieldDecl *NextField = *Field++; - appendFieldAndPadding(*this, Fields, CurField, NextField, - CFConstantStringClassRef, CFRD, STy); - + Fields[0] = CFConstantStringClassRef; + // Flags. - CurField = NextField; - NextField = *Field++; const llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy); - appendFieldAndPadding(*this, Fields, CurField, NextField, - isUTF16 ? llvm::ConstantInt::get(Ty, 0x07d0) - : llvm::ConstantInt::get(Ty, 0x07C8), - CFRD, STy); - + Fields[1] = isUTF16 ? llvm::ConstantInt::get(Ty, 0x07d0) : + llvm::ConstantInt::get(Ty, 0x07C8); + // String pointer. - CurField = NextField; - NextField = *Field++; - llvm::Constant *C = llvm::ConstantArray::get(str); + llvm::Constant *C = llvm::ConstantArray::get(VMContext, Entry.getKey().str()); - const char *Sect, *Prefix; + const char *Sect = 0; + llvm::GlobalValue::LinkageTypes Linkage; bool isConstant; if (isUTF16) { - Prefix = getContext().Target.getUnicodeStringSymbolPrefix(); Sect = getContext().Target.getUnicodeStringSection(); - // FIXME: Why does GCC not set constant here? - isConstant = false; - } else { - Prefix = getContext().Target.getStringSymbolPrefix(true); - Sect = getContext().Target.getCFStringDataSection(); - // FIXME: -fwritable-strings should probably affect this, but we - // are following gcc here. + // 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 + // does make plain ascii ones writable. isConstant = true; + } else { + Linkage = llvm::GlobalValue::PrivateLinkage; + isConstant = !Features.WritableStrings; } - llvm::GlobalVariable *GV = - new llvm::GlobalVariable(C->getType(), isConstant, - llvm::GlobalValue::InternalLinkage, - C, Prefix, &getModule()); + + 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); + GV->setAlignment(Align); } - appendFieldAndPadding(*this, Fields, CurField, NextField, - llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2), - CFRD, STy); - + Fields[2] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); + // String length. - CurField = NextField; - NextField = 0; Ty = getTypes().ConvertType(getContext().LongTy); - appendFieldAndPadding(*this, Fields, CurField, NextField, - llvm::ConstantInt::get(Ty, StringLength), CFRD, STy); - + Fields[3] = llvm::ConstantInt::get(Ty, StringLength); + // The struct. C = llvm::ConstantStruct::get(STy, Fields); - GV = new llvm::GlobalVariable(C->getType(), true, - llvm::GlobalVariable::InternalLinkage, C, - getContext().Target.getCFStringSymbolPrefix(), - &getModule()); + GV = new llvm::GlobalVariable(getModule(), C->getType(), true, + llvm::GlobalVariable::PrivateLinkage, C, + "_unnamed_cfstring_"); if (const char *Sect = getContext().Target.getCFStringSection()) GV->setSection(Sect); Entry.setValue(GV); - + return GV; } @@ -1341,16 +1489,16 @@ std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) { const ConstantArrayType *CAT = getContext().getAsConstantArrayType(E->getType()); assert(CAT && "String isn't pointer or array!"); - + // Resize the string to the right size. std::string Str(StrData, StrData+Len); uint64_t RealLen = CAT->getSize().getZExtValue(); - + if (E->isWide()) RealLen *= getContext().Target.getWCharWidth()/8; - + Str.resize(RealLen, '\0'); - + return Str; } @@ -1374,17 +1522,18 @@ CodeGenModule::GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *E) { /// GenerateWritableString -- Creates storage for a string literal. -static llvm::Constant *GenerateStringLiteral(const std::string &str, +static llvm::Constant *GenerateStringLiteral(const std::string &str, bool constant, CodeGenModule &CGM, const char *GlobalName) { // Create Constant for this string literal. Don't add a '\0'. - llvm::Constant *C = llvm::ConstantArray::get(str, false); - + llvm::Constant *C = + llvm::ConstantArray::get(CGM.getLLVMContext(), str, false); + // Create a global variable for this string - return new llvm::GlobalVariable(C->getType(), constant, - llvm::GlobalValue::InternalLinkage, - C, GlobalName, &CGM.getModule()); + return new llvm::GlobalVariable(CGM.getModule(), C->getType(), constant, + llvm::GlobalValue::PrivateLinkage, + C, GlobalName); } /// GetAddrOfConstantString - Returns a pointer to a character array @@ -1401,14 +1550,14 @@ llvm::Constant *CodeGenModule::GetAddrOfConstantString(const std::string &str, // Get the default prefix if a name wasn't specified. if (!GlobalName) - GlobalName = getContext().Target.getStringSymbolPrefix(IsConstant); + GlobalName = ".str"; // Don't share any string literals if strings aren't constant. if (!IsConstant) return GenerateStringLiteral(str, false, *this, GlobalName); - - llvm::StringMapEntry &Entry = - ConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]); + + llvm::StringMapEntry &Entry = + ConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]); if (Entry.getValue()) return Entry.getValue(); @@ -1429,12 +1578,12 @@ llvm::Constant *CodeGenModule::GetAddrOfConstantCString(const std::string &str, /// EmitObjCPropertyImplementations - Emit information for synthesized /// properties for an implementation. -void CodeGenModule::EmitObjCPropertyImplementations(const +void CodeGenModule::EmitObjCPropertyImplementations(const ObjCImplementationDecl *D) { - for (ObjCImplementationDecl::propimpl_iterator + for (ObjCImplementationDecl::propimpl_iterator i = D->propimpl_begin(), e = D->propimpl_end(); i != e; ++i) { ObjCPropertyImplDecl *PID = *i; - + // Dynamic is just for type-checking. if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { ObjCPropertyDecl *PD = PID->getPropertyDecl(); @@ -1464,7 +1613,8 @@ void CodeGenModule::EmitNamespace(const NamespaceDecl *ND) { // EmitLinkageSpec - Emit all declarations in a linkage spec. void CodeGenModule::EmitLinkageSpec(const LinkageSpecDecl *LSD) { - if (LSD->getLanguage() != LinkageSpecDecl::lang_c) { + if (LSD->getLanguage() != LinkageSpecDecl::lang_c && + LSD->getLanguage() != LinkageSpecDecl::lang_cxx) { ErrorUnsupported(LSD, "linkage spec"); return; } @@ -1485,18 +1635,20 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { // Ignore dependent declarations. if (D->getDeclContext() && D->getDeclContext()->isDependentContext()) return; - + switch (D->getKind()) { + case Decl::CXXConversion: case Decl::CXXMethod: case Decl::Function: // Skip function templates if (cast(D)->getDescribedFunctionTemplate()) return; + + EmitGlobal(cast(D)); + break; - // Fall through - case Decl::Var: - EmitGlobal(GlobalDecl(cast(D))); + EmitGlobal(cast(D)); break; // C++ Decls @@ -1505,8 +1657,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { break; // No code generation needed. case Decl::Using: + case Decl::UsingDirective: case Decl::ClassTemplate: case Decl::FunctionTemplate: + case Decl::NamespaceAlias: break; case Decl::CXXConstructor: EmitCXXConstructors(cast(D)); @@ -1520,7 +1674,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { break; // Objective-C Decls - + // Forward declarations, no (immediate) code generation. case Decl::ObjCClass: case Decl::ObjCForwardProtocol: @@ -1543,7 +1697,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { EmitObjCPropertyImplementations(OMD); Runtime->GenerateClass(OMD); break; - } + } case Decl::ObjCMethod: { ObjCMethodDecl *OMD = cast(D); // If this is not a prototype, emit the body. @@ -1551,7 +1705,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { CodeGenFunction(*this).GenerateObjCMethod(OMD); break; } - case Decl::ObjCCompatibleAlias: + case Decl::ObjCCompatibleAlias: // compatibility-alias is a directive and has no code gen. break; @@ -1563,7 +1717,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { FileScopeAsmDecl *AD = cast(D); std::string AsmString(AD->getAsmString()->getStrData(), AD->getAsmString()->getByteLength()); - + const std::string &S = getModule().getModuleInlineAsm(); if (S.empty()) getModule().setModuleInlineAsm(AsmString); @@ -1571,8 +1725,8 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { getModule().setModuleInlineAsm(S + '\n' + AsmString); break; } - - default: + + default: // Make sure we handled everything we should, every other kind is a // non-top-level decl. FIXME: Would be nice to have an isTopLevelDeclKind // function. Need to recode Decl::Kind to do that easily. diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index ba9f1b28a07d..2e58337ee52d 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -17,16 +17,22 @@ #include "clang/Basic/LangOptions.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" #include "CGBlocks.h" #include "CGCall.h" #include "CGCXX.h" +#include "CGVtable.h" #include "CodeGenTypes.h" +#include "Mangle.h" +#include "llvm/Module.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/ValueHandle.h" #include +#define ATTACH_DEBUG_INFO_TO_AN_INSN 1 + namespace llvm { class Module; class Constant; @@ -34,6 +40,7 @@ namespace llvm { class GlobalValue; class TargetData; class FunctionType; + class LLVMContext; } namespace clang { @@ -68,42 +75,50 @@ namespace CodeGen { /// GlobalDecl - represents a global declaration. This can either be a /// CXXConstructorDecl and the constructor type (Base, Complete). /// a CXXDestructorDecl and the destructor type (Base, Complete) or -// a regular VarDecl or a FunctionDecl. +/// a VarDecl, a FunctionDecl or a BlockDecl. class GlobalDecl { - llvm::PointerIntPair Value; + llvm::PointerIntPair Value; + + void Init(const Decl *D) { + assert(!isa(D) && "Use other ctor with ctor decls!"); + assert(!isa(D) && "Use other ctor with dtor decls!"); + + Value.setPointer(D); + } public: GlobalDecl() {} - - explicit GlobalDecl(const ValueDecl *VD) : Value(VD, 0) { - assert(!isa(VD) && "Use other ctor with ctor decls!"); - assert(!isa(VD) && "Use other ctor with dtor decls!"); - } - GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type) + + GlobalDecl(const VarDecl *D) { Init(D);} + GlobalDecl(const FunctionDecl *D) { Init(D); } + GlobalDecl(const BlockDecl *D) { Init(D); } + GlobalDecl(const ObjCMethodDecl *D) { Init(D); } + + GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type) : Value(D, Type) {} GlobalDecl(const CXXDestructorDecl *D, CXXDtorType Type) : Value(D, Type) {} - - const ValueDecl *getDecl() const { return Value.getPointer(); } - + + const Decl *getDecl() const { return Value.getPointer(); } + CXXCtorType getCtorType() const { assert(isa(getDecl()) && "Decl is not a ctor!"); return static_cast(Value.getInt()); } - + CXXDtorType getDtorType() const { assert(isa(getDecl()) && "Decl is not a dtor!"); return static_cast(Value.getInt()); } }; - + /// CodeGenModule - This class organizes the cross-function state that is used /// while generating LLVM code. class CodeGenModule : public BlockModule { CodeGenModule(const CodeGenModule&); // DO NOT IMPLEMENT void operator=(const CodeGenModule&); // DO NOT IMPLEMENT - typedef std::vector< std::pair > CtorList; + typedef std::vector > CtorList; ASTContext &Context; const LangOptions &Features; @@ -112,9 +127,14 @@ class CodeGenModule : public BlockModule { const llvm::TargetData &TheTargetData; Diagnostic &Diags; CodeGenTypes Types; + MangleContext MangleCtx; + + /// VtableInfo - Holds information about C++ vtables. + CGVtableInfo VtableInfo; + CGObjCRuntime* Runtime; CGDebugInfo* DebugInfo; - + llvm::Function *MemCpyFn; llvm::Function *MemMoveFn; llvm::Function *MemSetFn; @@ -171,9 +191,15 @@ class CodeGenModule : public BlockModule { llvm::StringMap CFConstantStringMap; llvm::StringMap ConstantStringMap; + /// CXXGlobalInits - Variables with global initializers that need to run + /// before main. + std::vector CXXGlobalInits; + /// CFConstantStringClassRef - Cached reference to the class for constant /// strings. This value has type int * but is actually an Obj-C class pointer. llvm::Constant *CFConstantStringClassRef; + + llvm::LLVMContext &VMContext; public: CodeGenModule(ASTContext &C, const CompileOptions &CompileOpts, llvm::Module &M, const llvm::TargetData &TD, Diagnostic &Diags); @@ -200,8 +226,11 @@ public: const LangOptions &getLangOptions() const { return Features; } llvm::Module &getModule() const { return TheModule; } CodeGenTypes &getTypes() { return Types; } + MangleContext &getMangleContext() { return MangleCtx; } + CGVtableInfo &getVtableInfo() { return VtableInfo; } Diagnostic &getDiags() const { return Diags; } const llvm::TargetData &getTargetData() const { return TheTargetData; } + llvm::LLVMContext &getLLVMContext() { return VMContext; } /// getDeclVisibilityMode - Compute the visibility of the decl \arg D. LangOptions::VisibilityMode getDeclVisibilityMode(const Decl *D) const; @@ -223,6 +252,22 @@ public: llvm::Constant *GetAddrOfFunction(GlobalDecl GD, const llvm::Type *Ty = 0); + /// GenerateRtti - Generate the rtti information for the given type. + llvm::Constant *GenerateRtti(const CXXRecordDecl *RD); + + /// BuildThunk - Build a thunk for the given method + llvm::Constant *BuildThunk(const CXXMethodDecl *MD, bool Extern, int64_t nv, + int64_t v); + /// BuildCoVariantThunk - Build a thunk for the given method + llvm::Constant *BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern, + int64_t nv_t, int64_t v_t, + int64_t nv_r, int64_t v_r); + + /// 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); + /// GetStringForStringLiteral - Return the appropriate bytes for a string /// literal, properly padded to match the literal type. If only the address of /// a constant is needed consider using GetAddrOfConstantStringLiteral. @@ -239,7 +284,7 @@ public: /// GetAddrOfConstantStringFromObjCEncode - Return a pointer to a constant /// array for the given ObjCEncodeExpr node. llvm::Constant *GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *); - + /// GetAddrOfConstantString - Returns a pointer to a character array /// containing the literal. This contents are exactly that of the given /// string, i.e. it will not be null terminated automatically; see @@ -264,17 +309,18 @@ public: /// GetAddrOfCXXConstructor - Return the address of the constructor of the /// given type. - llvm::Function *GetAddrOfCXXConstructor(const CXXConstructorDecl *D, + llvm::Function *GetAddrOfCXXConstructor(const CXXConstructorDecl *D, CXXCtorType Type); /// GetAddrOfCXXDestructor - Return the address of the constructor of the /// given type. - llvm::Function *GetAddrOfCXXDestructor(const CXXDestructorDecl *D, + llvm::Function *GetAddrOfCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type); - + /// getBuiltinLibFunction - Given a builtin id for a function like /// "__builtin_fabsf", return a Function* for "fabsf". - llvm::Value *getBuiltinLibFunction(unsigned BuiltinID); + llvm::Value *getBuiltinLibFunction(const FunctionDecl *FD, + unsigned BuiltinID); llvm::Function *getMemCpyFn(); llvm::Function *getMemMoveFn(); @@ -355,20 +401,30 @@ public: /// as a return type. bool ReturnTypeUsesSret(const CGFunctionInfo &FI); + /// ConstructAttributeList - Get the LLVM attributes and calling convention to + /// use for a particular function type. + /// + /// \param Info - The function type information. + /// \param TargetDecl - The decl these attributes are being constructed + /// for. If supplied the attributes applied to this decl may contribute to the + /// function attributes and calling convention. + /// \param PAL [out] - On return, the attribute list to use. + /// \param CallingConv [out] - On return, the LLVM calling convention to use. void ConstructAttributeList(const CGFunctionInfo &Info, const Decl *TargetDecl, - AttributeListType &PAL); + AttributeListType &PAL, + unsigned &CallingConv); const char *getMangledName(const GlobalDecl &D); const char *getMangledName(const NamedDecl *ND); - const char *getMangledCXXCtorName(const CXXConstructorDecl *D, + const char *getMangledCXXCtorName(const CXXConstructorDecl *D, CXXCtorType Type); - const char *getMangledCXXDtorName(const CXXDestructorDecl *D, + const char *getMangledCXXDtorName(const CXXDestructorDecl *D, CXXDtorType Type); void EmitTentativeDefinition(const VarDecl *D); - + enum GVALinkage { GVA_Internal, GVA_C99Inline, @@ -376,19 +432,22 @@ public: GVA_StrongExternal, GVA_TemplateInstantiation }; - + private: /// UniqueMangledName - Unique a name by (if necessary) inserting it into the /// MangledNames string map. const char *UniqueMangledName(const char *NameStart, const char *NameEnd); - + llvm::Constant *GetOrCreateLLVMFunction(const char *MangledName, const llvm::Type *Ty, GlobalDecl D); llvm::Constant *GetOrCreateLLVMGlobal(const char *MangledName, const llvm::PointerType *PTy, const VarDecl *D); - + void DeferredCopyConstructorToEmit(GlobalDecl D); + void DeferredCopyAssignmentToEmit(GlobalDecl D); + void DeferredDestructorToEmit(GlobalDecl D); + /// SetCommonAttributes - Set attributes which are common to any /// form of a global definition (alias, Objective-C method, /// function, global variable). @@ -397,9 +456,9 @@ private: void SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV); /// SetFunctionDefinitionAttributes - Set attributes for a global definition. - void SetFunctionDefinitionAttributes(const FunctionDecl *D, + void SetFunctionDefinitionAttributes(const FunctionDecl *D, llvm::GlobalValue *GV); - + /// SetFunctionAttributes - Set function attributes for a function /// declaration. void SetFunctionAttributes(const FunctionDecl *FD, @@ -418,26 +477,29 @@ private: void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D); // C++ related functions. - + void EmitNamespace(const NamespaceDecl *D); void EmitLinkageSpec(const LinkageSpecDecl *D); /// EmitCXXConstructors - Emit constructors (base, complete) from a /// C++ constructor Decl. void EmitCXXConstructors(const CXXConstructorDecl *D); - + /// EmitCXXConstructor - Emit a single constructor with the given type from /// a C++ constructor Decl. void EmitCXXConstructor(const CXXConstructorDecl *D, CXXCtorType Type); - - /// EmitCXXDestructors - Emit destructors (base, complete) from a + + /// EmitCXXDestructors - Emit destructors (base, complete) from a /// C++ destructor Decl. void EmitCXXDestructors(const CXXDestructorDecl *D); - + /// EmitCXXDestructor - Emit a single destructor with the given type from /// a C++ destructor Decl. void EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type); - + + /// EmitCXXGlobalInitFunc - Emit a function that initializes C++ globals. + void EmitCXXGlobalInitFunc(); + // FIXME: Hardcoding priority here is gross. void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535); void AddGlobalDtor(llvm::Function *Dtor, int Priority=65535); diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 1a30ea37fbbc..dedf824ef9fd 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -7,13 +7,14 @@ // //===----------------------------------------------------------------------===// // -// This is the code that handles AST -> LLVM type lowering. +// This is the code that handles AST -> LLVM type lowering. // //===----------------------------------------------------------------------===// #include "CodeGenTypes.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" #include "llvm/DerivedTypes.h" @@ -21,47 +22,11 @@ #include "llvm/Target/TargetData.h" #include "CGCall.h" +#include "CGRecordLayoutBuilder.h" using namespace clang; using namespace CodeGen; -namespace { - /// RecordOrganizer - This helper class, used by CGRecordLayout, layouts - /// structs and unions. It manages transient information used during layout. - /// FIXME : Handle field aligments. Handle packed structs. - class RecordOrganizer { - public: - explicit RecordOrganizer(CodeGenTypes &Types, const RecordDecl& Record) : - CGT(Types), RD(Record), STy(NULL) {} - - /// layoutStructFields - Do the actual work and lay out all fields. Create - /// corresponding llvm struct type. This should be invoked only after - /// all fields are added. - void layoutStructFields(const ASTRecordLayout &RL); - - /// layoutUnionFields - Do the actual work and lay out all fields. Create - /// corresponding llvm struct type. This should be invoked only after - /// all fields are added. - void layoutUnionFields(const ASTRecordLayout &RL); - - /// getLLVMType - Return associated llvm struct type. This may be NULL - /// if fields are not laid out. - llvm::Type *getLLVMType() const { - return STy; - } - - llvm::SmallSet &getPaddingFields() { - return PaddingFields; - } - - private: - CodeGenTypes &CGT; - const RecordDecl& RD; - llvm::Type *STy; - llvm::SmallSet PaddingFields; - }; -} - CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M, const llvm::TargetData &TD) : Context(Ctx), Target(Ctx.Target), TheModule(M), TheTargetData(TD), @@ -69,8 +34,8 @@ CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M, } CodeGenTypes::~CodeGenTypes() { - for(llvm::DenseMap::iterator - I = CGRecordLayouts.begin(), E = CGRecordLayouts.end(); + for (llvm::DenseMap::iterator + I = CGRecordLayouts.begin(), E = CGRecordLayouts.end(); I != E; ++I) delete I->second; CGRecordLayouts.clear(); @@ -100,7 +65,7 @@ const llvm::Type *CodeGenTypes::ConvertType(QualType T) { const llvm::Type *CodeGenTypes::ConvertTypeRecursive(QualType T) { T = Context.getCanonicalType(T); - + // See if type is already cached. llvm::DenseMap::iterator I = TypeCache.find(T.getTypePtr()); @@ -110,15 +75,16 @@ const llvm::Type *CodeGenTypes::ConvertTypeRecursive(QualType T) { return I->second.get(); const llvm::Type *ResultType = ConvertNewType(T); - TypeCache.insert(std::make_pair(T.getTypePtr(), + TypeCache.insert(std::make_pair(T.getTypePtr(), llvm::PATypeHolder(ResultType))); return ResultType; } const llvm::Type *CodeGenTypes::ConvertTypeForMemRecursive(QualType T) { const llvm::Type *ResultType = ConvertTypeRecursive(T); - if (ResultType == llvm::Type::Int1Ty) - return llvm::IntegerType::get((unsigned)Context.getTypeSize(T)); + if (ResultType == llvm::Type::getInt1Ty(getLLVMContext())) + return llvm::IntegerType::get(getLLVMContext(), + (unsigned)Context.getTypeSize(T)); return ResultType; } @@ -128,26 +94,27 @@ const llvm::Type *CodeGenTypes::ConvertTypeForMemRecursive(QualType T) { /// memory representation is usually i8 or i32, depending on the target. 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 != llvm::Type::Int1Ty) + if (R != llvm::Type::getInt1Ty(getLLVMContext())) return R; - + // Otherwise, return an integer of the target-specified size. - return llvm::IntegerType::get((unsigned)Context.getTypeSize(T)); - + return llvm::IntegerType::get(getLLVMContext(), + (unsigned)Context.getTypeSize(T)); + } // Code to verify a given function type is complete, i.e. the return type // and all of the argument types are complete. static const TagType *VerifyFuncTypeComplete(const Type* T) { const FunctionType *FT = cast(T); - if (const TagType* TT = FT->getResultType()->getAsTagType()) + if (const TagType* TT = FT->getResultType()->getAs()) if (!TT->getDecl()->isDefinition()) return TT; if (const FunctionProtoType *FPT = dyn_cast(T)) for (unsigned i = 0; i < FPT->getNumArgs(); i++) - if (const TagType* TT = FPT->getArgType(i)->getAsTagType()) + if (const TagType* TT = FPT->getArgType(i)->getAs()) if (!TT->getDecl()->isDefinition()) return TT; return 0; @@ -156,17 +123,16 @@ static const TagType *VerifyFuncTypeComplete(const Type* T) { /// UpdateCompletedType - When we find the full definition for a TagDecl, /// replace the 'opaque' type we previously made for it if applicable. void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) { - const Type *Key = - Context.getTagDeclType(const_cast(TD)).getTypePtr(); - llvm::DenseMap::iterator TDTI = + const Type *Key = Context.getTagDeclType(TD).getTypePtr(); + llvm::DenseMap::iterator TDTI = TagDeclTypes.find(Key); if (TDTI == TagDeclTypes.end()) return; - + // Remember the opaque LLVM type for this tagdecl. llvm::PATypeHolder OpaqueHolder = TDTI->second; assert(isa(OpaqueHolder.get()) && "Updating compilation of an already non-opaque type?"); - + // Remove it from TagDeclTypes so that it will be regenerated. TagDeclTypes.erase(TDTI); @@ -197,24 +163,25 @@ void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) { } } -static const llvm::Type* getTypeForFormat(const llvm::fltSemantics &format) { +static const llvm::Type* getTypeForFormat(llvm::LLVMContext &VMContext, + const llvm::fltSemantics &format) { if (&format == &llvm::APFloat::IEEEsingle) - return llvm::Type::FloatTy; + return llvm::Type::getFloatTy(VMContext); if (&format == &llvm::APFloat::IEEEdouble) - return llvm::Type::DoubleTy; + return llvm::Type::getDoubleTy(VMContext); if (&format == &llvm::APFloat::IEEEquad) - return llvm::Type::FP128Ty; + return llvm::Type::getFP128Ty(VMContext); if (&format == &llvm::APFloat::PPCDoubleDouble) - return llvm::Type::PPC_FP128Ty; + return llvm::Type::getPPC_FP128Ty(VMContext); if (&format == &llvm::APFloat::x87DoubleExtended) - return llvm::Type::X86_FP80Ty; + return llvm::Type::getX86_FP80Ty(VMContext); assert(0 && "Unknown float format!"); return 0; } const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { const clang::Type &Ty = *Context.getCanonicalType(T); - + switch (Ty.getTypeClass()) { #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) @@ -228,14 +195,16 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { switch (cast(Ty).getKind()) { default: assert(0 && "Unknown builtin type!"); case BuiltinType::Void: + case BuiltinType::ObjCId: + case BuiltinType::ObjCClass: // LLVM void type can only be used as the result of a function call. Just // map to the same as char. - return llvm::IntegerType::get(8); + return llvm::IntegerType::get(getLLVMContext(), 8); case BuiltinType::Bool: // Note that we always return bool as i1 for use as a scalar type. - return llvm::Type::Int1Ty; - + return llvm::Type::getInt1Ty(getLLVMContext()); + case BuiltinType::Char_S: case BuiltinType::Char_U: case BuiltinType::SChar: @@ -249,46 +218,56 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { case BuiltinType::LongLong: case BuiltinType::ULongLong: case BuiltinType::WChar: - return llvm::IntegerType::get( + case BuiltinType::Char16: + case BuiltinType::Char32: + return llvm::IntegerType::get(getLLVMContext(), static_cast(Context.getTypeSize(T))); - + case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: - return getTypeForFormat(Context.getFloatTypeSemantics(T)); - + return getTypeForFormat(getLLVMContext(), + Context.getFloatTypeSemantics(T)); + + case BuiltinType::NullPtr: { + // Model std::nullptr_t as i8* + const llvm::Type *Ty = llvm::IntegerType::get(getLLVMContext(), 8); + return llvm::PointerType::getUnqual(Ty); + } + case BuiltinType::UInt128: case BuiltinType::Int128: - return llvm::IntegerType::get(128); + return llvm::IntegerType::get(getLLVMContext(), 128); } break; } case Type::FixedWidthInt: - return llvm::IntegerType::get(cast(T)->getWidth()); + return llvm::IntegerType::get(getLLVMContext(), + cast(T)->getWidth()); case Type::Complex: { - const llvm::Type *EltTy = + const llvm::Type *EltTy = ConvertTypeRecursive(cast(Ty).getElementType()); - return llvm::StructType::get(EltTy, EltTy, NULL); + return llvm::StructType::get(TheModule.getContext(), EltTy, EltTy, NULL); } case Type::LValueReference: case Type::RValueReference: { const ReferenceType &RTy = cast(Ty); QualType ETy = RTy.getPointeeType(); - llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(); + llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext()); PointersToResolve.push_back(std::make_pair(ETy, PointeeType)); return llvm::PointerType::get(PointeeType, ETy.getAddressSpace()); } case Type::Pointer: { const PointerType &PTy = cast(Ty); QualType ETy = PTy.getPointeeType(); - llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(); + llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext()); PointersToResolve.push_back(std::make_pair(ETy, PointeeType)); return llvm::PointerType::get(PointeeType, ETy.getAddressSpace()); } - + case Type::VariableArray: { const VariableArrayType &A = cast(Ty); - assert(A.getIndexTypeQualifier() == 0 && + assert(A.getIndexTypeCVRQualifiers() == 0 && "FIXME: We only handle trivial array types so far!"); // VLAs resolve to the innermost element type; this matches // the return of alloca, and there isn't any obviously better choice. @@ -296,7 +275,7 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { } case Type::IncompleteArray: { const IncompleteArrayType &A = cast(Ty); - assert(A.getIndexTypeQualifier() == 0 && + assert(A.getIndexTypeCVRQualifiers() == 0 && "FIXME: We only handle trivial array types so far!"); // int X[] -> [0 x int] return llvm::ArrayType::get(ConvertTypeForMemRecursive(A.getElementType()), 0); @@ -320,7 +299,7 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { // we have an opaque type corresponding to the tag type. ConvertTagDeclType(TT->getDecl()); // Create an opaque type for this function type, save it, and return it. - llvm::Type *ResultType = llvm::OpaqueType::get(); + llvm::Type *ResultType = llvm::OpaqueType::get(getLLVMContext()); FunctionTypes.insert(std::make_pair(&Ty, ResultType)); return ResultType; } @@ -332,55 +311,57 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { const FunctionNoProtoType *FNPT = cast(&Ty); return GetFunctionType(getFunctionInfo(FNPT), true); } - - case Type::ExtQual: - return - ConvertTypeRecursive(QualType(cast(Ty).getBaseType(), 0)); - - case Type::ObjCQualifiedInterface: { - // Lower foo just like foo. - ObjCInterfaceDecl *ID = cast(Ty).getDecl(); - return ConvertTypeRecursive(Context.getObjCInterfaceType(ID)); - } - + case Type::ObjCInterface: { // Objective-C interfaces are always opaque (outside of the // runtime, which can do whatever it likes); we never refine // these. const llvm::Type *&T = InterfaceTypes[cast(&Ty)]; if (!T) - T = llvm::OpaqueType::get(); + T = llvm::OpaqueType::get(getLLVMContext()); return T; } - - case Type::ObjCObjectPointer: - // Protocols don't influence the LLVM type. - return ConvertTypeRecursive(Context.getObjCIdType()); + + case Type::ObjCObjectPointer: { + // Protocol qualifications do not influence the LLVM type, we just return a + // pointer to the underlying interface type. We don't need to worry about + // recursive conversion. + const llvm::Type *T = + ConvertTypeRecursive(cast(Ty).getPointeeType()); + return llvm::PointerType::getUnqual(T); + } case Type::Record: case Type::Enum: { const TagDecl *TD = cast(Ty).getDecl(); const llvm::Type *Res = ConvertTagDeclType(TD); - + std::string TypeName(TD->getKindName()); TypeName += '.'; - + // Name the codegen type after the typedef name // if there is no tag type name available if (TD->getIdentifier()) - TypeName += TD->getNameAsString(); + // FIXME: We should not have to check for a null decl context here. + // Right now we do it because the implicit Obj-C decls don't have one. + TypeName += TD->getDeclContext() ? TD->getQualifiedNameAsString() : + TD->getNameAsString(); else if (const TypedefType *TdT = dyn_cast(T)) - TypeName += TdT->getDecl()->getNameAsString(); + // FIXME: We should not have to check for a null decl context here. + // Right now we do it because the implicit Obj-C decls don't have one. + TypeName += TdT->getDecl()->getDeclContext() ? + TdT->getDecl()->getQualifiedNameAsString() : + TdT->getDecl()->getNameAsString(); else TypeName += "anon"; - - TheModule.addTypeName(TypeName, Res); + + TheModule.addTypeName(TypeName, Res); return Res; } case Type::BlockPointer: { const QualType FTy = cast(Ty).getPointeeType(); - llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(); + llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext()); PointersToResolve.push_back(std::make_pair(FTy, PointeeType)); return llvm::PointerType::get(PointeeType, FTy.getAddressSpace()); } @@ -392,7 +373,8 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { QualType ETy = cast(Ty).getPointeeType(); if (ETy->isFunctionType()) { - return llvm::StructType::get(ConvertType(Context.getPointerDiffType()), + return llvm::StructType::get(TheModule.getContext(), + ConvertType(Context.getPointerDiffType()), ConvertType(Context.getPointerDiffType()), NULL); } else @@ -402,85 +384,85 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { case Type::TemplateSpecialization: assert(false && "Dependent types can't get here"); } - + // FIXME: implement. - return llvm::OpaqueType::get(); + return llvm::OpaqueType::get(getLLVMContext()); } /// ConvertTagDeclType - Lay out a tagged decl type like struct or union or /// 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(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(i->getType()->getAs()->getDecl()); + ConvertTagDeclType(Base); + } + } + } + // TagDecl's are not necessarily unique, instead use the (clang) // type connected to the decl. - const Type *Key = - Context.getTagDeclType(const_cast(TD)).getTypePtr(); - llvm::DenseMap::iterator TDTI = + const Type *Key = + Context.getTagDeclType(TD).getTypePtr(); + llvm::DenseMap::iterator TDTI = TagDeclTypes.find(Key); - + // If we've already compiled this tag type, use the previous definition. 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 (!TD->isDefinition()) { - llvm::Type *ResultType = llvm::OpaqueType::get(); + llvm::Type *ResultType = llvm::OpaqueType::get(getLLVMContext()); TagDeclTypes.insert(std::make_pair(Key, ResultType)); return ResultType; } - + // Okay, this is a definition of a type. Compile the implementation now. - + if (TD->isEnum()) { // Don't bother storing enums in TagDeclTypes. return ConvertTypeRecursive(cast(TD)->getIntegerType()); } - + // This decl could well be recursive. In this case, insert an opaque // definition of this type, which the recursive uses will get. We will then // refine this opaque version later. // Create new OpaqueType now for later use in case this is a recursive // type. This will later be refined to the actual type. - llvm::PATypeHolder ResultHolder = llvm::OpaqueType::get(); + llvm::PATypeHolder ResultHolder = llvm::OpaqueType::get(getLLVMContext()); TagDeclTypes.insert(std::make_pair(Key, ResultHolder)); - + const llvm::Type *ResultType; const RecordDecl *RD = cast(TD); - // There isn't any extra information for empty structures/unions. - if (RD->field_empty()) { - ResultType = llvm::StructType::get(std::vector()); - } else { - // Layout fields. - RecordOrganizer RO(*this, *RD); - - if (TD->isStruct() || TD->isClass()) - RO.layoutStructFields(Context.getASTRecordLayout(RD)); - else { - assert(TD->isUnion() && "unknown tag decl kind!"); - RO.layoutUnionFields(Context.getASTRecordLayout(RD)); - } - - // Get llvm::StructType. - const Type *Key = - Context.getTagDeclType(const_cast(TD)).getTypePtr(); - CGRecordLayouts[Key] = new CGRecordLayout(RO.getLLVMType(), - RO.getPaddingFields()); - ResultType = RO.getLLVMType(); - } - + // Layout fields. + CGRecordLayout *Layout = + CGRecordLayoutBuilder::ComputeLayout(*this, RD); + + CGRecordLayouts[Key] = Layout; + ResultType = Layout->getLLVMType(); + // Refine our Opaque type to ResultType. This can invalidate ResultType, so // make sure to read the result out of the holder. cast(ResultHolder.get()) ->refineAbstractTypeTo(ResultType); - + return ResultHolder.get(); -} +} /// getLLVMFieldNo - Return llvm::StructType element number /// that corresponds to the field FD. unsigned CodeGenTypes::getLLVMFieldNo(const FieldDecl *FD) { + assert(!FD->isBitField() && "Don't use getLLVMFieldNo on bit fields!"); + llvm::DenseMap::iterator I = FieldInfo.find(FD); assert (I != FieldInfo.end() && "Unable to find field info"); return I->second; @@ -500,115 +482,19 @@ CodeGenTypes::BitFieldInfo CodeGenTypes::getBitFieldInfo(const FieldDecl *FD) { } /// addBitFieldInfo - Assign a start bit and a size to field FD. -void CodeGenTypes::addBitFieldInfo(const FieldDecl *FD, unsigned Begin, - unsigned Size) { - BitFields.insert(std::make_pair(FD, BitFieldInfo(Begin, Size))); +void CodeGenTypes::addBitFieldInfo(const FieldDecl *FD, unsigned FieldNo, + unsigned Start, unsigned Size) { + BitFields.insert(std::make_pair(FD, BitFieldInfo(FieldNo, Start, Size))); } /// getCGRecordLayout - Return record layout info for the given llvm::Type. -const CGRecordLayout * +const CGRecordLayout & CodeGenTypes::getCGRecordLayout(const TagDecl *TD) const { - const Type *Key = - Context.getTagDeclType(const_cast(TD)).getTypePtr(); + const Type *Key = + Context.getTagDeclType(TD).getTypePtr(); llvm::DenseMap::iterator I = CGRecordLayouts.find(Key); - assert (I != CGRecordLayouts.end() + assert (I != CGRecordLayouts.end() && "Unable to find record layout information for type"); - return I->second; -} - -/// layoutStructFields - Do the actual work and lay out all fields. Create -/// corresponding llvm struct type. -/// Note that this doesn't actually try to do struct layout; it depends on -/// the layout built by the AST. (We have to do struct layout to do Sema, -/// and there's no point to duplicating the work.) -void RecordOrganizer::layoutStructFields(const ASTRecordLayout &RL) { - // FIXME: This code currently always generates packed structures. - // Unpacked structures are more readable, and sometimes more efficient! - // (But note that any changes here are likely to impact CGExprConstant, - // which makes some messy assumptions.) - uint64_t llvmSize = 0; - // FIXME: Make this a SmallVector - std::vector LLVMFields; - - unsigned curField = 0; - for (RecordDecl::field_iterator Field = RD.field_begin(), - FieldEnd = RD.field_end(); - Field != FieldEnd; ++Field) { - uint64_t offset = RL.getFieldOffset(curField); - const llvm::Type *Ty = CGT.ConvertTypeForMemRecursive(Field->getType()); - uint64_t size = CGT.getTargetData().getTypeAllocSizeInBits(Ty); - - if (Field->isBitField()) { - uint64_t BitFieldSize = - Field->getBitWidth()->EvaluateAsInt(CGT.getContext()).getZExtValue(); - - // Bitfield field info is different from other field info; - // it actually ignores the underlying LLVM struct because - // there isn't any convenient mapping. - CGT.addFieldInfo(*Field, offset / size); - CGT.addBitFieldInfo(*Field, offset % size, BitFieldSize); - } else { - // Put the element into the struct. This would be simpler - // if we didn't bother, but it seems a bit too strange to - // allocate all structs as i8 arrays. - while (llvmSize < offset) { - LLVMFields.push_back(llvm::Type::Int8Ty); - llvmSize += 8; - } - - llvmSize += size; - CGT.addFieldInfo(*Field, LLVMFields.size()); - LLVMFields.push_back(Ty); - } - ++curField; - } - - while (llvmSize < RL.getSize()) { - LLVMFields.push_back(llvm::Type::Int8Ty); - llvmSize += 8; - } - - STy = llvm::StructType::get(LLVMFields, true); - assert(CGT.getTargetData().getTypeAllocSizeInBits(STy) == RL.getSize()); -} - -/// layoutUnionFields - Do the actual work and lay out all fields. Create -/// corresponding llvm struct type. This should be invoked only after -/// all fields are added. -void RecordOrganizer::layoutUnionFields(const ASTRecordLayout &RL) { - unsigned curField = 0; - for (RecordDecl::field_iterator Field = RD.field_begin(), - FieldEnd = RD.field_end(); - Field != FieldEnd; ++Field) { - // The offset should usually be zero, but bitfields could be strange - uint64_t offset = RL.getFieldOffset(curField); - CGT.ConvertTypeRecursive(Field->getType()); - - if (Field->isBitField()) { - Expr *BitWidth = Field->getBitWidth(); - uint64_t BitFieldSize = - BitWidth->EvaluateAsInt(CGT.getContext()).getZExtValue(); - - CGT.addFieldInfo(*Field, 0); - CGT.addBitFieldInfo(*Field, offset, BitFieldSize); - } else { - CGT.addFieldInfo(*Field, 0); - } - ++curField; - } - - // This looks stupid, but it is correct in the sense that - // it works no matter how complicated the sizes and alignments - // of the union elements are. The natural alignment - // of the result doesn't matter because anyone allocating - // structures should be aligning them appropriately anyway. - // FIXME: We can be a bit more intuitive in a lot of cases. - // FIXME: Make this a struct type to work around PR2399; the - // C backend doesn't like structs using array types. - std::vector LLVMFields; - LLVMFields.push_back(llvm::ArrayType::get(llvm::Type::Int8Ty, - RL.getSize() / 8)); - STy = llvm::StructType::get(LLVMFields, true); - assert(CGT.getTargetData().getTypeAllocSizeInBits(STy) == RL.getSize()); + return *I->second; } diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index b72d8e92013a..a92a019b988e 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -7,13 +7,14 @@ // //===----------------------------------------------------------------------===// // -// This is the code that handles AST -> LLVM type lowering. +// This is the code that handles AST -> LLVM type lowering. // //===----------------------------------------------------------------------===// #ifndef CLANG_CODEGEN_CODEGENTYPES_H #define CLANG_CODEGEN_CODEGENTYPES_H +#include "llvm/Module.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallSet.h" #include @@ -27,6 +28,7 @@ namespace llvm { class PATypeHolder; class TargetData; class Type; + class LLVMContext; } namespace clang { @@ -47,35 +49,44 @@ namespace clang { namespace CodeGen { class CodeGenTypes; - /// CGRecordLayout - This class handles struct and union layout info while + /// CGRecordLayout - This class handles struct and union layout info while /// lowering AST types to LLVM types. class CGRecordLayout { CGRecordLayout(); // DO NOT IMPLEMENT + + /// 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; + + /// KeyFunction - The key function of the record layout (if one exists), + /// which is the first non-pure virtual function that is not inline at the + /// point of class definition. + /// See http://www.codesourcery.com/public/cxx-abi/abi.html#vague-vtable. + const CXXMethodDecl *KeyFunction; + public: - CGRecordLayout(llvm::Type *T, llvm::SmallSet &PF) - : STy(T), PaddingFields(PF) { - // FIXME : Collect info about fields that requires adjustments - // (i.e. fields that do not directly map to llvm struct fields.) - } + CGRecordLayout(const llvm::Type *T, bool ContainsMemberPointer, + const CXXMethodDecl *KeyFunction) + : LLVMType(T), ContainsMemberPointer(ContainsMemberPointer), + KeyFunction(KeyFunction) { } /// getLLVMType - Return llvm type associated with this record. - llvm::Type *getLLVMType() const { - return STy; + const llvm::Type *getLLVMType() const { + return LLVMType; } - bool isPaddingField(unsigned No) const { - return PaddingFields.count(No) != 0; + bool containsMemberPointer() const { + return ContainsMemberPointer; } - unsigned getNumPaddingFields() { - return PaddingFields.size(); + const CXXMethodDecl *getKeyFunction() const { + return KeyFunction; } - - private: - llvm::Type *STy; - llvm::SmallSet PaddingFields; }; - + /// CodeGenTypes - This class organizes the cross-module state that is used /// while lowering AST types to LLVM types. class CodeGenTypes { @@ -84,7 +95,7 @@ class CodeGenTypes { llvm::Module& TheModule; const llvm::TargetData& TheTargetData; mutable const ABIInfo* TheABIInfo; - + llvm::SmallVector, 8> PointersToResolve; @@ -98,9 +109,9 @@ class CodeGenTypes { /// types are never refined. llvm::DenseMap InterfaceTypes; - /// CGRecordLayouts - This maps llvm struct type with corresponding - /// record layout info. - /// FIXME : If CGRecordLayout is less than 16 bytes then use + /// CGRecordLayouts - This maps llvm struct type with corresponding + /// record layout info. + /// FIXME : If CGRecordLayout is less than 16 bytes then use /// inline it in the map. llvm::DenseMap CGRecordLayouts; @@ -112,13 +123,15 @@ class CodeGenTypes { llvm::FoldingSet FunctionInfos; public: - class BitFieldInfo { - public: - explicit BitFieldInfo(unsigned short B, unsigned short S) - : Begin(B), Size(S) {} - - unsigned short Begin; - unsigned short Size; + struct BitFieldInfo { + BitFieldInfo(unsigned FieldNo, + unsigned Start, + unsigned Size) + : FieldNo(FieldNo), Start(Start), Size(Size) {} + + unsigned FieldNo; + unsigned Start; + unsigned Size; }; private: @@ -126,7 +139,7 @@ private: /// TypeCache - This map keeps cache of llvm::Types (through PATypeHolder) /// and maps llvm::Types to corresponding clang::Type. llvm::PATypeHolder is - /// used instead of llvm::Type because it allows us to bypass potential + /// used instead of llvm::Type because it allows us to bypass potential /// dangling type pointers due to type refinement on llvm side. llvm::DenseMap TypeCache; @@ -138,16 +151,17 @@ private: public: CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD); ~CodeGenTypes(); - + const llvm::TargetData &getTargetData() const { return TheTargetData; } TargetInfo &getTarget() const { return Target; } ASTContext &getContext() const { return Context; } const ABIInfo &getABIInfo() const; + llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); } - /// ConvertType - Convert type T into a llvm::Type. + /// ConvertType - Convert type T into a llvm::Type. const llvm::Type *ConvertType(QualType T); const llvm::Type *ConvertTypeRecursive(QualType T); - + /// ConvertTypeForMem - Convert type T into a llvm::Type. This differs from /// ConvertType in that it is used to convert to the memory representation for /// a type. For example, the scalar representation for _Bool is i1, but the @@ -158,39 +172,51 @@ public: /// GetFunctionType - Get the LLVM function type for \arg Info. const llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info, bool IsVariadic); - - const CGRecordLayout *getCGRecordLayout(const TagDecl*) const; - + + const CGRecordLayout &getCGRecordLayout(const TagDecl*) const; + /// getLLVMFieldNo - Return llvm::StructType element number /// that corresponds to the field FD. unsigned getLLVMFieldNo(const FieldDecl *FD); - + /// UpdateCompletedType - When we find the full definition for a TagDecl, /// replace the 'opaque' type we previously made for it if applicable. void UpdateCompletedType(const TagDecl *TD); - /// getFunctionInfo - Get the CGFunctionInfo for this function signature. - const CGFunctionInfo &getFunctionInfo(QualType RetTy, - const llvm::SmallVector - &ArgTys); - +private: const CGFunctionInfo &getFunctionInfo(const FunctionNoProtoType *FTNP); const CGFunctionInfo &getFunctionInfo(const FunctionProtoType *FTP); + +public: + /// getFunctionInfo - Get the function info for the specified function decl. const CGFunctionInfo &getFunctionInfo(const FunctionDecl *FD); const CGFunctionInfo &getFunctionInfo(const CXXMethodDecl *MD); const CGFunctionInfo &getFunctionInfo(const ObjCMethodDecl *MD); - const CGFunctionInfo &getFunctionInfo(QualType ResTy, - const CallArgList &Args); -public: - const CGFunctionInfo &getFunctionInfo(QualType ResTy, - const FunctionArgList &Args); + // getFunctionInfo - Get the function info for a member function. + const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD, + const FunctionProtoType *FTP); + + /// getFunctionInfo - Get the function info for a function described by a + /// return type and argument types. If the calling convention is not + /// specified, the "C" calling convention will be used. + const CGFunctionInfo &getFunctionInfo(QualType ResTy, + const CallArgList &Args, + unsigned CallingConvention = 0); + const CGFunctionInfo &getFunctionInfo(QualType ResTy, + const FunctionArgList &Args, + unsigned CallingConvention = 0); + const CGFunctionInfo &getFunctionInfo(QualType RetTy, + const llvm::SmallVector &ArgTys, + unsigned CallingConvention = 0); + public: // These are internal details of CGT that shouldn't be used externally. /// addFieldInfo - Assign field number to field FD. - void addFieldInfo(const FieldDecl *FD, unsigned No); + void addFieldInfo(const FieldDecl *FD, unsigned FieldNo); /// addBitFieldInfo - Assign a start bit and a size to field FD. - void addBitFieldInfo(const FieldDecl *FD, unsigned Begin, unsigned Size); + void addBitFieldInfo(const FieldDecl *FD, unsigned FieldNo, + unsigned Start, unsigned Size); /// getBitFieldInfo - Return the BitFieldInfo that corresponds to the field /// FD. diff --git a/lib/CodeGen/Makefile b/lib/CodeGen/Makefile index e716fe78bc60..108490b71d48 100644 --- a/lib/CodeGen/Makefile +++ b/lib/CodeGen/Makefile @@ -18,6 +18,9 @@ BUILD_ARCHIVE = 1 CXXFLAGS = -fno-rtti CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +ifdef CLANG_VENDOR +CPPFLAGS += -DCLANG_VENDOR='"$(CLANG_VENDOR) "' +endif include $(LEVEL)/Makefile.common diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 8018b4f45a84..fd772748dbda 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -20,85 +20,125 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" #include "clang/Basic/SourceManager.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" using namespace clang; namespace { class VISIBILITY_HIDDEN CXXNameMangler { - ASTContext &Context; + MangleContext &Context; llvm::raw_ostream &Out; const CXXMethodDecl *Structor; unsigned StructorType; CXXCtorType CtorType; + + llvm::DenseMap Substitutions; public: - CXXNameMangler(ASTContext &C, llvm::raw_ostream &os) + CXXNameMangler(MangleContext &C, llvm::raw_ostream &os) : Context(C), Out(os), Structor(0), StructorType(0) { } bool mangle(const NamedDecl *D); + void mangleCalloffset(int64_t nv, int64_t v); + void mangleThunk(const FunctionDecl *FD, int64_t nv, int64_t v); + void mangleCovariantThunk(const FunctionDecl *FD, + int64_t nv_t, int64_t v_t, + int64_t nv_r, int64_t v_r); void mangleGuardVariable(const VarDecl *D); - + + void mangleCXXVtable(const CXXRecordDecl *RD); + void mangleCXXRtti(const CXXRecordDecl *RD); void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type); void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type); private: - bool mangleFunctionDecl(const FunctionDecl *FD); + bool mangleSubstitution(const NamedDecl *ND); + bool mangleSubstitution(QualType T); + bool mangleSubstitution(uintptr_t Ptr); + + bool mangleStandardSubstitution(const NamedDecl *ND); + void addSubstitution(const NamedDecl *ND) { + addSubstitution(reinterpret_cast(ND)); + } + void addSubstitution(QualType T); + void addSubstitution(uintptr_t Ptr); + + bool mangleFunctionDecl(const FunctionDecl *FD); + void mangleFunctionEncoding(const FunctionDecl *FD); void mangleName(const NamedDecl *ND); + void mangleName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); void mangleUnqualifiedName(const NamedDecl *ND); + void mangleUnscopedName(const NamedDecl *ND); + void mangleUnscopedTemplateName(const TemplateDecl *ND); void mangleSourceName(const IdentifierInfo *II); void mangleLocalName(const NamedDecl *ND); void mangleNestedName(const NamedDecl *ND); + void mangleNestedName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); void manglePrefix(const DeclContext *DC); + void mangleTemplatePrefix(const TemplateDecl *ND); void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); - void mangleCVQualifiers(unsigned Quals); + void mangleQualifiers(Qualifiers Quals); void mangleType(QualType T); - void mangleType(const BuiltinType *T); - void mangleType(const FunctionType *T); - void mangleBareFunctionType(const FunctionType *T, bool MangleReturnType); - void mangleType(const TagType *T); - void mangleType(const ArrayType *T); - void mangleType(const MemberPointerType *T); - void mangleType(const TemplateTypeParmType *T); - void mangleType(const ObjCInterfaceType *T); - void mangleExpression(Expr *E); + + // Declare manglers for every type class. +#define ABSTRACT_TYPE(CLASS, PARENT) +#define NON_CANONICAL_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T); +#include "clang/AST/TypeNodes.def" + + void mangleType(const TagType*); + void mangleBareFunctionType(const FunctionType *T, + bool MangleReturnType); + void mangleExpression(const Expr *E); void mangleCXXCtorType(CXXCtorType T); void mangleCXXDtorType(CXXDtorType T); - + + void mangleTemplateArgs(const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); void mangleTemplateArgumentList(const TemplateArgumentList &L); void mangleTemplateArgument(const TemplateArgument &A); + + void mangleTemplateParameter(unsigned Index); }; } static bool isInCLinkageSpecification(const Decl *D) { - for (const DeclContext *DC = D->getDeclContext(); + for (const DeclContext *DC = D->getDeclContext(); !DC->isTranslationUnit(); DC = DC->getParent()) { - if (const LinkageSpecDecl *Linkage = dyn_cast(DC)) + if (const LinkageSpecDecl *Linkage = dyn_cast(DC)) return Linkage->getLanguage() == LinkageSpecDecl::lang_c; } - + return false; } bool CXXNameMangler::mangleFunctionDecl(const FunctionDecl *FD) { - // Clang's "overloadable" attribute extension to C/C++ implies - // name mangling (always). + // Clang's "overloadable" attribute extension to C/C++ implies name mangling + // (always). if (!FD->hasAttr()) { // C functions are not mangled, and "main" is never mangled. - if (!Context.getLangOptions().CPlusPlus || FD->isMain()) + if (!Context.getASTContext().getLangOptions().CPlusPlus || FD->isMain()) return false; - - // No mangling in an "implicit extern C" header. + + // No mangling in an "implicit extern C" header. if (FD->getLocation().isValid() && - Context.getSourceManager().isInExternCSystemHeader(FD->getLocation())) + Context.getASTContext().getSourceManager(). + isInExternCSystemHeader(FD->getLocation())) return false; - + // No name mangling in a C linkage specification. - if (isInCLinkageSpecification(FD)) + if (!isa(FD) && isInCLinkageSpecification(FD)) return false; } @@ -109,15 +149,15 @@ bool CXXNameMangler::mangleFunctionDecl(const FunctionDecl *FD) { } bool CXXNameMangler::mangle(const NamedDecl *D) { - // Any decl can be declared with __asm("foo") on it, and this takes - // precedence over all other naming in the .o file. + // Any decl can be declared with __asm("foo") on it, and this takes precedence + // over all other naming in the .o file. if (const AsmLabelAttr *ALA = D->getAttr()) { // If we have an asm name, then we use it as the mangling. Out << '\01'; // LLVM IR Marker for __asm("foo") Out << ALA->getLabel(); return true; } - + // ::= _Z // ::= // ::= @@ -125,43 +165,54 @@ bool CXXNameMangler::mangle(const NamedDecl *D) { // FIXME: Actually use a visitor to decode these? if (const FunctionDecl *FD = dyn_cast(D)) return mangleFunctionDecl(FD); - + if (const VarDecl *VD = dyn_cast(D)) { - if (!Context.getLangOptions().CPlusPlus || + if (!Context.getASTContext().getLangOptions().CPlusPlus || isInCLinkageSpecification(D) || D->getDeclContext()->isTranslationUnit()) return false; - + Out << "_Z"; mangleName(VD); return true; } - + return false; } -void CXXNameMangler::mangleCXXCtor(const CXXConstructorDecl *D, +void CXXNameMangler::mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type) { assert(!Structor && "Structor already set!"); Structor = D; StructorType = Type; - + mangle(D); } -void CXXNameMangler::mangleCXXDtor(const CXXDestructorDecl *D, +void CXXNameMangler::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type) { assert(!Structor && "Structor already set!"); Structor = D; StructorType = Type; - + mangle(D); } -void CXXNameMangler::mangleGuardVariable(const VarDecl *D) -{ - // ::= GV # Guard variable for one-time - // # initialization +void CXXNameMangler::mangleCXXVtable(const CXXRecordDecl *RD) { + // ::= TV # virtual table + Out << "_ZTV"; + mangleName(RD); +} + +void CXXNameMangler::mangleCXXRtti(const CXXRecordDecl *RD) { + // ::= TI # typeinfo structure + Out << "_ZTI"; + mangleName(RD); +} + +void CXXNameMangler::mangleGuardVariable(const VarDecl *D) { + // ::= GV # Guard variable for one-time + // # initialization Out << "_ZGV"; mangleName(D); @@ -170,29 +221,34 @@ void CXXNameMangler::mangleGuardVariable(const VarDecl *D) void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { // ::= mangleName(FD); - - // Whether the mangling of a function type includes the return type depends - // on the context and the nature of the function. The rules for deciding - // whether the return type is included are: - // + + // Whether the mangling of a function type includes the return type depends on + // the context and the nature of the function. The rules for deciding whether + // the return type is included are: + // // 1. Template functions (names or types) have return types encoded, with // the exceptions listed below. - // 2. Function types not appearing as part of a function name mangling, + // 2. Function types not appearing as part of a function name mangling, // e.g. parameters, pointer types, etc., have return type encoded, with the // exceptions listed below. // 3. Non-template function names do not have return types encoded. // - // The exceptions mentioned in (1) and (2) above, for which the return - // type is never included, are + // The exceptions mentioned in (1) and (2) above, for which the return type is + // never included, are // 1. Constructors. // 2. Destructors. // 3. Conversion operator functions, e.g. operator int. bool MangleReturnType = false; - if (FD->getPrimaryTemplate() && - !(isa(FD) || isa(FD) || - isa(FD))) - MangleReturnType = true; - mangleBareFunctionType(FD->getType()->getAsFunctionType(), MangleReturnType); + if (FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate()) { + if (!(isa(FD) || isa(FD) || + isa(FD))) + MangleReturnType = true; + + // Mangle the type of the primary template. + FD = PrimaryTemplate->getTemplatedDecl(); + } + + mangleBareFunctionType(FD->getType()->getAs(), MangleReturnType); } static bool isStdNamespace(const DeclContext *DC) { @@ -200,37 +256,196 @@ static bool isStdNamespace(const DeclContext *DC) { return false; const NamespaceDecl *NS = cast(DC); - return NS->getOriginalNamespace()->getIdentifier()->isStr("std"); + const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier(); + return II && II->isStr("std"); +} + +static const TemplateDecl * +isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) { + // Check if we have a function template. + if (const FunctionDecl *FD = dyn_cast(ND)){ + if (const TemplateDecl *TD = FD->getPrimaryTemplate()) { + TemplateArgs = FD->getTemplateSpecializationArgs(); + return TD; + } + } + + // Check if we have a class template. + if (const ClassTemplateSpecializationDecl *Spec = + dyn_cast(ND)) { + TemplateArgs = &Spec->getTemplateArgs(); + return Spec->getSpecializedTemplate(); + } + + return 0; } void CXXNameMangler::mangleName(const NamedDecl *ND) { // ::= // ::= // ::= - // ::= # See Scope Encoding below + // ::= // + const DeclContext *DC = ND->getDeclContext(); + while (isa(DC)) + DC = DC->getParent(); + + if (DC->isTranslationUnit() || isStdNamespace(DC)) { + // Check if we have a template. + const TemplateArgumentList *TemplateArgs = 0; + if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { + mangleUnscopedTemplateName(TD); + mangleTemplateArgumentList(*TemplateArgs); + return; + } + + mangleUnscopedName(ND); + return; + } + + if (isa(DC)) { + mangleLocalName(ND); + return; + } + + mangleNestedName(ND); +} +void CXXNameMangler::mangleName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + const DeclContext *DC = TD->getDeclContext(); + while (isa(DC)) { + assert(cast(DC)->getLanguage() == + LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!"); + DC = DC->getParent(); + } + + if (DC->isTranslationUnit() || isStdNamespace(DC)) { + mangleUnscopedTemplateName(TD); + mangleTemplateArgs(TemplateArgs, NumTemplateArgs); + } else { + mangleNestedName(TD, TemplateArgs, NumTemplateArgs); + } +} + +void CXXNameMangler::mangleUnscopedName(const NamedDecl *ND) { // ::= // ::= St # ::std:: - if (ND->getDeclContext()->isTranslationUnit()) - mangleUnqualifiedName(ND); - else if (isStdNamespace(ND->getDeclContext())) { + if (isStdNamespace(ND->getDeclContext())) Out << "St"; - mangleUnqualifiedName(ND); - } else if (isa(ND->getDeclContext())) - mangleLocalName(ND); - else - mangleNestedName(ND); + + mangleUnqualifiedName(ND); +} + +void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) { + // ::= + // ::= + if (mangleSubstitution(ND)) + return; + + mangleUnscopedName(ND->getTemplatedDecl()); + addSubstitution(ND); +} + +void CXXNameMangler::mangleCalloffset(int64_t nv, int64_t v) { + // ::= h _ + // ::= v _ + // ::= # non-virtual base override + // ::= _ + // # virtual base override, with vcall offset + if (v == 0) { + Out << "h"; + if (nv < 0) { + Out << "n"; + nv = -nv; + } + Out << nv; + } else { + Out << "v"; + if (nv < 0) { + Out << "n"; + nv = -nv; + } + Out << nv; + Out << "_"; + if (v < 0) { + Out << "n"; + v = -v; + } + Out << v; + } + Out << "_"; +} + +void CXXNameMangler::mangleThunk(const FunctionDecl *FD, int64_t nv, + int64_t v) { + // ::= T + // # base is the nominal target function of thunk + Out << "_ZT"; + mangleCalloffset(nv, v); + mangleFunctionEncoding(FD); +} + + void CXXNameMangler::mangleCovariantThunk(const FunctionDecl *FD, + int64_t nv_t, int64_t v_t, + int64_t nv_r, int64_t v_r) { + // ::= Tc + // # base is the nominal target function of thunk + // # first call-offset is 'this' adjustment + // # second call-offset is result adjustment + Out << "_ZTc"; + mangleCalloffset(nv_t, v_t); + mangleCalloffset(nv_r, v_r); + mangleFunctionEncoding(FD); } void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { // ::= - // ::= - // ::= + // ::= + // ::= DeclarationName Name = ND->getDeclName(); switch (Name.getNameKind()) { - case DeclarationName::Identifier: - mangleSourceName(Name.getAsIdentifierInfo()); + case DeclarationName::Identifier: { + if (const NamespaceDecl *NS = dyn_cast(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. + 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(ND); + if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) { + assert(TD->getDeclContext() == D->getDeclContext() && + "Typedef should not be in another decl context!"); + assert(D->getDeclName().getAsIdentifierInfo() && + "Typedef was not named!"); + mangleSourceName(D->getDeclName().getAsIdentifierInfo()); + break; + } + + // Get a unique id for the anonymous struct. + uint64_t AnonStructId = Context.getAnonymousStructId(TD); + + // Mangle it as a source name in the form + // [n] $_ + // where n is the length of the string. + llvm::SmallString<8> Str; + Str += "$_"; + Str += llvm::utostr(AnonStructId); + + Out << Str.size(); + Out << Str.str(); break; + } case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: @@ -240,8 +455,8 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { case DeclarationName::CXXConstructorName: if (ND == Structor) - // If the named decl is the C++ constructor we're mangling, use the - // type we were given. + // If the named decl is the C++ constructor we're mangling, use the type + // we were given. mangleCXXCtorType(static_cast(StructorType)); else // Otherwise, use the complete constructor name. This is relevant if a @@ -251,8 +466,8 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { case DeclarationName::CXXDestructorName: if (ND == Structor) - // If the named decl is the C++ destructor we're mangling, use the - // type we were given. + // If the named decl is the C++ destructor we're mangling, use the type we + // were given. mangleCXXDtorType(static_cast(StructorType)); else // Otherwise, use the complete destructor name. This is relevant if a @@ -261,9 +476,9 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { break; case DeclarationName::CXXConversionFunctionName: - // ::= cv # (cast) + // ::= cv # (cast) Out << "cv"; - mangleType(Context.getCanonicalType(Name.getCXXNameType())); + mangleType(Context.getASTContext().getCanonicalType(Name.getCXXNameType())); break; case DeclarationName::CXXOperatorName: @@ -275,12 +490,6 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { assert(false && "Can't mangle a using directive name!"); break; } - - if (const FunctionDecl *Function = dyn_cast(ND)) { - if (const TemplateArgumentList *TemplateArgs - = Function->getTemplateSpecializationArgs()) - mangleTemplateArgumentList(*TemplateArgs); - } } void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) { @@ -293,19 +502,40 @@ void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) { void CXXNameMangler::mangleNestedName(const NamedDecl *ND) { // ::= N [] E // ::= N [] E - // FIXME: no template support + Out << 'N'; if (const CXXMethodDecl *Method = dyn_cast(ND)) - mangleCVQualifiers(Method->getTypeQualifiers()); - manglePrefix(ND->getDeclContext()); - mangleUnqualifiedName(ND); + mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers())); + + // Check if we have a template. + const TemplateArgumentList *TemplateArgs = 0; + if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { + mangleTemplatePrefix(TD); + mangleTemplateArgumentList(*TemplateArgs); + } else { + manglePrefix(ND->getDeclContext()); + mangleUnqualifiedName(ND); + } + + Out << 'E'; +} +void CXXNameMangler::mangleNestedName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + // ::= N [] E + + Out << 'N'; + + mangleTemplatePrefix(TD); + mangleTemplateArgs(TemplateArgs, NumTemplateArgs); + Out << 'E'; } void CXXNameMangler::mangleLocalName(const NamedDecl *ND) { // := Z E [] // := Z E s [] - // := _ + // := _ Out << 'Z'; mangleFunctionEncoding(cast(ND->getDeclContext())); Out << 'E'; @@ -319,21 +549,46 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC) { // ::= # empty // ::= // FIXME: We only handle mangling of namespaces and classes at the moment. - if (!DC->getParent()->isTranslationUnit()) - manglePrefix(DC->getParent()); - if (const NamespaceDecl *Namespace = dyn_cast(DC)) - mangleSourceName(Namespace->getIdentifier()); - else if (const RecordDecl *Record = dyn_cast(DC)) { - if (const ClassTemplateSpecializationDecl *D = - dyn_cast(Record)) { - mangleType(QualType(D->getTypeForDecl(), 0)); - } else - mangleSourceName(Record->getIdentifier()); + while (isa(DC)) + DC = DC->getParent(); + + if (DC->isTranslationUnit()) + return; + + if (mangleSubstitution(cast(DC))) + return; + + // Check if we have a template. + const TemplateArgumentList *TemplateArgs = 0; + if (const TemplateDecl *TD = isTemplate(cast(DC), TemplateArgs)) { + mangleTemplatePrefix(TD); + mangleTemplateArgumentList(*TemplateArgs); + } else { + manglePrefix(DC->getParent()); + mangleUnqualifiedName(cast(DC)); } + + addSubstitution(cast(DC)); +} + +void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) { + // ::=