From 6b9a6e390fbb92c40eb9c6ac9e7abbd88dd7a767 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Thu, 3 May 2012 16:53:59 +0000 Subject: [PATCH] Vendor import of clang release_31 branch r155985: http://llvm.org/svn/llvm-project/cfe/branches/release_31@155985 --- CMakeLists.txt | 4 + bindings/python/clang/cindex.py | 9 + bindings/python/tests/cindex/test_type.py | 9 +- examples/clang-interpreter/CMakeLists.txt | 1 - include/clang/AST/Decl.h | 7 +- include/clang/AST/DeclBase.h | 1 - include/clang/AST/DeclLookups.h | 4 + include/clang/AST/Expr.h | 14 +- include/clang/AST/ExternalASTSource.h | 6 + include/clang/AST/RecursiveASTVisitor.h | 1 + include/clang/AST/Stmt.h | 42 ++ include/clang/AST/Type.h | 34 +- include/clang/AST/VTableBuilder.h | 12 +- include/clang/Analysis/ProgramPoint.h | 2 +- include/clang/Basic/BuiltinsX86.def | 6 +- include/clang/Basic/ConvertUTF.h | 2 +- include/clang/Basic/DelayedCleanupPool.h | 110 ---- include/clang/Basic/DiagnosticParseKinds.td | 2 + include/clang/Basic/DiagnosticSemaKinds.td | 23 +- .../clang/Basic/ExceptionSpecificationType.h | 18 +- include/clang/Basic/OnDiskHashTable.h | 33 +- include/clang/Basic/StmtNodes.td | 1 + include/clang/Basic/TargetInfo.h | 15 + include/clang/Basic/TokenKinds.def | 1 + include/clang/Config/config.h.cmake | 9 +- include/clang/Config/config.h.in | 9 +- include/clang/Driver/CC1Options.td | 3 - include/clang/Driver/Compilation.h | 3 + include/clang/Frontend/ASTUnit.h | 10 - include/clang/Frontend/FrontendActions.h | 9 - include/clang/Frontend/FrontendOptions.h | 1 - include/clang/Frontend/TextDiagnostic.h | 11 +- include/clang/Index/ASTLocation.h | 173 ----- include/clang/Index/Analyzer.h | 56 -- include/clang/Index/DeclReferenceMap.h | 50 -- include/clang/Index/Entity.h | 149 ----- include/clang/Index/GlobalCallGraph.h | 149 ----- include/clang/Index/GlobalSelector.h | 100 --- include/clang/Index/Handlers.h | 82 --- include/clang/Index/IndexProvider.h | 38 -- include/clang/Index/Indexer.h | 71 -- include/clang/Index/Program.h | 45 -- include/clang/Index/STLExtras.h | 63 -- include/clang/Index/SelectorMap.h | 57 -- include/clang/Index/TranslationUnit.h | 41 -- include/clang/Parse/Parser.h | 84 +-- include/clang/Sema/DeclSpec.h | 7 + include/clang/Sema/ParsedTemplate.h | 8 +- include/clang/Sema/Scope.h | 7 +- include/clang/Sema/Sema.h | 119 +++- include/clang/Serialization/ASTBitCodes.h | 2 + include/clang/Serialization/ASTReader.h | 9 +- include/clang/Serialization/ASTWriter.h | 1 + include/clang/Serialization/Module.h | 10 +- .../Core/PathSensitive/AnalysisManager.h | 17 - .../StaticAnalyzer/Core/PathSensitive/SVals.h | 2 + include/clang/Tooling/CompilationDatabase.h | 76 ++- lib/AST/ASTContext.cpp | 5 +- lib/AST/Decl.cpp | 119 ++-- lib/AST/Expr.cpp | 335 +--------- lib/AST/ExprConstant.cpp | 56 +- lib/AST/ExternalASTSource.cpp | 5 +- lib/AST/ItaniumMangle.cpp | 23 +- lib/AST/Stmt.cpp | 6 +- lib/AST/StmtPrinter.cpp | 17 + lib/AST/StmtProfile.cpp | 6 + lib/AST/Type.cpp | 10 + lib/AST/VTableBuilder.cpp | 9 +- lib/Analysis/CFG.cpp | 9 +- lib/Analysis/CMakeLists.txt | 2 +- lib/Basic/TargetInfo.cpp | 1 + lib/Basic/Targets.cpp | 7 +- lib/Basic/Version.cpp | 2 +- lib/CMakeLists.txt | 1 - lib/CodeGen/CGBlocks.cpp | 2 + lib/CodeGen/CGCall.cpp | 130 ++-- lib/CodeGen/CGClass.cpp | 13 +- lib/CodeGen/CGDebugInfo.cpp | 16 +- lib/CodeGen/CGDecl.cpp | 4 + lib/CodeGen/CGExpr.cpp | 115 ++-- lib/CodeGen/CGExprAgg.cpp | 34 +- lib/CodeGen/CGExprCXX.cpp | 5 +- lib/CodeGen/CGExprConstant.cpp | 8 +- lib/CodeGen/CGStmt.cpp | 7 + lib/CodeGen/CodeGenFunction.cpp | 11 +- lib/CodeGen/CodeGenFunction.h | 11 +- lib/CodeGen/CodeGenModule.cpp | 2 +- lib/CodeGen/CodeGenTBAA.cpp | 36 +- lib/CodeGen/CodeGenTBAA.h | 8 +- lib/CodeGen/TargetInfo.cpp | 24 +- lib/Driver/Compilation.cpp | 4 + lib/Driver/Driver.cpp | 54 +- lib/Driver/ToolChains.cpp | 7 +- lib/Driver/Tools.cpp | 10 +- lib/Frontend/ASTUnit.cpp | 6 +- lib/Frontend/CompilerInstance.cpp | 4 + lib/Frontend/CompilerInvocation.cpp | 3 - lib/Frontend/FrontendActions.cpp | 72 --- lib/Frontend/TextDiagnostic.cpp | 605 +++++++++++++----- .../ExecuteCompilerInvocation.cpp | 1 - lib/Headers/avx2intrin.h | 14 +- lib/Headers/avxintrin.h | 26 +- lib/Index/ASTLocation.cpp | 114 ---- lib/Index/ASTVisitor.h | 143 ----- lib/Index/Analyzer.cpp | 470 -------------- lib/Index/CMakeLists.txt | 18 - lib/Index/DeclReferenceMap.cpp | 90 --- lib/Index/Entity.cpp | 270 -------- lib/Index/EntityImpl.h | 71 -- lib/Index/GlobalCallGraph.cpp | 152 ----- lib/Index/GlobalSelector.cpp | 71 -- lib/Index/Handlers.cpp | 22 - lib/Index/IndexProvider.cpp | 20 - lib/Index/Indexer.cpp | 121 ---- lib/Index/Makefile | 18 - lib/Index/Program.cpp | 50 -- lib/Index/ProgramImpl.h | 56 -- lib/Index/SelectorMap.cpp | 84 --- lib/Makefile | 2 +- lib/Parse/ParseCXXInlineMethods.cpp | 94 ++- lib/Parse/ParseDecl.cpp | 54 +- lib/Parse/ParseDeclCXX.cpp | 101 ++- lib/Parse/ParseExpr.cpp | 6 +- lib/Parse/ParseExprCXX.cpp | 17 +- lib/Parse/ParseStmt.cpp | 181 +++--- lib/Parse/ParseTemplate.cpp | 3 +- lib/Parse/Parser.cpp | 28 +- lib/Rewrite/RewriteModernObjC.cpp | 158 ++--- lib/Rewrite/RewriteRope.cpp | 5 + lib/Sema/CMakeLists.txt | 1 + lib/Sema/DeclSpec.cpp | 5 + lib/Sema/Sema.cpp | 1 + lib/Sema/SemaAccess.cpp | 7 + lib/Sema/SemaDecl.cpp | 26 +- lib/Sema/SemaDeclCXX.cpp | 341 ++++++++-- lib/Sema/SemaExceptionSpec.cpp | 359 ++++++++++- lib/Sema/SemaExpr.cpp | 33 +- lib/Sema/SemaExprCXX.cpp | 73 ++- lib/Sema/SemaExprMember.cpp | 17 +- lib/Sema/SemaLookup.cpp | 45 +- lib/Sema/SemaOverload.cpp | 2 + lib/Sema/SemaPseudoObject.cpp | 28 +- lib/Sema/SemaStmt.cpp | 11 +- lib/Sema/SemaStmtAttr.cpp | 48 ++ lib/Sema/SemaTemplate.cpp | 4 + lib/Sema/SemaTemplateDeduction.cpp | 49 +- lib/Sema/SemaTemplateInstantiate.cpp | 99 ++- lib/Sema/SemaTemplateInstantiateDecl.cpp | 363 +++++++---- lib/Sema/SemaType.cpp | 51 +- lib/Sema/TreeTransform.h | 66 +- lib/Serialization/ASTReader.cpp | 148 +++-- lib/Serialization/ASTReaderDecl.cpp | 9 +- lib/Serialization/ASTReaderInternals.h | 10 +- lib/Serialization/ASTReaderStmt.cpp | 15 +- lib/Serialization/ASTWriter.cpp | 1 + lib/Serialization/ASTWriterDecl.cpp | 3 + lib/Serialization/ASTWriterStmt.cpp | 8 + lib/Serialization/Module.cpp | 3 +- .../Checkers/ObjCSelfInitChecker.cpp | 25 +- lib/StaticAnalyzer/Core/AnalysisManager.cpp | 24 +- lib/StaticAnalyzer/Core/CoreEngine.cpp | 1 - lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 + .../Core/ExprEngineCallAndReturn.cpp | 5 + .../Frontend/AnalysisConsumer.cpp | 1 - lib/Tooling/CompilationDatabase.cpp | 110 ++-- test/Analysis/objc-bool.m | 2 +- test/Analysis/redefined_system.c | 2 +- test/Analysis/self-init.m | 61 +- test/CXX/class/class.mem/p2.cpp | 27 + test/CXX/except/except.spec/p1.cpp | 4 +- .../expr.prim/expr.prim.general/p3-0x.cpp | 100 +++ test/CXX/special/class.inhctor/elsewhere.cpp | 16 +- test/CXX/special/class.inhctor/p3.cpp | 12 +- test/CXX/special/class.inhctor/p7.cpp | 12 +- test/CXX/temp/temp.decls/temp.variadic/p5.cpp | 2 +- test/CodeCompletion/preamble.c | 7 + test/CodeCompletion/some_struct.h | 1 + test/CodeGen/arm-homogenous.c | 160 +++++ test/CodeGen/avx-shuffle-builtins.c | 6 +- test/CodeGen/avx2-builtins.c | 6 +- test/CodeGen/builtins-x86.c | 3 + test/CodeGen/may-alias.c | 2 +- test/CodeGen/packed-nest-unpacked.c | 18 +- test/CodeGen/tbaa-for-vptr.cpp | 2 +- test/CodeGenCXX/block-byref-cxx-objc.cpp | 10 + test/CodeGenCXX/const-init-cxx11.cpp | 3 + test/CodeGenCXX/cxx11-exception-spec.cpp | 120 ++++ test/CodeGenCXX/inheriting-constructor.cpp | 2 + test/CodeGenCXX/mangle-this-cxx11.cpp | 20 + test/CodeGenCXX/static-init.cpp | 2 + .../{fpaccuracy.cl => fpmath.cl} | 6 +- test/Headers/typedef_guards.c | 2 +- test/Index/get-cursor.m | 17 + test/Lexer/newline-eof-c++98-compat.cpp | 2 +- test/Lexer/newline-eof.c | 2 +- test/Lexer/utf-16.c | 2 +- test/Misc/message-length.c | 3 +- test/Misc/pubnames.c | 19 - test/Misc/unprintable.c | 16 + test/Misc/wnull-character.cpp | Bin 0 -> 143 bytes test/Misc/wrong-encoding.c | 16 + test/PCH/typo2.cpp | 13 + test/Parser/MicrosoftExtensions.cpp | 29 +- test/Parser/cxx11-stmt-attributes.cpp | 54 ++ test/Parser/objcxx11-attributes.mm | 8 +- test/Preprocessor/pragma_sysheader.c | 2 +- test/Rewriter/blockcast3.mm | 7 +- test/Rewriter/instancetype-test.mm | 6 +- .../objc-bool-literal-check-modern.mm | 12 +- test/Rewriter/objc-bool-literal-modern.mm | 2 +- test/Rewriter/objc-modern-numeric-literal.mm | 10 +- test/Rewriter/rewrite-block-consts.mm | 2 +- test/Rewriter/rewrite-block-literal-1.mm | 3 + test/Rewriter/rewrite-block-literal.mm | 4 +- test/Rewriter/rewrite-block-pointer.mm | 2 + .../rewrite-byref-in-nested-blocks.mm | 2 + test/Rewriter/rewrite-elaborated-type.mm | 6 +- test/Rewriter/rewrite-foreach-in-block.mm | 2 + .../rewrite-modern-container-literal.mm | 2 +- .../rewrite-modern-extern-c-func-decl.mm | 48 ++ test/Rewriter/rewrite-modern-protocol-1.mm | 14 + test/Rewriter/rewrite-modern-super.mm | 23 + test/Rewriter/rewrite-modern-typeof.mm | 46 ++ test/Rewriter/rewrite-nested-blocks-1.mm | 2 + test/Rewriter/rewrite-nested-blocks-2.mm | 3 + test/Rewriter/rewrite-nested-blocks.mm | 2 + .../rewrite-nested-property-in-blocks.mm | 2 + test/Rewriter/rewrite-unique-block-api.mm | 2 + test/Sema/const-eval-64.c | 7 + test/Sema/const-eval.c | 10 + test/Sema/surpress-deprecated.c | 2 +- test/SemaCXX/constant-expression-cxx11.cpp | 4 + test/SemaCXX/cxx98-compat.cpp | 6 +- .../dependent-noexcept-unevaluated.cpp | 2 +- test/SemaCXX/implicit-exception-spec.cpp | 10 +- test/SemaCXX/warn-everthing.cpp | 8 +- test/SemaCXX/warn-thread-safety-parsing.cpp | 2 +- test/SemaObjC/error-implicit-property.m | 30 + test/SemaObjC/objc-literal-nsnumber.m | 4 +- test/SemaObjCXX/literals.mm | 2 +- test/SemaObjCXX/property-reference.mm | 15 + test/SemaTemplate/default-expr-arguments.cpp | 11 + test/SemaTemplate/dependent-names.cpp | 32 + test/SemaTemplate/instantiate-declref.cpp | 10 + .../instantiate-exception-spec-cxx11.cpp | 133 ++++ test/Tooling/clang-check-args.cpp | 8 + tools/arcmt-test/Makefile | 2 +- tools/c-arcmt-test/Makefile | 2 +- tools/c-index-test/Makefile | 2 +- tools/c-index-test/c-index-test.c | 1 + tools/clang-check/ClangCheck.cpp | 16 +- tools/driver/CMakeLists.txt | 1 - tools/driver/Makefile | 2 +- tools/libclang/CIndex.cpp | 34 +- tools/libclang/CMakeLists.txt | 1 - tools/libclang/CXCursor.cpp | 14 +- tools/libclang/Makefile | 5 + tools/scan-build/ccc-analyzer | 2 + unittests/Frontend/Makefile | 2 +- unittests/Tooling/CompilationDatabaseTest.cpp | 69 ++ www/cxx_status.html | 7 +- www/hacking.html | 12 +- www/libstdc++4.7-clang11.patch | 13 + 263 files changed, 4663 insertions(+), 4896 deletions(-) delete mode 100644 include/clang/Basic/DelayedCleanupPool.h delete mode 100644 include/clang/Index/ASTLocation.h delete mode 100644 include/clang/Index/Analyzer.h delete mode 100644 include/clang/Index/DeclReferenceMap.h delete mode 100644 include/clang/Index/Entity.h delete mode 100644 include/clang/Index/GlobalCallGraph.h delete mode 100644 include/clang/Index/GlobalSelector.h delete mode 100644 include/clang/Index/Handlers.h delete mode 100644 include/clang/Index/IndexProvider.h delete mode 100644 include/clang/Index/Indexer.h delete mode 100644 include/clang/Index/Program.h delete mode 100644 include/clang/Index/STLExtras.h delete mode 100644 include/clang/Index/SelectorMap.h delete mode 100644 include/clang/Index/TranslationUnit.h delete mode 100644 lib/Index/ASTLocation.cpp delete mode 100644 lib/Index/ASTVisitor.h delete mode 100644 lib/Index/Analyzer.cpp delete mode 100644 lib/Index/CMakeLists.txt delete mode 100644 lib/Index/DeclReferenceMap.cpp delete mode 100644 lib/Index/Entity.cpp delete mode 100644 lib/Index/EntityImpl.h delete mode 100644 lib/Index/GlobalCallGraph.cpp delete mode 100644 lib/Index/GlobalSelector.cpp delete mode 100644 lib/Index/Handlers.cpp delete mode 100644 lib/Index/IndexProvider.cpp delete mode 100644 lib/Index/Indexer.cpp delete mode 100644 lib/Index/Makefile delete mode 100644 lib/Index/Program.cpp delete mode 100644 lib/Index/ProgramImpl.h delete mode 100644 lib/Index/SelectorMap.cpp create mode 100644 lib/Sema/SemaStmtAttr.cpp create mode 100644 test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp create mode 100644 test/CodeCompletion/preamble.c create mode 100644 test/CodeCompletion/some_struct.h create mode 100644 test/CodeGen/arm-homogenous.c create mode 100644 test/CodeGenCXX/cxx11-exception-spec.cpp create mode 100644 test/CodeGenCXX/mangle-this-cxx11.cpp rename test/CodeGenOpenCL/{fpaccuracy.cl => fpmath.cl} (79%) delete mode 100644 test/Misc/pubnames.c create mode 100644 test/Misc/unprintable.c create mode 100644 test/Misc/wnull-character.cpp create mode 100644 test/Misc/wrong-encoding.c create mode 100644 test/PCH/typo2.cpp create mode 100644 test/Parser/cxx11-stmt-attributes.cpp create mode 100644 test/Rewriter/rewrite-modern-extern-c-func-decl.mm create mode 100644 test/Rewriter/rewrite-modern-protocol-1.mm create mode 100644 test/Rewriter/rewrite-modern-super.mm create mode 100644 test/Rewriter/rewrite-modern-typeof.mm create mode 100644 test/Sema/const-eval-64.c create mode 100644 test/SemaObjC/error-implicit-property.m create mode 100644 test/SemaTemplate/instantiate-exception-spec-cxx11.cpp create mode 100644 test/Tooling/clang-check-args.cpp create mode 100644 www/libstdc++4.7-clang11.patch diff --git a/CMakeLists.txt b/CMakeLists.txt index 1197610f7b1f..c828482ac702 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,10 @@ set(CLANG_RESOURCE_DIR "" CACHE STRING set(C_INCLUDE_DIRS "" CACHE STRING "Colon separated list of directories clang will search for headers.") +set(GCC_INSTALL_PREFIX "" CACHE PATH "Directory where gcc is installed." ) +set(DEFAULT_SYSROOT "" CACHE PATH + "Default to all compiler invocations for --sysroot=." ) + set(CLANG_VENDOR "" CACHE STRING "Vendor-specific text for showing with version information.") diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py index b4563eb0c624..6f0d25f1a8f5 100644 --- a/bindings/python/clang/cindex.py +++ b/bindings/python/clang/cindex.py @@ -1079,6 +1079,11 @@ def name(self): self._name_map[value] = key return self._name_map[self] + @property + def spelling(self): + """Retrieve the spelling of this TypeKind.""" + return TypeKind_spelling(self.value) + @staticmethod def from_id(id): if id >= len(TypeKind._kinds) or TypeKind._kinds[id] is None: @@ -1088,6 +1093,10 @@ def from_id(id): def __repr__(self): return 'TypeKind.%s' % (self.name,) +TypeKind_spelling = lib.clang_getTypeKindSpelling +TypeKind_spelling.argtypes = [c_uint] +TypeKind_spelling.restype = _CXString +TypeKind_spelling.errcheck = _CXString.from_result TypeKind.INVALID = TypeKind(0) diff --git a/bindings/python/tests/cindex/test_type.py b/bindings/python/tests/cindex/test_type.py index ed852103b94a..03621f3017c7 100644 --- a/bindings/python/tests/cindex/test_type.py +++ b/bindings/python/tests/cindex/test_type.py @@ -1,5 +1,4 @@ from clang.cindex import CursorKind -from clang.cindex import Index from clang.cindex import TypeKind from nose.tools import raises from .util import get_cursor @@ -109,6 +108,14 @@ def test_equal(): assert a.type != None assert a.type != 'foo' +def test_typekind_spelling(): + """Ensure TypeKind.spelling works.""" + tu = get_tu('int a;') + a = get_cursor(tu, 'a') + + assert a is not None + assert a.type.kind.spelling == 'Int' + def test_function_argument_types(): """Ensure that Type.argument_types() works as expected.""" tu = get_tu('void f(int, int);') diff --git a/examples/clang-interpreter/CMakeLists.txt b/examples/clang-interpreter/CMakeLists.txt index 4d5d4bf9445c..809e324dbe60 100644 --- a/examples/clang-interpreter/CMakeLists.txt +++ b/examples/clang-interpreter/CMakeLists.txt @@ -7,7 +7,6 @@ set(LLVM_USED_LIBS clangStaticAnalyzerFrontend clangStaticAnalyzerCheckers clangStaticAnalyzerCore - clangIndex clangAnalysis clangRewrite clangAST diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 11696db279d3..ac7ab0f9d1d9 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -64,6 +64,9 @@ class TypeSourceInfo { /// \brief Return the TypeLoc wrapper for the type source info. TypeLoc getTypeLoc() const; // implemented in TypeLoc.h + + /// \brief Override the type stored in this TypeSourceInfo. Use with caution! + void overrideType(QualType T) { Ty = T; } }; /// TranslationUnitDecl - The top declaration context. @@ -242,11 +245,7 @@ class NamedDecl : public Decl { bool visibilityExplicit() const { return explicit_; } void setLinkage(Linkage L) { linkage_ = L; } - void setVisibility(Visibility V) { visibility_ = V; } void setVisibility(Visibility V, bool E) { visibility_ = V; explicit_ = E; } - void setVisibility(LinkageInfo Other) { - setVisibility(Other.visibility(), Other.visibilityExplicit()); - } void mergeLinkage(Linkage L) { setLinkage(minLinkage(linkage(), L)); diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 4c675aed8fe6..223289123eb7 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -861,7 +861,6 @@ class Decl { void dumpXML(raw_ostream &OS) const; private: - const Attr *getAttrsImpl() const; void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx); void setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC, ASTContext &Ctx); diff --git a/include/clang/AST/DeclLookups.h b/include/clang/AST/DeclLookups.h index 66d190f42988..b8abe97be1fb 100644 --- a/include/clang/AST/DeclLookups.h +++ b/include/clang/AST/DeclLookups.h @@ -67,6 +67,8 @@ class DeclContext::all_lookups_iterator { DeclContext::all_lookups_iterator DeclContext::lookups_begin() const { DeclContext *Primary = const_cast(this)->getPrimaryContext(); + if (hasExternalVisibleStorage()) + getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary); if (StoredDeclsMap *Map = Primary->buildLookup()) return all_lookups_iterator(Map->begin(), Map->end()); return all_lookups_iterator(); @@ -74,6 +76,8 @@ DeclContext::all_lookups_iterator DeclContext::lookups_begin() const { DeclContext::all_lookups_iterator DeclContext::lookups_end() const { DeclContext *Primary = const_cast(this)->getPrimaryContext(); + if (hasExternalVisibleStorage()) + getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary); if (StoredDeclsMap *Map = Primary->buildLookup()) return all_lookups_iterator(Map->end(), Map->end()); return all_lookups_iterator(); diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 558bd00ba978..b0b9b0fd6ffe 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -581,16 +581,6 @@ class Expr : public Stmt { /// member expression. static QualType findBoundMemberType(const Expr *expr); - /// \brief Result type of CanThrow(). - enum CanThrowResult { - CT_Cannot, - CT_Dependent, - CT_Can - }; - /// \brief Test if this expression, if evaluated, might throw, according to - /// the rules of C++ [expr.unary.noexcept]. - CanThrowResult CanThrow(ASTContext &C) const; - /// IgnoreImpCasts - Skip past any implicit casts which might /// surround this expression. Only skips ImplicitCastExprs. Expr *IgnoreImpCasts() LLVM_READONLY; @@ -3608,6 +3598,10 @@ class InitListExpr : public Expr { return LBraceLoc.isValid() && RBraceLoc.isValid(); } + // Is this an initializer for an array of characters, initialized by a string + // literal or an @encode? + bool isStringLiteralInit() const; + SourceLocation getLBraceLoc() const { return LBraceLoc; } void setLBraceLoc(SourceLocation Loc) { LBraceLoc = Loc; } SourceLocation getRBraceLoc() const { return RBraceLoc; } diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h index 18a1432b706e..e2a60d5cf032 100644 --- a/include/clang/AST/ExternalASTSource.h +++ b/include/clang/AST/ExternalASTSource.h @@ -126,6 +126,12 @@ class ExternalASTSource { virtual DeclContextLookupResult FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name); + /// \brief Ensures that the table of all visible declarations inside this + /// context is up to date. + /// + /// The default implementation of this functino is a no-op. + virtual void completeVisibleDeclsMap(const DeclContext *DC); + /// \brief Finds all declarations lexically contained within the given /// DeclContext, after applying an optional filter predicate. /// diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index a4ad52570174..f1b517102137 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -1870,6 +1870,7 @@ DEF_TRAVERSE_STMT(GotoStmt, { }) DEF_TRAVERSE_STMT(IfStmt, { }) DEF_TRAVERSE_STMT(IndirectGotoStmt, { }) DEF_TRAVERSE_STMT(LabelStmt, { }) +DEF_TRAVERSE_STMT(AttributedStmt, { }) DEF_TRAVERSE_STMT(NullStmt, { }) DEF_TRAVERSE_STMT(ObjCAtCatchStmt, { }) DEF_TRAVERSE_STMT(ObjCAtFinallyStmt, { }) diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 84bdfb89cac2..1b0f576e271d 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -20,6 +20,7 @@ #include "clang/AST/StmtIterator.h" #include "clang/AST/DeclGroup.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" @@ -794,6 +795,47 @@ class LabelStmt : public Stmt { }; +/// \brief Represents an attribute applied to a statement. +/// +/// Represents an attribute applied to a statement. For example: +/// [[omp::for(...)]] for (...) { ... } +/// +class AttributedStmt : public Stmt { + Stmt *SubStmt; + SourceLocation AttrLoc; + AttrVec Attrs; + // TODO: It can be done as Attr *Attrs[1]; and variable size array as in + // StringLiteral + + friend class ASTStmtReader; + +public: + AttributedStmt(SourceLocation loc, const AttrVec &attrs, Stmt *substmt) + : Stmt(AttributedStmtClass), SubStmt(substmt), AttrLoc(loc), Attrs(attrs) { + } + + // \brief Build an empty attributed statement. + explicit AttributedStmt(EmptyShell Empty) + : Stmt(AttributedStmtClass, Empty) { + } + + SourceLocation getAttrLoc() const { return AttrLoc; } + const AttrVec &getAttrs() const { return Attrs; } + Stmt *getSubStmt() { return SubStmt; } + const Stmt *getSubStmt() const { return SubStmt; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(AttrLoc, SubStmt->getLocEnd()); + } + child_range children() { return child_range(&SubStmt, &SubStmt + 1); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == AttributedStmtClass; + } + static bool classof(const AttributedStmt *) { return true; } +}; + + /// IfStmt - This represents an if/then/else. /// class IfStmt : public Stmt { diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 7bd367c054fa..7b615c19dcc4 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -79,6 +79,7 @@ namespace clang { class CXXRecordDecl; class EnumDecl; class FieldDecl; + class FunctionDecl; class ObjCInterfaceDecl; class ObjCProtocolDecl; class ObjCMethodDecl; @@ -2700,7 +2701,9 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { ExtProtoInfo() : Variadic(false), HasTrailingReturn(false), TypeQuals(0), ExceptionSpecType(EST_None), RefQualifier(RQ_None), - NumExceptions(0), Exceptions(0), NoexceptExpr(0), ConsumedArguments(0) {} + NumExceptions(0), Exceptions(0), NoexceptExpr(0), + ExceptionSpecDecl(0), ExceptionSpecTemplate(0), + ConsumedArguments(0) {} FunctionType::ExtInfo ExtInfo; bool Variadic : 1; @@ -2711,6 +2714,8 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { unsigned NumExceptions; const QualType *Exceptions; Expr *NoexceptExpr; + FunctionDecl *ExceptionSpecDecl; + FunctionDecl *ExceptionSpecTemplate; const bool *ConsumedArguments; }; @@ -2756,6 +2761,11 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { // NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing // to the expression in the noexcept() specifier. + // ExceptionSpecDecl, ExceptionSpecTemplate - Instead of Exceptions, there may + // be a pair of FunctionDecl* pointing to the function which should be used to + // instantiate this function type's exception specification, and the function + // from which it should be instantiated. + // ConsumedArgs - A variable size array, following Exceptions // and of length NumArgs, holding flags indicating which arguments // are consumed. This only appears if HasAnyConsumedArgs is true. @@ -2795,6 +2805,9 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { EPI.Exceptions = exception_begin(); } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { EPI.NoexceptExpr = getNoexceptExpr(); + } else if (EPI.ExceptionSpecType == EST_Uninstantiated) { + EPI.ExceptionSpecDecl = getExceptionSpecDecl(); + EPI.ExceptionSpecTemplate = getExceptionSpecTemplate(); } if (hasAnyConsumedArgs()) EPI.ConsumedArguments = getConsumedArgsBuffer(); @@ -2838,9 +2851,26 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { // NoexceptExpr sits where the arguments end. return *reinterpret_cast(arg_type_end()); } + /// \brief If this function type has an uninstantiated exception + /// specification, this is the function whose exception specification + /// is represented by this type. + FunctionDecl *getExceptionSpecDecl() const { + if (getExceptionSpecType() != EST_Uninstantiated) + return 0; + return reinterpret_cast(arg_type_end())[0]; + } + /// \brief If this function type has an uninstantiated exception + /// specification, this is the function whose exception specification + /// should be instantiated to find the exception specification for + /// this type. + FunctionDecl *getExceptionSpecTemplate() const { + if (getExceptionSpecType() != EST_Uninstantiated) + return 0; + return reinterpret_cast(arg_type_end())[1]; + } bool isNothrow(ASTContext &Ctx) const { ExceptionSpecificationType EST = getExceptionSpecType(); - assert(EST != EST_Delayed); + assert(EST != EST_Delayed && EST != EST_Uninstantiated); if (EST == EST_DynamicNone || EST == EST_BasicNoexcept) return true; if (EST != EST_ComputedNoexcept) diff --git a/include/clang/AST/VTableBuilder.h b/include/clang/AST/VTableBuilder.h index 2aa9a3dec9a4..392dad94a4a3 100644 --- a/include/clang/AST/VTableBuilder.h +++ b/include/clang/AST/VTableBuilder.h @@ -205,11 +205,11 @@ class VTableLayout { typedef llvm::DenseMap AddressPointsMapTy; private: uint64_t NumVTableComponents; - VTableComponent *VTableComponents; + llvm::OwningArrayPtr VTableComponents; /// VTableThunks - Contains thunks needed by vtables. uint64_t NumVTableThunks; - VTableThunkTy *VTableThunks; + llvm::OwningArrayPtr VTableThunks; /// Address points - Address points for all vtables. AddressPointsMapTy AddressPoints; @@ -227,11 +227,11 @@ class VTableLayout { } vtable_component_iterator vtable_component_begin() const { - return VTableComponents; + return VTableComponents.get(); } vtable_component_iterator vtable_component_end() const { - return VTableComponents+NumVTableComponents; + return VTableComponents.get()+NumVTableComponents; } uint64_t getNumVTableThunks() const { @@ -239,11 +239,11 @@ class VTableLayout { } vtable_thunk_iterator vtable_thunk_begin() const { - return VTableThunks; + return VTableThunks.get(); } vtable_thunk_iterator vtable_thunk_end() const { - return VTableThunks+NumVTableThunks; + return VTableThunks.get()+NumVTableThunks; } uint64_t getAddressPoint(BaseSubobject Base) const { diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index b2200c65cfd6..aa7a33c956e4 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -129,7 +129,7 @@ class ProgramPoint { static bool classof(const ProgramPoint*) { return true; } bool operator==(const ProgramPoint & RHS) const { - return Data1 == Data1 && + return Data1 == RHS.Data1 && Data2 == RHS.Data2 && L == RHS.L && Tag == RHS.Tag; diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def index f44aed6f9548..4aea980a9d5c 100644 --- a/include/clang/Basic/BuiltinsX86.def +++ b/include/clang/Basic/BuiltinsX86.def @@ -412,6 +412,9 @@ BUILTIN(__builtin_ia32_cvtps2pd256, "V4dV4f", "") BUILTIN(__builtin_ia32_cvttpd2dq256, "V4iV4d", "") BUILTIN(__builtin_ia32_cvtpd2dq256, "V4iV4d", "") BUILTIN(__builtin_ia32_cvttps2dq256, "V8iV8f", "") +BUILTIN(__builtin_ia32_vperm2f128_pd256, "V4dV4dV4dIc", "") +BUILTIN(__builtin_ia32_vperm2f128_ps256, "V8fV8fV8fIc", "") +BUILTIN(__builtin_ia32_vperm2f128_si256, "V8iV8iV8iIc", "") BUILTIN(__builtin_ia32_vinsertf128_pd256, "V4dV4dV2dIc", "") BUILTIN(__builtin_ia32_vinsertf128_ps256, "V8fV8fV4fIc", "") BUILTIN(__builtin_ia32_vinsertf128_si256, "V8iV8iV4iIc", "") @@ -560,9 +563,8 @@ BUILTIN(__builtin_ia32_pbroadcastw128, "V8sV8s", "") BUILTIN(__builtin_ia32_pbroadcastd128, "V4iV4i", "") BUILTIN(__builtin_ia32_pbroadcastq128, "V2LLiV2LLi", "") BUILTIN(__builtin_ia32_permvarsi256, "V8iV8iV8i", "") -BUILTIN(__builtin_ia32_permdf256, "V4dV4dIc", "") BUILTIN(__builtin_ia32_permvarsf256, "V8fV8fV8f", "") -BUILTIN(__builtin_ia32_permdi256, "V4LLiV4LLiIc", "") +BUILTIN(__builtin_ia32_permti256, "V4LLiV4LLiV4LLiIc", "") BUILTIN(__builtin_ia32_extract128i256, "V2LLiV4LLiIc", "") BUILTIN(__builtin_ia32_insert128i256, "V4LLiV4LLiV2LLiIc", "") BUILTIN(__builtin_ia32_maskloadd256, "V8iV8iC*V8i", "") diff --git a/include/clang/Basic/ConvertUTF.h b/include/clang/Basic/ConvertUTF.h index ec6b973e6a7f..7fb587402712 100644 --- a/include/clang/Basic/ConvertUTF.h +++ b/include/clang/Basic/ConvertUTF.h @@ -151,9 +151,9 @@ ConversionResult ConvertUTF16toUTF32 ( ConversionResult ConvertUTF32toUTF16 ( const UTF32** sourceStart, const UTF32* sourceEnd, UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); +#endif Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); -#endif Boolean isLegalUTF8String(const UTF8 *source, const UTF8 *sourceEnd); diff --git a/include/clang/Basic/DelayedCleanupPool.h b/include/clang/Basic/DelayedCleanupPool.h deleted file mode 100644 index 8575bc21113f..000000000000 --- a/include/clang/Basic/DelayedCleanupPool.h +++ /dev/null @@ -1,110 +0,0 @@ -//=== DelayedCleanupPool.h - Delayed Clean-up Pool Implementation *- 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 facility to delay calling cleanup methods until specific -// points. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H -#define LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H - -#include "clang/Basic/LLVM.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallVector.h" - -namespace clang { - -/// \brief Gathers pairs of pointer-to-object/pointer-to-cleanup-function -/// allowing the cleanup functions to get called (with the pointer as parameter) -/// at specific points. -/// -/// The use case is to simplify clean-up of certain resources that, while their -/// lifetime is well-known and restricted, cleaning them up manually is easy to -/// miss and cause a leak. -/// -/// The same pointer can be added multiple times; its clean-up function will -/// only be called once. -class DelayedCleanupPool { -public: - typedef void (*CleanupFn)(void *ptr); - - /// \brief Adds a pointer and its associated cleanup function to be called - /// at a later point. - /// - /// \returns false if the pointer is already added, true otherwise. - bool delayCleanup(void *ptr, CleanupFn fn) { - assert(ptr && "Expected valid pointer to object"); - assert(fn && "Expected valid pointer to function"); - - CleanupFn &mapFn = Ptrs[ptr]; - assert((!mapFn || mapFn == fn) && - "Adding a pointer with different cleanup function!"); - - if (!mapFn) { - mapFn = fn; - Cleanups.push_back(std::make_pair(ptr, fn)); - return true; - } - - return false; - } - - template - bool delayDelete(T *ptr) { - return delayCleanup(ptr, cleanupWithDelete); - } - - template - bool delayMemberFunc(T *ptr) { - return delayCleanup(ptr, cleanupWithMemberFunc); - } - - void doCleanup() { - for (SmallVector, 8>::reverse_iterator - I = Cleanups.rbegin(), E = Cleanups.rend(); I != E; ++I) - I->second(I->first); - Cleanups.clear(); - Ptrs.clear(); - } - - ~DelayedCleanupPool() { - doCleanup(); - } - -private: - llvm::DenseMap Ptrs; - SmallVector, 8> Cleanups; - - template - static void cleanupWithDelete(void *ptr) { - delete static_cast(ptr); - } - - template - static void cleanupWithMemberFunc(void *ptr) { - (static_cast(ptr)->*Fn)(); - } -}; - -/// \brief RAII object for triggering a cleanup of a DelayedCleanupPool. -class DelayedCleanupPoint { - DelayedCleanupPool &Pool; - -public: - DelayedCleanupPoint(DelayedCleanupPool &pool) : Pool(pool) { } - - ~DelayedCleanupPoint() { - Pool.doCleanup(); - } -}; - -} // end namespace clang - -#endif diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index c183da7a6ac9..957f05b66426 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -410,6 +410,8 @@ def ext_ellipsis_exception_spec : Extension< "exception specification of '...' is a Microsoft extension">; def err_dynamic_and_noexcept_specification : Error< "cannot have both throw() and noexcept() clause on the same function">; +def err_except_spec_unparsed : Error< + "unexpected end of exception specification">; def warn_cxx98_compat_noexcept_decl : Warning< "noexcept specifications are incompatible with C++98">, InGroup, DefaultIgnore; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index e553740ab1df..0614adee85b8 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -231,9 +231,13 @@ def err_using_decl_can_not_refer_to_namespace : Error< "using declaration can not refer to namespace">; def err_using_decl_constructor : Error< "using declaration can not refer to a constructor">; -def warn_cxx98_compat_using_decl_constructor : Warning< - "inherited constructors are incompatible with C++98">, - InGroup, DefaultIgnore; +def err_using_decl_constructor_unsupported : Error< + "inheriting constructors are not supported">; +// FIXME: Replace the above error with this warning if support for +// inheriting constructors is implemented. +//def warn_cxx98_compat_using_decl_constructor : Warning< +// "inheriting constructors are incompatible with C++98">, +// InGroup, DefaultIgnore; def err_using_decl_destructor : Error< "using declaration can not refer to a destructor">; def err_using_decl_template_id : Error< @@ -1547,9 +1551,6 @@ def warn_objc_redundant_literal_use : Warning< "using %0 with a literal is redundant">, InGroup; } -def warn_bool_for_boolean_literal : Warning< - "BOOL of type %0 is non-intergal and unsuitable for a " - "boolean literal - ignored">, InGroup>; def err_only_annotate_after_access_spec : Error< "access specifier can only have annotation attributes">; def err_attribute_section_invalid_for_target : Error< @@ -1563,6 +1564,9 @@ def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning< def warn_attribute_ignored : Warning<"%0 attribute ignored">; def warn_unknown_attribute_ignored : Warning< "unknown attribute %0 ignored">, InGroup; +def warn_attribute_invalid_on_stmt : Warning< + "attribute %0 cannot be specified on a statement">, + InGroup; def warn_declspec_attribute_ignored : Warning< "attribute %0 is ignored, place it after \"%select{class|struct|union|enum}1\" to apply attribute to type declaration">, InGroup; def warn_attribute_precede_definition : Warning< @@ -2583,6 +2587,8 @@ def note_template_enum_def_here : Note< "in instantiation of enumeration %q0 requested here">; def note_template_type_alias_instantiation_here : Note< "in instantiation of template type alias %0 requested here">; +def note_template_exception_spec_instantiation_here : Note< + "in instantiation of exception specification for %0 requested here">; def note_default_arg_instantiation_here : Note< "in instantiation of default argument for '%0' required here">; @@ -3798,6 +3804,9 @@ def warn_null_in_comparison_operation : Warning< def err_invalid_this_use : Error< "invalid use of 'this' outside of a non-static member function">; +def err_this_static_member_func : Error< + "'this' cannot be%select{| implicitly}0 used in a static member function " + "declaration">; def err_invalid_member_use_in_static_method : Error< "invalid use of member %0 in static member function">; def err_invalid_qualified_function_type : Error< @@ -3907,7 +3916,7 @@ def err_nosetter_property_incdec : Error< def err_nogetter_property_compound_assignment : Error< "a getter method is needed to perform a compound assignment on a property">; def err_nogetter_property_incdec : Error< - "no getter method %1 for %select{increment|decrement} of property">; + "no getter method %1 for %select{increment|decrement}0 of property">; def error_no_subobject_property_setting : Error< "expression is not assignable">; def err_qualified_objc_access : Error< diff --git a/include/clang/Basic/ExceptionSpecificationType.h b/include/clang/Basic/ExceptionSpecificationType.h index 98cfd297addf..e911bde1910a 100644 --- a/include/clang/Basic/ExceptionSpecificationType.h +++ b/include/clang/Basic/ExceptionSpecificationType.h @@ -16,7 +16,7 @@ namespace clang { -/// \brief The various types of exception specifications that exist in C++0x. +/// \brief The various types of exception specifications that exist in C++11. enum ExceptionSpecificationType { EST_None, ///< no exception specification EST_DynamicNone, ///< throw() @@ -24,7 +24,8 @@ enum ExceptionSpecificationType { EST_MSAny, ///< Microsoft throw(...) extension EST_BasicNoexcept, ///< noexcept EST_ComputedNoexcept, ///< noexcept(expression) - EST_Delayed ///< not known yet + EST_Delayed, ///< not known yet + EST_Uninstantiated ///< not instantiated yet }; inline bool isDynamicExceptionSpec(ExceptionSpecificationType ESpecType) { @@ -35,6 +36,19 @@ inline bool isNoexceptExceptionSpec(ExceptionSpecificationType ESpecType) { return ESpecType == EST_BasicNoexcept || ESpecType == EST_ComputedNoexcept; } +/// \brief Possible results from evaluation of a noexcept expression. +enum CanThrowResult { + CT_Cannot, + CT_Dependent, + CT_Can +}; + +inline CanThrowResult mergeCanThrow(CanThrowResult CT1, CanThrowResult CT2) { + // CanThrowResult constants are ordered so that the maximum is the correct + // merge result. + return CT1 > CT2 ? CT1 : CT2; +} + } // end namespace clang #endif // LLVM_CLANG_BASIC_EXCEPTIONSPECIFICATIONTYPE_H diff --git a/include/clang/Basic/OnDiskHashTable.h b/include/clang/Basic/OnDiskHashTable.h index 8028a73326c3..b92f1cf9c6ae 100644 --- a/include/clang/Basic/OnDiskHashTable.h +++ b/include/clang/Basic/OnDiskHashTable.h @@ -132,7 +132,7 @@ class OnDiskChainedHashTableGenerator { class Bucket { public: io::Offset off; - Item* head; + Item* head; unsigned length; Bucket() {} @@ -201,6 +201,7 @@ class OnDiskChainedHashTableGenerator { // Write out the number of items in the bucket. Emit16(out, B.length); + assert(B.length != 0 && "Bucket has a head but zero length?"); // Write out the entries in the bucket. for (Item *I = B.head; I ; I = I->next) { @@ -398,31 +399,30 @@ class OnDiskChainedHashTable { } key_iterator key_end() { return key_iterator(); } - /// \brief Iterates over all the entries in the table, returning - /// a key/data pair. - class item_iterator { + /// \brief Iterates over all the entries in the table, returning the data. + class data_iterator { const unsigned char* Ptr; unsigned NumItemsInBucketLeft; unsigned NumEntriesLeft; Info *InfoObj; public: - typedef std::pair value_type; + typedef data_type value_type; - item_iterator(const unsigned char* const Ptr, unsigned NumEntries, + data_iterator(const unsigned char* const Ptr, unsigned NumEntries, Info *InfoObj) : Ptr(Ptr), NumItemsInBucketLeft(0), NumEntriesLeft(NumEntries), InfoObj(InfoObj) { } - item_iterator() + data_iterator() : Ptr(0), NumItemsInBucketLeft(0), NumEntriesLeft(0), InfoObj(0) { } - bool operator==(const item_iterator& X) const { + bool operator==(const data_iterator& X) const { return X.NumEntriesLeft == NumEntriesLeft; } - bool operator!=(const item_iterator& X) const { + bool operator!=(const data_iterator& X) const { return X.NumEntriesLeft != NumEntriesLeft; } - item_iterator& operator++() { // Preincrement + data_iterator& operator++() { // Preincrement if (!NumItemsInBucketLeft) { // 'Items' starts with a 16-bit unsigned integer representing the // number of items in this bucket. @@ -438,8 +438,8 @@ class OnDiskChainedHashTable { --NumEntriesLeft; return *this; } - item_iterator operator++(int) { // Postincrement - item_iterator tmp = *this; ++*this; return tmp; + data_iterator operator++(int) { // Postincrement + data_iterator tmp = *this; ++*this; return tmp; } value_type operator*() const { @@ -454,15 +454,14 @@ class OnDiskChainedHashTable { // Read the key. const internal_key_type& Key = InfoObj->ReadKey(LocalPtr, L.first); - return std::make_pair(InfoObj->GetExternalKey(Key), - InfoObj->ReadData(Key, LocalPtr + L.first, L.second)); + return InfoObj->ReadData(Key, LocalPtr + L.first, L.second); } }; - item_iterator item_begin() { - return item_iterator(Base + 4, getNumEntries(), &InfoObj); + data_iterator data_begin() { + return data_iterator(Base + 4, getNumEntries(), &InfoObj); } - item_iterator item_end() { return item_iterator(); } + data_iterator data_end() { return data_iterator(); } Info &getInfoObj() { return InfoObj; } diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index 67d71e44c0a4..e7718cd80cb3 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -12,6 +12,7 @@ class DStmt : Stmt { def NullStmt : Stmt; def CompoundStmt : Stmt; def LabelStmt : Stmt; +def AttributedStmt : Stmt; def IfStmt : Stmt; def SwitchStmt : Stmt; def WhileStmt : Stmt; diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index bbd376a82415..a03cf83ff7db 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -132,6 +132,11 @@ class TargetInfo : public RefCountedBase { IntType SizeType, IntMaxType, UIntMaxType, PtrDiffType, IntPtrType, WCharType, WIntType, Char16Type, Char32Type, Int64Type, SigAtomicType; + /// Flag whether the Objective-C built-in boolean type should be signed char. + /// Otherwise, when this flag is not set, the normal built-in boolean type is + /// used. + unsigned UseSignedCharForObjCBool : 1; + /// Control whether the alignment of bit-field types is respected when laying /// out structures. If true, then the alignment of the bit-field type will be /// used to (a) impact the alignment of the containing structure, and (b) @@ -299,6 +304,16 @@ class TargetInfo : public RefCountedBase { return MCountName; } + /// useSignedCharForObjCBool - Check if the Objective-C built-in boolean + /// type should be signed char. Otherwise, if this returns false, the + /// normal built-in boolean type should also be used for Objective-C. + bool useSignedCharForObjCBool() const { + return UseSignedCharForObjCBool; + } + void noSignedCharForObjCBool() { + UseSignedCharForObjCBool = false; + } + /// useBitFieldTypeAlignment() - Check whether the alignment of bit-field /// types is respected when laying out structures. bool useBitFieldTypeAlignment() const { diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 2e4d34dff0ba..fe0ef3068167 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -105,6 +105,7 @@ TOK(eod) // End of preprocessing directive (end of line inside a // directive). TOK(code_completion) // Code completion marker TOK(cxx_defaultarg_end) // C++ default argument end marker +TOK(cxx_exceptspec_end) // C++ exception-specification end marker // C99 6.4.9: Comments. TOK(comment) // Comment (only in -E -C[C] mode) diff --git a/include/clang/Config/config.h.cmake b/include/clang/Config/config.h.cmake index bd5dc31f3232..c18c4cc86f76 100644 --- a/include/clang/Config/config.h.cmake +++ b/include/clang/Config/config.h.cmake @@ -4,8 +4,11 @@ /* Relative directory for resource files */ #define CLANG_RESOURCE_DIR "${CLANG_RESOURCE_DIR}" -/* Directory where gcc is installed. */ -#define GCC_INSTALL_PREFIX "${GCC_INSTALL_PREFIX}" - /* Directories clang will search for headers */ #define C_INCLUDE_DIRS "${C_INCLUDE_DIRS}" + +/* Default to all compiler invocations for --sysroot=. */ +#define DEFAULT_SYSROOT "${DEFAULT_SYSROOT}" + +/* Directory where gcc is installed. */ +#define GCC_INSTALL_PREFIX "${GCC_INSTALL_PREFIX}" diff --git a/include/clang/Config/config.h.in b/include/clang/Config/config.h.in index 86d5b0959b6e..8ff94178e27e 100644 --- a/include/clang/Config/config.h.in +++ b/include/clang/Config/config.h.in @@ -9,13 +9,16 @@ /* Relative directory for resource files */ #undef CLANG_RESOURCE_DIR -/* Directory where gcc is installed. */ -#undef GCC_INSTALL_PREFIX - /* Directories clang will search for headers */ #undef C_INCLUDE_DIRS /* Linker version detected at compile time. */ #undef HOST_LINK_VERSION +/* Default to all compiler invocations for --sysroot=. */ +#undef DEFAULT_SYSROOT + +/* Directory where gcc is installed. */ +#undef GCC_INSTALL_PREFIX + #endif diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index 3ab8f8348183..83c988abd13d 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -428,9 +428,6 @@ def ast_view : Flag<"-ast-view">, HelpText<"Build ASTs and view them with GraphViz">; def print_decl_contexts : Flag<"-print-decl-contexts">, HelpText<"Print DeclContexts and their Decls">; -def pubnames_dump : Flag<"-pubnames-dump">, - HelpText<"Print all of the public (global) names in the source, e.g., the " - "names of all global declarations and macros">; def emit_module : Flag<"-emit-module">, HelpText<"Generate pre-compiled module file from a module map">; def emit_pth : Flag<"-emit-pth">, diff --git a/include/clang/Driver/Compilation.h b/include/clang/Driver/Compilation.h index fd88c3a63636..6f1a2217cd1c 100644 --- a/include/clang/Driver/Compilation.h +++ b/include/clang/Driver/Compilation.h @@ -92,6 +92,9 @@ class Compilation { return FailureResultFiles; } + /// Returns the sysroot path. + StringRef getSysRoot() const; + /// getArgsForToolChain - Return the derived argument list for the /// tool chain \arg TC (or the default tool chain, if TC is not /// specified). diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 5e4ecadd6900..041eabb5b992 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -14,7 +14,6 @@ #ifndef LLVM_CLANG_FRONTEND_ASTUNIT_H #define LLVM_CLANG_FRONTEND_ASTUNIT_H -#include "clang/Index/ASTLocation.h" #include "clang/Serialization/ASTBitCodes.h" #include "clang/Sema/Sema.h" #include "clang/Sema/CodeCompleteConsumer.h" @@ -57,8 +56,6 @@ class SourceManager; class TargetInfo; class ASTFrontendAction; -using namespace idx; - /// \brief Utility class for loading a ASTContext from an AST file. /// class ASTUnit : public ModuleLoader { @@ -134,9 +131,6 @@ class ASTUnit : public ModuleLoader { /// The name of the original source file used to generate this ASTUnit. std::string OriginalSourceFile; - // Critical optimization when using clang_getCursor(). - ASTLocation LastLoc; - /// \brief The set of diagnostics produced when creating the preamble. SmallVector PreambleDiagnostics; @@ -474,10 +468,6 @@ class ASTUnit : public ModuleLoader { bool getOwnsRemappedFileBuffers() const { return OwnsRemappedFileBuffers; } void setOwnsRemappedFileBuffers(bool val) { OwnsRemappedFileBuffers = val; } - void setLastASTLocation(ASTLocation ALoc) { LastLoc = ALoc; } - ASTLocation getLastASTLocation() const { return LastLoc; } - - StringRef getMainFileName() const; typedef std::vector::iterator top_level_iterator; diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h index 8817c5af564e..8f7fe87ee67d 100644 --- a/include/clang/Frontend/FrontendActions.h +++ b/include/clang/Frontend/FrontendActions.h @@ -173,15 +173,6 @@ class PrintPreambleAction : public FrontendAction { virtual bool usesPreprocessorOnly() const { return true; } }; -class PubnamesDumpAction : public ASTFrontendAction { -protected: - virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, - StringRef InFile); - -public: - virtual bool hasCodeCompletionSupport() const { return false; } -}; - //===----------------------------------------------------------------------===// // Preprocessor Actions //===----------------------------------------------------------------------===// diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h index a051d7ff629e..888388c310e4 100644 --- a/include/clang/Frontend/FrontendOptions.h +++ b/include/clang/Frontend/FrontendOptions.h @@ -42,7 +42,6 @@ namespace frontend { PrintDeclContext, ///< Print DeclContext and their Decls. PrintPreamble, ///< Print the "preamble" of the input file PrintPreprocessedInput, ///< -E mode. - PubnamesDump, ///< Print all of the "public" names in the source. RewriteMacros, ///< Expand macros but not #includes. RewriteObjC, ///< ObjC->C Rewriter. RewriteTest, ///< Rewriter playground diff --git a/include/clang/Frontend/TextDiagnostic.h b/include/clang/Frontend/TextDiagnostic.h index 519d3b61ce70..314003bce2c5 100644 --- a/include/clang/Frontend/TextDiagnostic.h +++ b/include/clang/Frontend/TextDiagnostic.h @@ -18,6 +18,8 @@ #include "clang/Frontend/DiagnosticRenderer.h" +struct SourceColumnMap; + namespace clang { /// \brief Class to encapsulate the logic for formatting and printing a textual @@ -103,15 +105,16 @@ class TextDiagnostic : public DiagnosticRenderer { SmallVectorImpl& Ranges, ArrayRef Hints); + void emitSnippet(StringRef SourceLine); + void highlightRange(const CharSourceRange &R, unsigned LineNo, FileID FID, - const std::string &SourceLine, + const SourceColumnMap &map, std::string &CaretLine); + std::string buildFixItInsertionLine(unsigned LineNo, - const char *LineStart, - const char *LineEnd, + const SourceColumnMap &map, ArrayRef Hints); - void expandTabs(std::string &SourceLine, std::string &CaretLine); void emitParseableFixits(ArrayRef Hints); }; diff --git a/include/clang/Index/ASTLocation.h b/include/clang/Index/ASTLocation.h deleted file mode 100644 index 45097cc5c3d9..000000000000 --- a/include/clang/Index/ASTLocation.h +++ /dev/null @@ -1,173 +0,0 @@ -//===--- ASTLocation.h - A pair --------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// ASTLocation is Decl or a Stmt and its immediate Decl parent. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INDEX_ASTLOCATION_H -#define LLVM_CLANG_INDEX_ASTLOCATION_H - -#include "clang/AST/TypeLoc.h" -#include "llvm/ADT/PointerIntPair.h" -#include "llvm/Support/Compiler.h" - -namespace clang { - class Decl; - class Stmt; - class NamedDecl; - -namespace idx { - class TranslationUnit; - -/// \brief Represents a Decl or a Stmt and its immediate Decl parent. It's -/// immutable. -/// -/// ASTLocation is intended to be used as a "pointer" into the AST. It is either -/// just a Decl, or a Stmt and its Decl parent. Since a single Stmt is devoid -/// of context, its parent Decl provides all the additional missing information -/// like the declaration context, ASTContext, etc. -/// -class ASTLocation { -public: - enum NodeKind { - N_Decl, N_NamedRef, N_Stmt, N_Type - }; - - struct NamedRef { - NamedDecl *ND; - SourceLocation Loc; - - NamedRef() : ND(0) { } - NamedRef(NamedDecl *nd, SourceLocation loc) : ND(nd), Loc(loc) { } - }; - -private: - llvm::PointerIntPair ParentDecl; - - union { - Decl *D; - Stmt *Stm; - struct { - NamedDecl *ND; - unsigned RawLoc; - } NDRef; - struct { - void *TyPtr; - void *Data; - } Ty; - }; - -public: - ASTLocation() { } - - explicit ASTLocation(const Decl *d) - : ParentDecl(const_cast(d), N_Decl), D(const_cast(d)) { } - - ASTLocation(const Decl *parentDecl, const Stmt *stm) - : ParentDecl(const_cast(parentDecl), N_Stmt), - Stm(const_cast(stm)) { - if (!stm) ParentDecl.setPointer(0); - } - - ASTLocation(const Decl *parentDecl, NamedDecl *ndRef, SourceLocation loc) - : ParentDecl(const_cast(parentDecl), N_NamedRef) { - if (ndRef) { - NDRef.ND = ndRef; - NDRef.RawLoc = loc.getRawEncoding(); - } else - ParentDecl.setPointer(0); - } - - ASTLocation(const Decl *parentDecl, TypeLoc tyLoc) - : ParentDecl(const_cast(parentDecl), N_Type) { - if (tyLoc) { - Ty.TyPtr = tyLoc.getType().getAsOpaquePtr(); - Ty.Data = tyLoc.getOpaqueData(); - } else - ParentDecl.setPointer(0); - } - - bool isValid() const { return ParentDecl.getPointer() != 0; } - bool isInvalid() const { return !isValid(); } - - NodeKind getKind() const { - assert(isValid()); - return (NodeKind)ParentDecl.getInt(); - } - - Decl *getParentDecl() const { return ParentDecl.getPointer(); } - - Decl *AsDecl() const { - assert(getKind() == N_Decl); - return D; - } - Stmt *AsStmt() const { - assert(getKind() == N_Stmt); - return Stm; - } - NamedRef AsNamedRef() const { - assert(getKind() == N_NamedRef); - return NamedRef(NDRef.ND, SourceLocation::getFromRawEncoding(NDRef.RawLoc)); - } - TypeLoc AsTypeLoc() const { - assert(getKind() == N_Type); - return TypeLoc(QualType::getFromOpaquePtr(Ty.TyPtr), Ty.Data); - } - - Decl *dyn_AsDecl() const { return isValid() && getKind() == N_Decl ? D : 0; } - Stmt *dyn_AsStmt() const { - return isValid() && getKind() == N_Stmt ? Stm : 0; - } - NamedRef dyn_AsNamedRef() const { - return getKind() == N_Type ? AsNamedRef() : NamedRef(); - } - TypeLoc dyn_AsTypeLoc() const { - return getKind() == N_Type ? AsTypeLoc() : TypeLoc(); - } - - bool isDecl() const { return isValid() && getKind() == N_Decl; } - bool isStmt() const { return isValid() && getKind() == N_Stmt; } - bool isNamedRef() const { return isValid() && getKind() == N_NamedRef; } - bool isType() const { return isValid() && getKind() == N_Type; } - - /// \brief Returns the declaration that this ASTLocation references. - /// - /// If this points to a Decl, that Decl is returned. - /// If this points to an Expr that references a Decl, that Decl is returned, - /// otherwise it returns NULL. - Decl *getReferencedDecl(); - const Decl *getReferencedDecl() const { - return const_cast(this)->getReferencedDecl(); - } - - SourceRange getSourceRange() const LLVM_READONLY; - - void print(raw_ostream &OS) const; -}; - -/// \brief Like ASTLocation but also contains the TranslationUnit that the -/// ASTLocation originated from. -class TULocation : public ASTLocation { - TranslationUnit *TU; - -public: - TULocation(TranslationUnit *tu, ASTLocation astLoc) - : ASTLocation(astLoc), TU(tu) { - assert(tu && "Passed null translation unit"); - } - - TranslationUnit *getTU() const { return TU; } -}; - -} // namespace idx - -} // namespace clang - -#endif diff --git a/include/clang/Index/Analyzer.h b/include/clang/Index/Analyzer.h deleted file mode 100644 index f6b5465148e6..000000000000 --- a/include/clang/Index/Analyzer.h +++ /dev/null @@ -1,56 +0,0 @@ -//===--- Analyzer.h - Analysis for indexing information ---------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the Analyzer interface. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INDEX_ANALYZER_H -#define LLVM_CLANG_INDEX_ANALYZER_H - -namespace clang { - class Decl; - class ObjCMessageExpr; - -namespace idx { - class Program; - class IndexProvider; - class TULocationHandler; - -/// \brief Provides indexing information, like finding all references of an -/// Entity across translation units. -class Analyzer { - Program &Prog; - IndexProvider &Idxer; - - Analyzer(const Analyzer&); // do not implement - Analyzer &operator=(const Analyzer &); // do not implement - -public: - explicit Analyzer(Program &prog, IndexProvider &idxer) - : Prog(prog), Idxer(idxer) { } - - /// \brief Find all TULocations for declarations of the given Decl and pass - /// them to Handler. - void FindDeclarations(Decl *D, TULocationHandler &Handler); - - /// \brief Find all TULocations for references of the given Decl and pass - /// them to Handler. - void FindReferences(Decl *D, TULocationHandler &Handler); - - /// \brief Find methods that may respond to the given message and pass them - /// to Handler. - void FindObjCMethods(ObjCMessageExpr *MsgE, TULocationHandler &Handler); -}; - -} // namespace idx - -} // namespace clang - -#endif diff --git a/include/clang/Index/DeclReferenceMap.h b/include/clang/Index/DeclReferenceMap.h deleted file mode 100644 index 73f2fe50b3b6..000000000000 --- a/include/clang/Index/DeclReferenceMap.h +++ /dev/null @@ -1,50 +0,0 @@ -//===--- DeclReferenceMap.h - Map Decls to their references -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// DeclReferenceMap creates a mapping from Decls to the ASTLocations that -// reference them. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INDEX_DECLREFERENCEMAP_H -#define LLVM_CLANG_INDEX_DECLREFERENCEMAP_H - -#include "clang/Index/ASTLocation.h" -#include "clang/Index/STLExtras.h" -#include - -namespace clang { - class ASTContext; - class NamedDecl; - -namespace idx { - -/// \brief Maps NamedDecls with the ASTLocations that reference them. -/// -/// References are mapped and retrieved using the canonical decls. -class DeclReferenceMap { -public: - explicit DeclReferenceMap(ASTContext &Ctx); - - typedef std::multimap MapTy; - typedef pair_value_iterator astlocation_iterator; - - astlocation_iterator refs_begin(NamedDecl *D) const; - astlocation_iterator refs_end(NamedDecl *D) const; - bool refs_empty(NamedDecl *D) const; - -private: - mutable MapTy Map; -}; - -} // end idx namespace - -} // end clang namespace - -#endif diff --git a/include/clang/Index/Entity.h b/include/clang/Index/Entity.h deleted file mode 100644 index d104458ec249..000000000000 --- a/include/clang/Index/Entity.h +++ /dev/null @@ -1,149 +0,0 @@ -//===--- Entity.h - Cross-translation-unit "token" for decls ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Entity is a ASTContext-independent way to refer to declarations that are -// visible across translation units. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INDEX_ENTITY_H -#define LLVM_CLANG_INDEX_ENTITY_H - -#include "clang/Basic/LLVM.h" -#include "llvm/ADT/PointerUnion.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/StringRef.h" -#include - -namespace clang { - class ASTContext; - class Decl; - -namespace idx { - class Program; - class EntityImpl; - -/// \brief A ASTContext-independent way to refer to declarations. -/// -/// Entity is basically the link for declarations that are semantically the same -/// in multiple ASTContexts. A client will convert a Decl into an Entity and -/// later use that Entity to find the "same" Decl into another ASTContext. -/// Declarations that are semantically the same and visible across translation -/// units will be associated with the same Entity. -/// -/// An Entity may also refer to declarations that cannot be visible across -/// translation units, e.g. static functions with the same name in multiple -/// translation units will be associated with different Entities. -/// -/// Entities can be checked for equality but note that the same Program object -/// should be used when getting Entities. -/// -class Entity { - /// \brief Stores the Decl directly if it is not visible outside of its own - /// translation unit, otherwise it stores the associated EntityImpl. - llvm::PointerUnion Val; - - explicit Entity(Decl *D); - explicit Entity(EntityImpl *impl) : Val(impl) { } - friend class EntityGetter; - -public: - Entity() { } - - /// \brief Find the Decl that can be referred to by this entity. - Decl *getDecl(ASTContext &AST) const; - - /// \brief If this Entity represents a declaration that is internal to its - /// translation unit, getInternalDecl() returns it. - Decl *getInternalDecl() const { - assert(isInternalToTU() && "This Entity is not internal!"); - return Val.get(); - } - - /// \brief Get a printable name for debugging purpose. - std::string getPrintableName() const; - - /// \brief Get an Entity associated with the given Decl. - /// \returns invalid Entity if an Entity cannot refer to this Decl. - static Entity get(Decl *D, Program &Prog); - - /// \brief Get an Entity associated with a name in the global namespace. - static Entity get(StringRef Name, Program &Prog); - - /// \brief true if the Entity is not visible outside the trasnlation unit. - bool isInternalToTU() const { - assert(isValid() && "This Entity is not valid!"); - return Val.is(); - } - - bool isValid() const { return !Val.isNull(); } - bool isInvalid() const { return !isValid(); } - - void *getAsOpaquePtr() const { return Val.getOpaqueValue(); } - static Entity getFromOpaquePtr(void *Ptr) { - Entity Ent; - Ent.Val = llvm::PointerUnion::getFromOpaqueValue(Ptr); - return Ent; - } - - friend bool operator==(const Entity &LHS, const Entity &RHS) { - return LHS.getAsOpaquePtr() == RHS.getAsOpaquePtr(); - } - - // For use in a std::map. - friend bool operator < (const Entity &LHS, const Entity &RHS) { - return LHS.getAsOpaquePtr() < RHS.getAsOpaquePtr(); - } - - // For use in DenseMap/DenseSet. - static Entity getEmptyMarker() { - Entity Ent; - Ent.Val = - llvm::PointerUnion::getFromOpaqueValue((void*)-1); - return Ent; - } - static Entity getTombstoneMarker() { - Entity Ent; - Ent.Val = - llvm::PointerUnion::getFromOpaqueValue((void*)-2); - return Ent; - } -}; - -} // namespace idx - -} // namespace clang - -namespace llvm { -/// Define DenseMapInfo so that Entities can be used as keys in DenseMap and -/// DenseSets. -template<> -struct DenseMapInfo { - static inline clang::idx::Entity getEmptyKey() { - return clang::idx::Entity::getEmptyMarker(); - } - - static inline clang::idx::Entity getTombstoneKey() { - return clang::idx::Entity::getTombstoneMarker(); - } - - static unsigned getHashValue(clang::idx::Entity); - - static inline bool - isEqual(clang::idx::Entity LHS, clang::idx::Entity RHS) { - return LHS == RHS; - } -}; - -template <> -struct isPodLike { static const bool value = true; }; - -} // end namespace llvm - -#endif diff --git a/include/clang/Index/GlobalCallGraph.h b/include/clang/Index/GlobalCallGraph.h deleted file mode 100644 index 7ba1cceac184..000000000000 --- a/include/clang/Index/GlobalCallGraph.h +++ /dev/null @@ -1,149 +0,0 @@ -//== GlobalCallGraph.h - 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 CallGraphNode classes. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INDEX_CALLGRAPH -#define LLVM_CLANG_INDEX_CALLGRAPH - -#include "clang/Index/ASTLocation.h" -#include "clang/Index/Entity.h" -#include "clang/Index/Program.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/GraphTraits.h" -#include "llvm/ADT/STLExtras.h" -#include -#include - -using namespace clang; - -namespace clang { -namespace idx { - -class CallGraphNode { - Entity F; - typedef std::pair CallRecord; - std::vector CalledFunctions; - -public: - CallGraphNode(Entity f) : F(f) {} - - typedef std::vector::iterator iterator; - typedef std::vector::const_iterator const_iterator; - - iterator begin() { return CalledFunctions.begin(); } - iterator end() { return CalledFunctions.end(); } - const_iterator begin() const { return CalledFunctions.begin(); } - const_iterator end() const { return CalledFunctions.end(); } - - void addCallee(ASTLocation L, CallGraphNode *Node) { - CalledFunctions.push_back(std::make_pair(L, Node)); - } - - bool hasCallee() const { return begin() != end(); } - - std::string getName() const { return F.getPrintableName(); } - - Decl *getDecl(ASTContext &Ctx) const { return F.getDecl(Ctx); } -}; - -class CallGraph { - /// Program manages all Entities. - Program &Prog; - - typedef std::map FunctionMapTy; - - /// FunctionMap owns all CallGraphNodes. - FunctionMapTy FunctionMap; - - /// CallerCtx maps a caller to its ASTContext. - llvm::DenseMap CallerCtx; - - /// Root node is the 'main' function or 0. - CallGraphNode *Root; - - /// ExternalCallingNode has edges to all external functions. - CallGraphNode *ExternalCallingNode; - -public: - CallGraph(Program &P); - ~CallGraph(); - - typedef FunctionMapTy::iterator iterator; - typedef FunctionMapTy::const_iterator const_iterator; - - iterator begin() { return FunctionMap.begin(); } - iterator end() { return FunctionMap.end(); } - const_iterator begin() const { return FunctionMap.begin(); } - const_iterator end() const { return FunctionMap.end(); } - - CallGraphNode *getRoot() { return Root; } - - CallGraphNode *getExternalCallingNode() { return ExternalCallingNode; } - - void addTU(ASTContext &AST); - - Program &getProgram() { return Prog; } - - CallGraphNode *getOrInsertFunction(idx::Entity F); - - Decl *getDecl(CallGraphNode *Node); - - void print(raw_ostream &os); - void dump(); - - void ViewCallGraph() const; -}; - -}} // end clang idx namespace - -namespace llvm { - -template <> struct GraphTraits { - typedef clang::idx::CallGraph GraphType; - typedef clang::idx::CallGraphNode NodeType; - - typedef std::pair CGNPairTy; - typedef std::pointer_to_unary_function CGNDerefFun; - - typedef mapped_iterator ChildIteratorType; - - static NodeType *getEntryNode(GraphType *CG) { - return CG->getExternalCallingNode(); - } - - static ChildIteratorType child_begin(NodeType *N) { - return map_iterator(N->begin(), CGNDerefFun(CGNDeref)); - } - static ChildIteratorType child_end(NodeType *N) { - return map_iterator(N->end(), CGNDerefFun(CGNDeref)); - } - - typedef std::pair PairTy; - typedef std::pointer_to_unary_function DerefFun; - - typedef mapped_iterator nodes_iterator; - - static nodes_iterator nodes_begin(const GraphType &CG) { - return map_iterator(CG.begin(), DerefFun(CGDeref)); - } - static nodes_iterator nodes_end(const GraphType &CG) { - return map_iterator(CG.end(), DerefFun(CGDeref)); - } - - static NodeType *CGNDeref(CGNPairTy P) { return P.second; } - - static NodeType *CGDeref(PairTy P) { return P.second; } -}; - -} // end llvm namespace - -#endif diff --git a/include/clang/Index/GlobalSelector.h b/include/clang/Index/GlobalSelector.h deleted file mode 100644 index 9cd83a8595b9..000000000000 --- a/include/clang/Index/GlobalSelector.h +++ /dev/null @@ -1,100 +0,0 @@ -//===--- GlobalSelector.h - Cross-translation-unit "token" for selectors --===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// GlobalSelector is a ASTContext-independent way to refer to selectors. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INDEX_GLOBALSELECTOR_H -#define LLVM_CLANG_INDEX_GLOBALSELECTOR_H - -#include "llvm/ADT/DenseMap.h" -#include - -namespace clang { - class ASTContext; - class Selector; - -namespace idx { - class Program; - -/// \brief A ASTContext-independent way to refer to selectors. -class GlobalSelector { - void *Val; - - explicit GlobalSelector(void *val) : Val(val) { } - -public: - GlobalSelector() : Val(0) { } - - /// \brief Get the ASTContext-specific selector. - Selector getSelector(ASTContext &AST) const; - - bool isValid() const { return Val != 0; } - bool isInvalid() const { return !isValid(); } - - /// \brief Get a printable name for debugging purpose. - std::string getPrintableName() const; - - /// \brief Get a GlobalSelector for the ASTContext-specific selector. - static GlobalSelector get(Selector Sel, Program &Prog); - - void *getAsOpaquePtr() const { return Val; } - - static GlobalSelector getFromOpaquePtr(void *Ptr) { - return GlobalSelector(Ptr); - } - - friend bool operator==(const GlobalSelector &LHS, const GlobalSelector &RHS) { - return LHS.getAsOpaquePtr() == RHS.getAsOpaquePtr(); - } - - // For use in a std::map. - friend bool operator< (const GlobalSelector &LHS, const GlobalSelector &RHS) { - return LHS.getAsOpaquePtr() < RHS.getAsOpaquePtr(); - } - - // For use in DenseMap/DenseSet. - static GlobalSelector getEmptyMarker() { return GlobalSelector((void*)-1); } - static GlobalSelector getTombstoneMarker() { - return GlobalSelector((void*)-2); - } -}; - -} // namespace idx - -} // namespace clang - -namespace llvm { -/// Define DenseMapInfo so that GlobalSelectors can be used as keys in DenseMap -/// and DenseSets. -template<> -struct DenseMapInfo { - static inline clang::idx::GlobalSelector getEmptyKey() { - return clang::idx::GlobalSelector::getEmptyMarker(); - } - - static inline clang::idx::GlobalSelector getTombstoneKey() { - return clang::idx::GlobalSelector::getTombstoneMarker(); - } - - static unsigned getHashValue(clang::idx::GlobalSelector); - - static inline bool - isEqual(clang::idx::GlobalSelector LHS, clang::idx::GlobalSelector RHS) { - return LHS == RHS; - } -}; - -template <> -struct isPodLike { static const bool value = true;}; - -} // end namespace llvm - -#endif diff --git a/include/clang/Index/Handlers.h b/include/clang/Index/Handlers.h deleted file mode 100644 index 1e017f8a7c83..000000000000 --- a/include/clang/Index/Handlers.h +++ /dev/null @@ -1,82 +0,0 @@ -//===--- Handlers.h - Interfaces for receiving information ------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Abstract interfaces for receiving information. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INDEX_HANDLERS_H -#define LLVM_CLANG_INDEX_HANDLERS_H - -#include "clang/Basic/LLVM.h" -#include "llvm/ADT/SmallVector.h" - -namespace clang { - -namespace idx { - class Entity; - class TranslationUnit; - class TULocation; - -/// \brief Abstract interface for receiving Entities. -class EntityHandler { -public: - typedef Entity receiving_type; - - virtual ~EntityHandler(); - virtual void Handle(Entity Ent) = 0; -}; - -/// \brief Abstract interface for receiving TranslationUnits. -class TranslationUnitHandler { -public: - typedef TranslationUnit* receiving_type; - - virtual ~TranslationUnitHandler(); - virtual void Handle(TranslationUnit *TU) = 0; -}; - -/// \brief Abstract interface for receiving TULocations. -class TULocationHandler { -public: - typedef TULocation receiving_type; - - virtual ~TULocationHandler(); - virtual void Handle(TULocation TULoc) = 0; -}; - -/// \brief Helper for the Handler classes. Stores the objects into a vector. -/// example: -/// @code -/// Storing TURes; -/// IndexProvider.GetTranslationUnitsFor(Entity, TURes); -/// for (Storing::iterator -/// I = TURes.begin(), E = TURes.end(); I != E; ++I) { .... -/// @endcode -template -class Storing : public handler_type { - typedef typename handler_type::receiving_type receiving_type; - typedef SmallVector StoreTy; - StoreTy Store; - -public: - virtual void Handle(receiving_type Obj) { - Store.push_back(Obj); - } - - typedef typename StoreTy::const_iterator iterator; - iterator begin() const { return Store.begin(); } - iterator end() const { return Store.end(); } -}; - -} // namespace idx - -} // namespace clang - -#endif diff --git a/include/clang/Index/IndexProvider.h b/include/clang/Index/IndexProvider.h deleted file mode 100644 index 187dd9393cbb..000000000000 --- a/include/clang/Index/IndexProvider.h +++ /dev/null @@ -1,38 +0,0 @@ -//===--- IndexProvider.h - Maps information to translation units -*- C++ -*-==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Maps information to TranslationUnits. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INDEX_INDEXPROVIDER_H -#define LLVM_CLANG_INDEX_INDEXPROVIDER_H - -namespace clang { - -namespace idx { - class Entity; - class TranslationUnitHandler; - class GlobalSelector; - -/// \brief Maps information to TranslationUnits. -class IndexProvider { -public: - virtual ~IndexProvider(); - virtual void GetTranslationUnitsFor(Entity Ent, - TranslationUnitHandler &Handler) = 0; - virtual void GetTranslationUnitsFor(GlobalSelector Sel, - TranslationUnitHandler &Handler) = 0; -}; - -} // namespace idx - -} // namespace clang - -#endif diff --git a/include/clang/Index/Indexer.h b/include/clang/Index/Indexer.h deleted file mode 100644 index 96c585df2478..000000000000 --- a/include/clang/Index/Indexer.h +++ /dev/null @@ -1,71 +0,0 @@ -//===--- Indexer.h - IndexProvider implementation ---------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// IndexProvider implementation. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INDEX_INDEXER_H -#define LLVM_CLANG_INDEX_INDEXER_H - -#include "clang/Index/IndexProvider.h" -#include "clang/Index/Entity.h" -#include "clang/Index/GlobalSelector.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/DenseMap.h" -#include - -namespace clang { - class ASTContext; - class FunctionDecl; - -namespace idx { - class Program; - class TranslationUnit; - -/// \brief Maps information to TranslationUnits. -class Indexer : public IndexProvider { -public: - typedef llvm::SmallPtrSet TUSetTy; - typedef llvm::DenseMap CtxTUMapTy; - typedef std::map MapTy; - typedef std::map SelMapTy; - typedef std::map > DefMapTy; - - explicit Indexer(Program &prog) : - Prog(prog) { } - - Program &getProgram() const { return Prog; } - - /// \brief Find all Entities and map them to the given translation unit. - void IndexAST(TranslationUnit *TU); - - virtual void GetTranslationUnitsFor(Entity Ent, - TranslationUnitHandler &Handler); - virtual void GetTranslationUnitsFor(GlobalSelector Sel, - TranslationUnitHandler &Handler); - - std::pair getDefinitionFor(Entity Ent); - -private: - Program &Prog; - - MapTy Map; - // Map a function Entity to the its definition. - DefMapTy DefMap; - - CtxTUMapTy CtxTUMap; - SelMapTy SelMap; -}; - -} // namespace idx - -} // namespace clang - -#endif diff --git a/include/clang/Index/Program.h b/include/clang/Index/Program.h deleted file mode 100644 index 8039192512d6..000000000000 --- a/include/clang/Index/Program.h +++ /dev/null @@ -1,45 +0,0 @@ -//===--- Program.h - Cross-translation unit information ---------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the idx::Program interface. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INDEX_PROGRAM_H -#define LLVM_CLANG_INDEX_PROGRAM_H - -namespace clang { - class ASTContext; - -namespace idx { - class EntityHandler; - -/// \brief Top level object that owns and maintains information -/// that is common across translation units. -class Program { - void *Impl; - - Program(const Program&); // do not implement - Program &operator=(const Program &); // do not implement - friend class Entity; - friend class GlobalSelector; - -public: - Program(); - ~Program(); - - /// \brief Traverses the AST and passes all the entities to the Handler. - void FindEntities(ASTContext &Ctx, EntityHandler &Handler); -}; - -} // namespace idx - -} // namespace clang - -#endif diff --git a/include/clang/Index/STLExtras.h b/include/clang/Index/STLExtras.h deleted file mode 100644 index a3693c6c79a6..000000000000 --- a/include/clang/Index/STLExtras.h +++ /dev/null @@ -1,63 +0,0 @@ -//===--- STLExtras.h - Helper STL related templates -------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Helper templates for using with the STL. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INDEX_STLEXTRAS_H -#define LLVM_CLANG_INDEX_STLEXTRAS_H - -namespace clang { - -namespace idx { - -/// \brief Wraps an iterator whose value_type is a pair, and provides -/// pair's second object as the value. -template -class pair_value_iterator { - iter_type I; - -public: - typedef typename iter_type::value_type::second_type value_type; - typedef value_type& reference; - typedef value_type* pointer; - typedef typename iter_type::iterator_category iterator_category; - typedef typename iter_type::difference_type difference_type; - - pair_value_iterator() { } - pair_value_iterator(iter_type i) : I(i) { } - - reference operator*() const { return I->second; } - pointer operator->() const { return &I->second; } - - pair_value_iterator& operator++() { - ++I; - return *this; - } - - pair_value_iterator operator++(int) { - pair_value_iterator tmp(*this); - ++(*this); - return tmp; - } - - friend bool operator==(pair_value_iterator L, pair_value_iterator R) { - return L.I == R.I; - } - friend bool operator!=(pair_value_iterator L, pair_value_iterator R) { - return L.I != R.I; - } -}; - -} // end idx namespace - -} // end clang namespace - -#endif diff --git a/include/clang/Index/SelectorMap.h b/include/clang/Index/SelectorMap.h deleted file mode 100644 index be01702fcbdb..000000000000 --- a/include/clang/Index/SelectorMap.h +++ /dev/null @@ -1,57 +0,0 @@ -//===--- SelectorMap.h - Maps selectors to methods and messages -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// SelectorMap creates a mapping from selectors to ObjC method declarations -// and ObjC message expressions. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INDEX_SELECTORMAP_H -#define LLVM_CLANG_INDEX_SELECTORMAP_H - -#include "clang/Index/ASTLocation.h" -#include "clang/Index/STLExtras.h" -#include "clang/Basic/IdentifierTable.h" -#include - -namespace clang { - class ASTContext; - class ObjCMethodDecl; - -namespace idx { - -/// \brief Maps NamedDecls with the ASTLocations that reference them. -/// -/// References are mapped and retrieved using the canonical decls. -class SelectorMap { -public: - explicit SelectorMap(ASTContext &Ctx); - - typedef std::multimap SelMethMapTy; - typedef std::multimap SelRefMapTy; - - typedef pair_value_iterator method_iterator; - typedef pair_value_iterator astlocation_iterator; - - method_iterator methods_begin(Selector Sel) const; - method_iterator methods_end(Selector Sel) const; - - astlocation_iterator refs_begin(Selector Sel) const; - astlocation_iterator refs_end(Selector Sel) const; - -private: - mutable SelMethMapTy SelMethMap; - mutable SelRefMapTy SelRefMap; -}; - -} // end idx namespace - -} // end clang namespace - -#endif diff --git a/include/clang/Index/TranslationUnit.h b/include/clang/Index/TranslationUnit.h deleted file mode 100644 index ba5d48d37321..000000000000 --- a/include/clang/Index/TranslationUnit.h +++ /dev/null @@ -1,41 +0,0 @@ -//===--- TranslationUnit.h - Interface for a translation unit ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Abstract interface for a translation unit. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INDEX_TRANSLATIONUNIT_H -#define LLVM_CLANG_INDEX_TRANSLATIONUNIT_H - -namespace clang { - class ASTContext; - class DiagnosticsEngine; - class Preprocessor; - -namespace idx { - class DeclReferenceMap; - class SelectorMap; - -/// \brief Abstract interface for a translation unit. -class TranslationUnit { -public: - virtual ~TranslationUnit(); - virtual ASTContext &getASTContext() = 0; - virtual Preprocessor &getPreprocessor() = 0; - virtual DiagnosticsEngine &getDiagnostic() = 0; - virtual DeclReferenceMap &getDeclReferenceMap() = 0; - virtual SelectorMap &getSelectorMap() = 0; -}; - -} // namespace idx - -} // namespace clang - -#endif diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 0e5e8c7d88c2..de62ed2def53 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -15,7 +15,6 @@ #define LLVM_CLANG_PARSE_PARSER_H #include "clang/Basic/Specifiers.h" -#include "clang/Basic/DelayedCleanupPool.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/CodeCompletionHandler.h" #include "clang/Sema/Sema.h" @@ -192,9 +191,9 @@ class Parser : public CodeCompletionHandler { /// Factory object for creating AttributeList objects. AttributeFactory AttrFactory; - /// \brief Gathers and cleans up objects when parsing of a top-level - /// declaration is finished. - DelayedCleanupPool TopLevelDeclCleanupPool; + /// \brief Gathers and cleans up TemplateIdAnnotations when parsing of a + /// top-level declaration is finished. + SmallVector TemplateIds; IdentifierInfo *getSEHExceptKeyword(); @@ -568,9 +567,7 @@ class Parser : public CodeCompletionHandler { const char *&PrevSpec, unsigned &DiagID, bool &isInvalid); - /// \brief Get the TemplateIdAnnotation from the token and put it in the - /// cleanup pool so that it gets destroyed when parsing the current top level - /// declaration is finished. + /// \brief Get the TemplateIdAnnotation from the token. TemplateIdAnnotation *takeTemplateIdAnnotation(const Token &tok); /// TentativeParsingAction - An object that is used as a kind of "tentative @@ -858,7 +855,7 @@ class Parser : public CodeCompletionHandler { /// argument (C++ [class.mem]p2). struct LateParsedMethodDeclaration : public LateParsedDeclaration { explicit LateParsedMethodDeclaration(Parser *P, Decl *M) - : Self(P), Method(M), TemplateScope(false) { } + : Self(P), Method(M), TemplateScope(false), ExceptionSpecTokens(0) { } virtual void ParseLexedMethodDeclarations(); @@ -878,6 +875,10 @@ class Parser : public CodeCompletionHandler { /// method will be stored so that they can be reintroduced into /// scope at the appropriate times. SmallVector DefaultArgs; + + /// \brief The set of tokens that make up an exception-specification that + /// has not yet been parsed. + CachedTokens *ExceptionSpecTokens; }; /// LateParsedMemberInitializer - An initializer for a non-static class data @@ -1420,11 +1421,13 @@ class Parser : public CodeCompletionHandler { // C++ 15: C++ Throw Expression ExprResult ParseThrowExpression(); - ExceptionSpecificationType MaybeParseExceptionSpecification( + ExceptionSpecificationType tryParseExceptionSpecification( + bool Delayed, SourceRange &SpecificationRange, SmallVectorImpl &DynamicExceptions, SmallVectorImpl &DynamicExceptionRanges, - ExprResult &NoexceptExpr); + ExprResult &NoexceptExpr, + CachedTokens *&ExceptionSpecTokens); // EndLoc is filled with the location of the last token of the specification. ExceptionSpecificationType ParseDynamicExceptionSpecification( @@ -1517,42 +1520,40 @@ class Parser : public CodeCompletionHandler { //===--------------------------------------------------------------------===// // C99 6.8: Statements and Blocks. - StmtResult ParseStatement(SourceLocation *TrailingElseLoc = NULL) { + StmtResult ParseStatement(SourceLocation *TrailingElseLoc = 0) { StmtVector Stmts(Actions); return ParseStatementOrDeclaration(Stmts, true, TrailingElseLoc); } - StmtResult ParseStatementOrDeclaration(StmtVector& Stmts, + StmtResult ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement, - SourceLocation *TrailingElseLoc = NULL); - StmtResult ParseExprStatement(ParsedAttributes &Attrs); - StmtResult ParseLabeledStatement(ParsedAttributes &Attr); - StmtResult ParseCaseStatement(ParsedAttributes &Attr, - bool MissingCase = false, + SourceLocation *TrailingElseLoc = 0); + StmtResult ParseStatementOrDeclarationAfterAttributes( + StmtVector &Stmts, + bool OnlyStatement, + SourceLocation *TrailingElseLoc, + ParsedAttributesWithRange &Attrs); + StmtResult ParseExprStatement(); + StmtResult ParseLabeledStatement(ParsedAttributesWithRange &attrs); + StmtResult ParseCaseStatement(bool MissingCase = false, ExprResult Expr = ExprResult()); - StmtResult ParseDefaultStatement(ParsedAttributes &Attr); - StmtResult ParseCompoundStatement(ParsedAttributes &Attr, - bool isStmtExpr = false); - StmtResult ParseCompoundStatement(ParsedAttributes &Attr, - bool isStmtExpr, + StmtResult ParseDefaultStatement(); + StmtResult ParseCompoundStatement(bool isStmtExpr = false); + StmtResult ParseCompoundStatement(bool isStmtExpr, unsigned ScopeFlags); StmtResult ParseCompoundStatementBody(bool isStmtExpr = false); bool ParseParenExprOrCondition(ExprResult &ExprResult, Decl *&DeclResult, SourceLocation Loc, bool ConvertToBoolean); - StmtResult ParseIfStatement(ParsedAttributes &Attr, - SourceLocation *TrailingElseLoc); - StmtResult ParseSwitchStatement(ParsedAttributes &Attr, - SourceLocation *TrailingElseLoc); - StmtResult ParseWhileStatement(ParsedAttributes &Attr, - SourceLocation *TrailingElseLoc); - StmtResult ParseDoStatement(ParsedAttributes &Attr); - StmtResult ParseForStatement(ParsedAttributes &Attr, - SourceLocation *TrailingElseLoc); - StmtResult ParseGotoStatement(ParsedAttributes &Attr); - StmtResult ParseContinueStatement(ParsedAttributes &Attr); - StmtResult ParseBreakStatement(ParsedAttributes &Attr); - StmtResult ParseReturnStatement(ParsedAttributes &Attr); + StmtResult ParseIfStatement(SourceLocation *TrailingElseLoc); + StmtResult ParseSwitchStatement(SourceLocation *TrailingElseLoc); + StmtResult ParseWhileStatement(SourceLocation *TrailingElseLoc); + StmtResult ParseDoStatement(); + StmtResult ParseForStatement(SourceLocation *TrailingElseLoc); + StmtResult ParseGotoStatement(); + StmtResult ParseContinueStatement(); + StmtResult ParseBreakStatement(); + StmtResult ParseReturnStatement(); StmtResult ParseAsmStatement(bool &msAsm); StmtResult ParseMicrosoftAsmStatement(SourceLocation AsmLoc); @@ -1586,7 +1587,7 @@ class Parser : public CodeCompletionHandler { /// \brief The behavior of this __if_exists or __if_not_exists block /// should. IfExistsBehavior Behavior; -}; + }; bool ParseMicrosoftIfExistsCondition(IfExistsCondition& Result); void ParseMicrosoftIfExistsStatement(StmtVector &Stmts); @@ -1602,14 +1603,14 @@ class Parser : public CodeCompletionHandler { //===--------------------------------------------------------------------===// // C++ 6: Statements and Blocks - StmtResult ParseCXXTryBlock(ParsedAttributes &Attr); + StmtResult ParseCXXTryBlock(); StmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc); StmtResult ParseCXXCatchBlock(); //===--------------------------------------------------------------------===// // MS: SEH Statements and Blocks - StmtResult ParseSEHTryBlock(ParsedAttributes &Attr); + StmtResult ParseSEHTryBlock(); StmtResult ParseSEHTryBlockCommon(SourceLocation Loc); StmtResult ParseSEHExceptBlock(SourceLocation Loc); StmtResult ParseSEHFinallyBlock(SourceLocation Loc); @@ -1883,6 +1884,7 @@ class Parser : public CodeCompletionHandler { void ProhibitAttributes(ParsedAttributesWithRange &attrs) { if (!attrs.Range.isValid()) return; DiagnoseProhibitedAttributes(attrs); + attrs.clear(); } void DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs); @@ -1967,7 +1969,7 @@ class Parser : public CodeCompletionHandler { void ParseTypeofSpecifier(DeclSpec &DS); SourceLocation ParseDecltypeSpecifier(DeclSpec &DS); - void AnnotateExistingDecltypeSpecifier(const DeclSpec &DS, + void AnnotateExistingDecltypeSpecifier(const DeclSpec &DS, SourceLocation StartLoc, SourceLocation EndLoc); void ParseUnderlyingTypeSpecifier(DeclSpec &DS); @@ -2106,8 +2108,8 @@ class Parser : public CodeCompletionHandler { ParsingDeclRAIIObject *DiagsFromTParams = 0); void ParseConstructorInitializer(Decl *ConstructorDecl); MemInitResult ParseMemInitializer(Decl *ConstructorDecl); - void HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, - Decl *ThisDecl); + void HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo, + Decl *ThisDecl); //===--------------------------------------------------------------------===// // C++ 10: Derived classes [class.derived] diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 67fd3939f35d..2f3dda408e32 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -1150,6 +1150,10 @@ struct DeclaratorChunk { /// \brief Pointer to the expression in the noexcept-specifier of this /// function, if it has one. Expr *NoexceptExpr; + + /// \brief Pointer to the cached tokens for an exception-specification + /// that has not yet been parsed. + CachedTokens *ExceptionSpecTokens; }; /// TrailingReturnType - If this isn't null, it's the trailing return type @@ -1172,6 +1176,8 @@ struct DeclaratorChunk { delete[] ArgInfo; if (getExceptionSpecType() == EST_Dynamic) delete[] Exceptions; + else if (getExceptionSpecType() == EST_Delayed) + delete ExceptionSpecTokens; } /// isKNRPrototype - Return true if this is a K&R style identifier list, @@ -1347,6 +1353,7 @@ struct DeclaratorChunk { SourceRange *ExceptionRanges, unsigned NumExceptions, Expr *NoexceptExpr, + CachedTokens *ExceptionSpecTokens, SourceLocation LocalRangeBegin, SourceLocation LocalRangeEnd, Declarator &TheDeclarator, diff --git a/include/clang/Sema/ParsedTemplate.h b/include/clang/Sema/ParsedTemplate.h index 3ff045954be7..c1b471014b73 100644 --- a/include/clang/Sema/ParsedTemplate.h +++ b/include/clang/Sema/ParsedTemplate.h @@ -178,8 +178,11 @@ namespace clang { ParsedTemplateArgument *getTemplateArgs() { return reinterpret_cast(this + 1); } - - static TemplateIdAnnotation* Allocate(unsigned NumArgs) { + + /// \brief Creates a new TemplateIdAnnotation with NumArgs arguments and + /// appends it to List. + static TemplateIdAnnotation * + Allocate(unsigned NumArgs, SmallVectorImpl &List) { TemplateIdAnnotation *TemplateId = (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) + sizeof(ParsedTemplateArgument) * NumArgs); @@ -193,6 +196,7 @@ namespace clang { for (unsigned I = 0; I != NumArgs; ++I) new (TemplateArgs + I) ParsedTemplateArgument(); + List.push_back(TemplateId); return TemplateId; } diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h index e9aa173cb9c7..48f54179ec4a 100644 --- a/include/clang/Sema/Scope.h +++ b/include/clang/Sema/Scope.h @@ -81,13 +81,8 @@ class Scope { /// SwitchScope - This is a scope that corresponds to a switch statement. SwitchScope = 0x800, - /// ThisScope - This is the scope of a struct/union/class definition, - /// outside of any member function definition, where 'this' is nonetheless - /// usable. - ThisScope = 0x1000, - /// TryScope - This is the scope of a C++ try statement. - TryScope = 0x2000 + TryScope = 0x1000 }; private: /// The parent scope for this scope. This is null for the translation-unit diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 31c410a9f90a..8ac7c3ee01a3 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -446,11 +446,13 @@ class Sema { Sema &S; DeclContext *SavedContext; ProcessingContextState SavedContextState; - + QualType SavedCXXThisTypeOverride; + public: ContextRAII(Sema &S, DeclContext *ContextToPush) : S(S), SavedContext(S.CurContext), - SavedContextState(S.DelayedDiagnostics.pushContext()) + SavedContextState(S.DelayedDiagnostics.pushContext()), + SavedCXXThisTypeOverride(S.CXXThisTypeOverride) { assert(ContextToPush && "pushing null context"); S.CurContext = ContextToPush; @@ -460,6 +462,7 @@ class Sema { if (!SavedContext) return; S.CurContext = SavedContext; S.DelayedDiagnostics.popContext(SavedContextState); + S.CXXThisTypeOverride = SavedCXXThisTypeOverride; SavedContext = 0; } @@ -646,7 +649,7 @@ class Sema { /// A stack of expression evaluation contexts. SmallVector ExprEvalContexts; - + /// SpecialMemberOverloadResult - The overloading result for a special member /// function. /// @@ -898,11 +901,15 @@ class Sema { TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy); TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, TypeSourceInfo *ReturnTypeInfo); + /// \brief Package the given type and TSI into a ParsedType. ParsedType CreateParsedType(QualType T, TypeSourceInfo *TInfo); DeclarationNameInfo GetNameForDeclarator(Declarator &D); DeclarationNameInfo GetNameFromUnqualifiedId(const UnqualifiedId &Name); static QualType GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo = 0); + CanThrowResult canThrow(const Expr *E); + const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc, + const FunctionProtoType *FPT); bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range); bool CheckDistantExceptionSpec(QualType T); bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New); @@ -1974,6 +1981,10 @@ class Sema { bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC); bool CheckNoReturnAttr(const AttributeList &attr); + /// \brief Stmt attributes - this routine is the top level dispatcher. + StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs, + SourceRange Range); + void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, bool &IncompleteImpl, unsigned DiagID); void WarnConflictingTypedMethods(ObjCMethodDecl *Method, @@ -2251,6 +2262,9 @@ class Sema { StmtResult ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, SourceLocation ColonLoc, Stmt *SubStmt); + StmtResult ActOnAttributedStmt(SourceLocation AttrLoc, const AttrVec &Attrs, + Stmt *SubStmt); + StmtResult ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar, Stmt *ThenVal, @@ -3039,7 +3053,7 @@ class Sema { /// implicitly-declared special member functions. class ImplicitExceptionSpecification { // Pointer to allow copying - ASTContext *Context; + Sema *Self; // We order exception specifications thus: // noexcept is the most restrictive, but is only used in C++0x. // throw() comes next. @@ -3063,9 +3077,9 @@ class Sema { } public: - explicit ImplicitExceptionSpecification(ASTContext &Context) - : Context(&Context), ComputedEST(EST_BasicNoexcept) { - if (!Context.getLangOpts().CPlusPlus0x) + explicit ImplicitExceptionSpecification(Sema &Self) + : Self(&Self), ComputedEST(EST_BasicNoexcept) { + if (!Self.Context.getLangOpts().CPlusPlus0x) ComputedEST = EST_DynamicNone; } @@ -3083,7 +3097,7 @@ class Sema { const QualType *data() const { return Exceptions.data(); } /// \brief Integrate another called method into the collected data. - void CalledDecl(CXXMethodDecl *Method); + void CalledDecl(SourceLocation CallLoc, CXXMethodDecl *Method); /// \brief Integrate an invoked expression into the collected data. void CalledExpr(Expr *E); @@ -3135,6 +3149,25 @@ class Sema { ImplicitExceptionSpecification ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl); + /// \brief Check the given exception-specification and update the + /// extended prototype information with the results. + void checkExceptionSpecification(ExceptionSpecificationType EST, + ArrayRef DynamicExceptions, + ArrayRef DynamicExceptionRanges, + Expr *NoexceptExpr, + llvm::SmallVectorImpl &Exceptions, + FunctionProtoType::ExtProtoInfo &EPI); + + /// \brief Add an exception-specification to the given member function + /// (or member function template). The exception-specification was parsed + /// after the method itself was declared. + void actOnDelayedExceptionSpecification(Decl *Method, + ExceptionSpecificationType EST, + SourceRange SpecificationRange, + ArrayRef DynamicExceptions, + ArrayRef DynamicExceptionRanges, + Expr *NoexceptExpr); + /// \brief Determine if a special member function should have a deleted /// definition when it is defaulted. bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, @@ -3240,6 +3273,22 @@ class Sema { /// special member function. bool isImplicitlyDeleted(FunctionDecl *FD); + /// \brief Check whether 'this' shows up in the type of a static member + /// function after the (naturally empty) cv-qualifier-seq would be. + /// + /// \returns true if an error occurred. + bool checkThisInStaticMemberFunctionType(CXXMethodDecl *Method); + + /// \brief Whether this' shows up in the exception specification of a static + /// member function. + bool checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method); + + /// \brief Check whether 'this' shows up in the attributes of the given + /// static member function. + /// + /// \returns true if an error occurred. + bool checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method); + /// MaybeBindToTemporary - If the passed in expression has a record type with /// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise /// it simply returns the passed in expression. @@ -3321,6 +3370,29 @@ class Sema { /// \returns The type of 'this', if possible. Otherwise, returns a NULL type. QualType getCurrentThisType(); + /// \brief When non-NULL, the C++ 'this' expression is allowed despite the + /// current context not being a non-static member function. In such cases, + /// this provides the type used for 'this'. + QualType CXXThisTypeOverride; + + /// \brief RAII object used to temporarily allow the C++ 'this' expression + /// to be used, with the given qualifiers on the current class type. + class CXXThisScopeRAII { + Sema &S; + QualType OldCXXThisTypeOverride; + bool Enabled; + + public: + /// \brief Introduce a new scope where 'this' may be allowed (when enabled), + /// using the given declaration (which is either a class template or a + /// class) along with the given qualifiers. + /// along with the qualifiers placed on '*this'. + CXXThisScopeRAII(Sema &S, Decl *ContextDecl, unsigned CXXThisTypeQuals, + bool Enabled = true); + + ~CXXThisScopeRAII(); + }; + /// \brief Make sure the value of 'this' is actually available in the current /// context, if it is a potentially evaluated context. /// @@ -3330,6 +3402,11 @@ class Sema { /// capture list. void CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false); + /// \brief Determine whether the given type is the type of *this that is used + /// outside of the body of a member function for a type that is currently + /// being defined. + bool isThisOutsideMemberFunctionBody(QualType BaseType); + /// ActOnCXXBoolLiteral - Parse {true,false} literals. ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind); @@ -5120,7 +5197,11 @@ class Sema { /// We are checking the validity of a default template argument that /// has been used when naming a template-id. - DefaultTemplateArgumentChecking + DefaultTemplateArgumentChecking, + + /// We are instantiating the exception specification for a function + /// template which was deferred until it was needed. + ExceptionSpecInstantiation } Kind; /// \brief The point of instantiation within the source code. @@ -5168,6 +5249,7 @@ class Sema { switch (X.Kind) { case TemplateInstantiation: + case ExceptionSpecInstantiation: return true; case PriorTemplateArgumentSubstitution: @@ -5285,6 +5367,13 @@ class Sema { Decl *Entity, SourceRange InstantiationRange = SourceRange()); + struct ExceptionSpecification {}; + /// \brief Note that we are instantiating an exception specification + /// of a function template. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + FunctionDecl *Entity, ExceptionSpecification, + SourceRange InstantiationRange = SourceRange()); + /// \brief Note that we are instantiating a default argument in a /// template-id. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -5474,7 +5563,9 @@ class Sema { TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, - DeclarationName Entity); + DeclarationName Entity, + CXXRecordDecl *ThisContext, + unsigned ThisTypeQuals); ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs, int indexAdjustment, @@ -5582,6 +5673,8 @@ class Sema { TemplateArgumentListInfo &Result, const MultiLevelTemplateArgumentList &TemplateArgs); + void InstantiateExceptionSpec(SourceLocation PointOfInstantiation, + FunctionDecl *Function); void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive = false, @@ -6463,11 +6556,11 @@ class Sema { /// and reports the appropriate diagnostics. Returns false on success. /// Can optionally return the value of the expression. ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, - PartialDiagnostic Diag, + const PartialDiagnostic &Diag, bool AllowFold, - PartialDiagnostic FoldDiag); + const PartialDiagnostic &FoldDiag); ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, - PartialDiagnostic Diag, + const PartialDiagnostic &Diag, bool AllowFold = true) { return VerifyIntegerConstantExpression(E, Result, Diag, AllowFold, PDiag(0)); diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 4591630357dd..f9bb8928a362 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -964,6 +964,8 @@ namespace clang { STMT_DEFAULT, /// \brief A LabelStmt record. STMT_LABEL, + /// \brief An AttributedStmt record. + STMT_ATTRIBUTED, /// \brief An IfStmt record. STMT_IF, /// \brief A SwitchStmt record. diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 9baaf4bcb527..a9d0fc3f1e86 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -170,6 +170,9 @@ class ReadMethodPoolVisitor; namespace reader { class ASTIdentifierLookupTrait; + /// \brief The on-disk hash table used for the DeclContext's Name lookup table. + typedef OnDiskChainedHashTable + ASTDeclContextNameLookupTable; } } // end namespace serialization @@ -323,7 +326,9 @@ class ASTReader // TU, and when we read those update records, the actual context will not // be available yet (unless it's the TU), so have this pending map using the // ID as a key. It will be realized when the context is actually loaded. - typedef SmallVector, 1> DeclContextVisibleUpdates; + typedef + SmallVector, 1> DeclContextVisibleUpdates; typedef llvm::DenseMap DeclContextVisibleUpdatesPending; @@ -1467,7 +1472,7 @@ class ASTReader llvm::DenseMap::iterator Pos); /// \brief Load all external visible decls in the given DeclContext. - void completeVisibleDeclsMap(DeclContext *DC); + void completeVisibleDeclsMap(const DeclContext *DC); /// \brief Retrieve the AST context that this AST reader supplements. ASTContext &getContext() { return Context; } diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index 4c62385cf2c2..e693f17593f9 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -76,6 +76,7 @@ class ASTWriter : public ASTDeserializationListener, typedef SmallVectorImpl RecordDataImpl; friend class ASTDeclWriter; + friend class ASTStmtWriter; private: /// \brief Map that provides the ID numbers of each type within the /// output stream, plus those deserialized from a chained PCH. diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h index 4c93c33842cf..786ecd33c1d3 100644 --- a/include/clang/Serialization/Module.h +++ b/include/clang/Serialization/Module.h @@ -27,9 +27,14 @@ namespace clang { class DeclContext; class Module; - +template class OnDiskChainedHashTable; + namespace serialization { +namespace reader { + class ASTDeclContextNameLookupTrait; +} + /// \brief Specifies the kind of module that has been loaded. enum ModuleKind { MK_Module, ///< File is a module proper. @@ -43,7 +48,8 @@ struct DeclContextInfo { DeclContextInfo() : NameLookupTableData(), LexicalDecls(), NumLexicalDecls() {} - void *NameLookupTableData; // an ASTDeclContextNameLookupTable. + OnDiskChainedHashTable + *NameLookupTableData; // an ASTDeclContextNameLookupTable. const KindDeclIDPair *LexicalDecls; unsigned NumLexicalDecls; }; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h index 3cbecf7d6efc..d01644ba0eb5 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h @@ -22,11 +22,6 @@ namespace clang { -namespace idx { - class Indexer; - class TranslationUnit; -} - namespace ento { class CheckerManager; @@ -46,11 +41,6 @@ class AnalysisManager : public BugReporterData { CheckerManager *CheckerMgr; - /// \brief Provide function definitions in other translation units. This is - /// NULL if we don't have multiple translation units. AnalysisManager does - /// not own the Indexer. - idx::Indexer *Idxer; - enum AnalysisScope { ScopeTU, ScopeDecl } AScope; /// \brief The maximum number of exploded nodes the analyzer will generate. @@ -99,7 +89,6 @@ class AnalysisManager : public BugReporterData { StoreManagerCreator storemgr, ConstraintManagerCreator constraintmgr, CheckerManager *checkerMgr, - idx::Indexer *idxer, unsigned maxnodes, unsigned maxvisit, bool vizdot, bool vizubi, AnalysisPurgeMode purge, bool eager, bool trim, @@ -137,8 +126,6 @@ class AnalysisManager : public BugReporterData { CheckerManager *getCheckerManager() const { return CheckerMgr; } - idx::Indexer *getIndexer() const { return Idxer; } - virtual ASTContext &getASTContext() { return Ctx; } @@ -186,10 +173,6 @@ class AnalysisManager : public BugReporterData { bool shouldInlineCall() const { return (IPAMode == Inlining); } - bool hasIndexer() const { return Idxer != 0; } - - AnalysisDeclContext *getAnalysisDeclContextInAnotherTU(const Decl *D); - CFG *getCFG(Decl const *D) { return AnaCtxMgr.getContext(D)->getCFG(); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index ed01db25ef2e..ce3eb1db8365 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -425,10 +425,12 @@ class MemRegionVal : public Loc { public: explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {} + /// \brief Get the underlining region. const MemRegion* getRegion() const { return static_cast(Data); } + /// \brief Get the underlining region and strip casts. const MemRegion* stripCasts() const; template diff --git a/include/clang/Tooling/CompilationDatabase.h b/include/clang/Tooling/CompilationDatabase.h index 3430320b511e..625c8eced4b8 100644 --- a/include/clang/Tooling/CompilationDatabase.h +++ b/include/clang/Tooling/CompilationDatabase.h @@ -33,22 +33,21 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/YAMLParser.h" #include #include -namespace llvm { -class MemoryBuffer; -} // end namespace llvm - namespace clang { namespace tooling { /// \brief Specifies the working directory and command of a compilation. struct CompileCommand { CompileCommand() {} - CompileCommand(StringRef Directory, ArrayRef CommandLine) - : Directory(Directory), CommandLine(CommandLine) {} + CompileCommand(Twine Directory, ArrayRef CommandLine) + : Directory(Directory.str()), CommandLine(CommandLine) {} /// \brief The working directory the command was executed from. std::string Directory; @@ -95,6 +94,59 @@ class CompilationDatabase { StringRef FilePath) const = 0; }; +/// \brief A compilation database that returns a single compile command line. +/// +/// Useful when we want a tool to behave more like a compiler invocation. +class FixedCompilationDatabase : public CompilationDatabase { +public: + /// \brief Creates a FixedCompilationDatabase from the arguments after "--". + /// + /// Parses the given command line for "--". If "--" is found, the rest of + /// the arguments will make up the command line in the returned + /// FixedCompilationDatabase. + /// The arguments after "--" must not include positional parameters or the + /// argv[0] of the tool. Those will be added by the FixedCompilationDatabase + /// when a CompileCommand is requested. The argv[0] of the returned command + /// line will be "clang-tool". + /// + /// Returns NULL in case "--" is not found. + /// + /// The argument list is meant to be compatible with normal llvm command line + /// parsing in main methods. + /// int main(int argc, char **argv) { + /// llvm::OwningPtr Compilations( + /// FixedCompilationDatabase::loadFromCommandLine(argc, argv)); + /// cl::ParseCommandLineOptions(argc, argv); + /// ... + /// } + /// + /// \param Argc The number of command line arguments - will be changed to + /// the number of arguments before "--", if "--" was found in the argument + /// list. + /// \param Argv Points to the command line arguments. + /// \param Directory The base directory used in the FixedCompilationDatabase. + static FixedCompilationDatabase *loadFromCommandLine(int &Argc, + const char **Argv, + Twine Directory = "."); + + /// \brief Constructs a compilation data base from a specified directory + /// and command line. + FixedCompilationDatabase(Twine Directory, ArrayRef CommandLine); + + /// \brief Returns the given compile command. + /// + /// Will always return a vector with one entry that contains the directory + /// and command line specified at construction with "clang-tool" as argv[0] + /// and 'FilePath' as positional argument. + virtual std::vector getCompileCommands( + StringRef FilePath) const; + +private: + /// This is built up to contain a single entry vector to be returned from + /// getCompileCommands after adding the positional argument. + std::vector CompileCommands; +}; + /// \brief A JSON based compilation database. /// /// JSON compilation database files must contain a list of JSON objects which @@ -114,7 +166,6 @@ class CompilationDatabase { /// by setting the flag -DCMAKE_EXPORT_COMPILE_COMMANDS. class JSONCompilationDatabase : public CompilationDatabase { public: - /// \brief Loads a JSON compilation database from the specified file. /// /// Returns NULL and sets ErrorMessage if the database could not be @@ -139,7 +190,7 @@ class JSONCompilationDatabase : public CompilationDatabase { private: /// \brief Constructs a JSON compilation database on a memory buffer. JSONCompilationDatabase(llvm::MemoryBuffer *Database) - : Database(Database) {} + : Database(Database), YAMLStream(Database->getBuffer(), SM) {} /// \brief Parses the database file and creates the index. /// @@ -147,14 +198,17 @@ class JSONCompilationDatabase : public CompilationDatabase { /// failed. bool parse(std::string &ErrorMessage); - // Tuple (directory, commandline) where 'commandline' is a JSON escaped bash - // escaped command line. - typedef std::pair CompileCommandRef; + // Tuple (directory, commandline) where 'commandline' pointing to the + // corresponding nodes in the YAML stream. + typedef std::pair CompileCommandRef; // Maps file paths to the compile command lines for that file. llvm::StringMap< std::vector > IndexByFile; llvm::OwningPtr Database; + llvm::SourceMgr SM; + llvm::yaml::Stream YAMLStream; }; } // end namespace tooling diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index acf5e0bbc9af..cb4d336de157 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -481,7 +481,8 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { InitBuiltinType(ObjCBuiltinSelTy, BuiltinType::ObjCSel); // Builtin type for __objc_yes and __objc_no - ObjCBuiltinBoolTy = SignedCharTy; + ObjCBuiltinBoolTy = (Target.useSignedCharForObjCBool() ? + SignedCharTy : BoolTy); ObjCConstantStringType = QualType(); @@ -2193,6 +2194,8 @@ ASTContext::getFunctionType(QualType ResultTy, Size += EPI.NumExceptions * sizeof(QualType); else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { Size += sizeof(Expr*); + } else if (EPI.ExceptionSpecType == EST_Uninstantiated) { + Size += 2 * sizeof(FunctionDecl*); } if (EPI.ConsumedArguments) Size += NumArgs * sizeof(bool); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 399f2e48abee..53032bc64d61 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -69,33 +69,25 @@ typedef NamedDecl::LinkageInfo LinkageInfo; namespace { /// Flags controlling the computation of linkage and visibility. struct LVFlags { - bool ConsiderGlobalVisibility; - bool ConsiderVisibilityAttributes; - bool ConsiderTemplateParameterTypes; + const bool ConsiderGlobalVisibility; + const bool ConsiderVisibilityAttributes; + const bool ConsiderTemplateParameterTypes; LVFlags() : ConsiderGlobalVisibility(true), ConsiderVisibilityAttributes(true), ConsiderTemplateParameterTypes(true) { } + LVFlags(bool Global, bool Attributes, bool Parameters) : + ConsiderGlobalVisibility(Global), + ConsiderVisibilityAttributes(Attributes), + ConsiderTemplateParameterTypes(Parameters) { + } + /// \brief Returns a set of flags that is only useful for computing the /// linkage, not the visibility, of a declaration. static LVFlags CreateOnlyDeclLinkage() { - LVFlags F; - F.ConsiderGlobalVisibility = false; - F.ConsiderVisibilityAttributes = false; - F.ConsiderTemplateParameterTypes = false; - return F; - } - - /// Returns a set of flags, otherwise based on these, which ignores - /// off all sources of visibility except template arguments. - LVFlags onlyTemplateVisibility() const { - LVFlags F = *this; - F.ConsiderGlobalVisibility = false; - F.ConsiderVisibilityAttributes = false; - F.ConsiderTemplateParameterTypes = false; - return F; + return LVFlags(false, false, false); } }; } // end anonymous namespace @@ -284,7 +276,6 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { if (F.ConsiderVisibilityAttributes) { if (llvm::Optional Vis = D->getExplicitVisibility()) { LV.setVisibility(*Vis, true); - F.ConsiderGlobalVisibility = false; } else { // If we're declared in a namespace with a visibility attribute, // use that namespace's visibility, but don't call it explicit. @@ -295,7 +286,6 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { if (!ND) continue; if (llvm::Optional Vis = ND->getExplicitVisibility()) { LV.setVisibility(*Vis, true); - F.ConsiderGlobalVisibility = false; break; } } @@ -335,8 +325,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { LinkageInfo TypeLV = getLVForType(Var->getType()); if (TypeLV.linkage() != ExternalLinkage) return LinkageInfo::uniqueExternal(); - LV.mergeVisibilityWithMin(TypeLV.visibility(), - TypeLV.visibilityExplicit()); + LV.mergeVisibilityWithMin(TypeLV); } if (Var->getStorageClass() == SC_PrivateExtern) @@ -412,7 +401,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { = Function->getTemplateSpecializationInfo()) { if (shouldConsiderTemplateLV(Function, specInfo)) { LV.merge(getLVForDecl(specInfo->getTemplate(), - F.onlyTemplateVisibility())); + LVFlags::CreateOnlyDeclLinkage())); const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments; LV.mergeWithMin(getLVForTemplateArgumentList(templateArgs, F)); } @@ -436,7 +425,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { if (shouldConsiderTemplateLV(spec)) { // From the template. LV.merge(getLVForDecl(spec->getSpecializedTemplate(), - F.onlyTemplateVisibility())); + LVFlags::CreateOnlyDeclLinkage())); // The arguments at which the template was instantiated. const TemplateArgumentList &TemplateArgs = spec->getTemplateArgs(); @@ -444,12 +433,6 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { } } - // Consider -fvisibility unless the type has C linkage. - if (F.ConsiderGlobalVisibility) - F.ConsiderGlobalVisibility = - (Context.getLangOpts().CPlusPlus && - !Tag->getDeclContext()->isExternCContext()); - // - an enumerator belonging to an enumeration with external linkage; } else if (isa(D)) { LinkageInfo EnumLV = getLVForDecl(cast(D->getDeclContext()), F); @@ -501,22 +484,47 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) { LinkageInfo LV; LV.mergeVisibility(D->getASTContext().getLangOpts().getVisibilityMode()); - // The flags we're going to use to compute the class's visibility. - LVFlags ClassF = F; - + bool DHasExplicitVisibility = false; // If we have an explicit visibility attribute, merge that in. if (F.ConsiderVisibilityAttributes) { if (llvm::Optional Vis = D->getExplicitVisibility()) { LV.mergeVisibility(*Vis, true); - // Ignore global visibility later, but not this attribute. - F.ConsiderGlobalVisibility = false; - - // Ignore both global visibility and attributes when computing our - // parent's visibility. - ClassF = F.onlyTemplateVisibility(); + DHasExplicitVisibility = true; } } + // Ignore both global visibility and attributes when computing our + // parent's visibility if we already have an explicit one. + LVFlags ClassF = DHasExplicitVisibility ? + LVFlags::CreateOnlyDeclLinkage() : F; + + // If we're paying attention to global visibility, apply + // -finline-visibility-hidden if this is an inline method. + // + // Note that we do this before merging information about + // the class visibility. + if (const CXXMethodDecl *MD = dyn_cast(D)) { + TemplateSpecializationKind TSK = TSK_Undeclared; + if (FunctionTemplateSpecializationInfo *spec + = MD->getTemplateSpecializationInfo()) { + TSK = spec->getTemplateSpecializationKind(); + } else if (MemberSpecializationInfo *MSI = + MD->getMemberSpecializationInfo()) { + TSK = MSI->getTemplateSpecializationKind(); + } + + const FunctionDecl *Def = 0; + // InlineVisibilityHidden only applies to definitions, and + // isInlined() only gives meaningful answers on definitions + // anyway. + if (TSK != TSK_ExplicitInstantiationDeclaration && + TSK != TSK_ExplicitInstantiationDefinition && + F.ConsiderGlobalVisibility && + !LV.visibilityExplicit() && + MD->getASTContext().getLangOpts().InlineVisibilityHidden && + MD->hasBody(Def) && Def->isInlined()) + LV.mergeVisibility(HiddenVisibility, true); + } // Class members only have linkage if their class has external // linkage. @@ -534,8 +542,6 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) { if (MD->getType()->getLinkage() == UniqueExternalLinkage) return LinkageInfo::uniqueExternal(); - TemplateSpecializationKind TSK = TSK_Undeclared; - // If this is a method template specialization, use the linkage for // the template parameters and arguments. if (FunctionTemplateSpecializationInfo *spec @@ -547,29 +553,6 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) { LV.merge(getLVForTemplateParameterList( spec->getTemplate()->getTemplateParameters())); } - - TSK = spec->getTemplateSpecializationKind(); - } else if (MemberSpecializationInfo *MSI = - MD->getMemberSpecializationInfo()) { - TSK = MSI->getTemplateSpecializationKind(); - } - - // If we're paying attention to global visibility, apply - // -finline-visibility-hidden if this is an inline method. - // - // Note that ConsiderGlobalVisibility doesn't yet have information - // about whether containing classes have visibility attributes, - // and that's intentional. - if (TSK != TSK_ExplicitInstantiationDeclaration && - TSK != TSK_ExplicitInstantiationDefinition && - F.ConsiderGlobalVisibility && - MD->getASTContext().getLangOpts().InlineVisibilityHidden) { - // InlineVisibilityHidden only applies to definitions, and - // isInlined() only gives meaningful answers on definitions - // anyway. - const FunctionDecl *Def = 0; - if (MD->hasBody(Def) && Def->isInlined()) - LV.setVisibility(HiddenVisibility); } // Note that in contrast to basically every other situation, we @@ -597,7 +580,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) { if (TypeLV.linkage() != ExternalLinkage) LV.mergeLinkage(UniqueExternalLinkage); if (!LV.visibilityExplicit()) - LV.mergeVisibility(TypeLV.visibility(), TypeLV.visibilityExplicit()); + LV.mergeVisibility(TypeLV); } return LV; @@ -802,7 +785,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) { LinkageInfo LV; if (Flags.ConsiderVisibilityAttributes) { if (llvm::Optional Vis = Function->getExplicitVisibility()) - LV.setVisibility(*Vis); + LV.setVisibility(*Vis, true); } if (const FunctionDecl *Prev = Function->getPreviousDecl()) { @@ -823,10 +806,10 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) { LinkageInfo LV; if (Var->getStorageClass() == SC_PrivateExtern) - LV.setVisibility(HiddenVisibility); + LV.setVisibility(HiddenVisibility, true); else if (Flags.ConsiderVisibilityAttributes) { if (llvm::Optional Vis = Var->getExplicitVisibility()) - LV.setVisibility(*Vis); + LV.setVisibility(*Vis, true); } if (const VarDecl *Prev = Var->getPreviousDecl()) { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 868109e3d56e..fcde5429b394 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1590,6 +1590,16 @@ void InitListExpr::setArrayFiller(Expr *filler) { inits[i] = filler; } +bool InitListExpr::isStringLiteralInit() const { + if (getNumInits() != 1) + return false; + const ConstantArrayType *CAT = dyn_cast(getType()); + if (!CAT || !CAT->getElementType()->isIntegerType()) + return false; + const Expr *Init = getInit(0)->IgnoreParenImpCasts(); + return isa(Init) || isa(Init); +} + SourceRange InitListExpr::getSourceRange() const { if (SyntacticForm) return SyntacticForm->getSourceRange(); @@ -1986,331 +1996,6 @@ QualType Expr::findBoundMemberType(const Expr *expr) { return QualType(); } -static Expr::CanThrowResult MergeCanThrow(Expr::CanThrowResult CT1, - Expr::CanThrowResult CT2) { - // CanThrowResult constants are ordered so that the maximum is the correct - // merge result. - return CT1 > CT2 ? CT1 : CT2; -} - -static Expr::CanThrowResult CanSubExprsThrow(ASTContext &C, const Expr *CE) { - Expr *E = const_cast(CE); - Expr::CanThrowResult R = Expr::CT_Cannot; - for (Expr::child_range I = E->children(); I && R != Expr::CT_Can; ++I) { - R = MergeCanThrow(R, cast(*I)->CanThrow(C)); - } - return R; -} - -static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Expr *E, - const Decl *D, - bool NullThrows = true) { - if (!D) - return NullThrows ? Expr::CT_Can : Expr::CT_Cannot; - - // See if we can get a function type from the decl somehow. - const ValueDecl *VD = dyn_cast(D); - if (!VD) // If we have no clue what we're calling, assume the worst. - return Expr::CT_Can; - - // As an extension, we assume that __attribute__((nothrow)) functions don't - // throw. - if (isa(D) && D->hasAttr()) - return Expr::CT_Cannot; - - QualType T = VD->getType(); - const FunctionProtoType *FT; - if ((FT = T->getAs())) { - } else if (const PointerType *PT = T->getAs()) - FT = PT->getPointeeType()->getAs(); - else if (const ReferenceType *RT = T->getAs()) - FT = RT->getPointeeType()->getAs(); - else if (const MemberPointerType *MT = T->getAs()) - FT = MT->getPointeeType()->getAs(); - else if (const BlockPointerType *BT = T->getAs()) - FT = BT->getPointeeType()->getAs(); - - if (!FT) - return Expr::CT_Can; - - if (FT->getExceptionSpecType() == EST_Delayed) { - assert(isa(D) && - "only constructor exception specs can be unknown"); - Ctx.getDiagnostics().Report(E->getLocStart(), - diag::err_exception_spec_unknown) - << E->getSourceRange(); - return Expr::CT_Can; - } - - return FT->isNothrow(Ctx) ? Expr::CT_Cannot : Expr::CT_Can; -} - -static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr *DC) { - if (DC->isTypeDependent()) - return Expr::CT_Dependent; - - if (!DC->getTypeAsWritten()->isReferenceType()) - return Expr::CT_Cannot; - - if (DC->getSubExpr()->isTypeDependent()) - return Expr::CT_Dependent; - - return DC->getCastKind() == clang::CK_Dynamic? Expr::CT_Can : Expr::CT_Cannot; -} - -static Expr::CanThrowResult CanTypeidThrow(ASTContext &C, - const CXXTypeidExpr *DC) { - if (DC->isTypeOperand()) - return Expr::CT_Cannot; - - Expr *Op = DC->getExprOperand(); - if (Op->isTypeDependent()) - return Expr::CT_Dependent; - - const RecordType *RT = Op->getType()->getAs(); - if (!RT) - return Expr::CT_Cannot; - - if (!cast(RT->getDecl())->isPolymorphic()) - return Expr::CT_Cannot; - - if (Op->Classify(C).isPRValue()) - return Expr::CT_Cannot; - - return Expr::CT_Can; -} - -Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { - // C++ [expr.unary.noexcept]p3: - // [Can throw] if in a potentially-evaluated context the expression would - // contain: - switch (getStmtClass()) { - case CXXThrowExprClass: - // - a potentially evaluated throw-expression - return CT_Can; - - case CXXDynamicCastExprClass: { - // - a potentially evaluated dynamic_cast expression dynamic_cast(v), - // where T is a reference type, that requires a run-time check - CanThrowResult CT = CanDynamicCastThrow(cast(this)); - if (CT == CT_Can) - return CT; - return MergeCanThrow(CT, CanSubExprsThrow(C, this)); - } - - case CXXTypeidExprClass: - // - a potentially evaluated typeid expression applied to a glvalue - // expression whose type is a polymorphic class type - return CanTypeidThrow(C, cast(this)); - - // - a potentially evaluated call to a function, member function, function - // pointer, or member function pointer that does not have a non-throwing - // exception-specification - case CallExprClass: - case CXXMemberCallExprClass: - case CXXOperatorCallExprClass: - case UserDefinedLiteralClass: { - const CallExpr *CE = cast(this); - CanThrowResult CT; - if (isTypeDependent()) - CT = CT_Dependent; - else if (isa(CE->getCallee()->IgnoreParens())) - CT = CT_Cannot; - else - CT = CanCalleeThrow(C, this, CE->getCalleeDecl()); - if (CT == CT_Can) - return CT; - return MergeCanThrow(CT, CanSubExprsThrow(C, this)); - } - - case CXXConstructExprClass: - case CXXTemporaryObjectExprClass: { - CanThrowResult CT = CanCalleeThrow(C, this, - cast(this)->getConstructor()); - if (CT == CT_Can) - return CT; - return MergeCanThrow(CT, CanSubExprsThrow(C, this)); - } - - case LambdaExprClass: { - const LambdaExpr *Lambda = cast(this); - CanThrowResult CT = Expr::CT_Cannot; - for (LambdaExpr::capture_init_iterator Cap = Lambda->capture_init_begin(), - CapEnd = Lambda->capture_init_end(); - Cap != CapEnd; ++Cap) - CT = MergeCanThrow(CT, (*Cap)->CanThrow(C)); - return CT; - } - - case CXXNewExprClass: { - CanThrowResult CT; - if (isTypeDependent()) - CT = CT_Dependent; - else - CT = CanCalleeThrow(C, this, cast(this)->getOperatorNew()); - if (CT == CT_Can) - return CT; - return MergeCanThrow(CT, CanSubExprsThrow(C, this)); - } - - case CXXDeleteExprClass: { - CanThrowResult CT; - QualType DTy = cast(this)->getDestroyedType(); - if (DTy.isNull() || DTy->isDependentType()) { - CT = CT_Dependent; - } else { - CT = CanCalleeThrow(C, this, - cast(this)->getOperatorDelete()); - if (const RecordType *RT = DTy->getAs()) { - const CXXRecordDecl *RD = cast(RT->getDecl()); - CT = MergeCanThrow(CT, CanCalleeThrow(C, this, RD->getDestructor())); - } - if (CT == CT_Can) - return CT; - } - return MergeCanThrow(CT, CanSubExprsThrow(C, this)); - } - - case CXXBindTemporaryExprClass: { - // The bound temporary has to be destroyed again, which might throw. - CanThrowResult CT = CanCalleeThrow(C, this, - cast(this)->getTemporary()->getDestructor()); - if (CT == CT_Can) - return CT; - return MergeCanThrow(CT, CanSubExprsThrow(C, this)); - } - - // ObjC message sends are like function calls, but never have exception - // specs. - case ObjCMessageExprClass: - case ObjCPropertyRefExprClass: - case ObjCSubscriptRefExprClass: - return CT_Can; - - // All the ObjC literals that are implemented as calls are - // potentially throwing unless we decide to close off that - // possibility. - case ObjCArrayLiteralClass: - case ObjCDictionaryLiteralClass: - case ObjCNumericLiteralClass: - return CT_Can; - - // Many other things have subexpressions, so we have to test those. - // Some are simple: - case ConditionalOperatorClass: - case CompoundLiteralExprClass: - case CXXConstCastExprClass: - case CXXDefaultArgExprClass: - case CXXReinterpretCastExprClass: - case DesignatedInitExprClass: - case ExprWithCleanupsClass: - case ExtVectorElementExprClass: - case InitListExprClass: - case MemberExprClass: - case ObjCIsaExprClass: - case ObjCIvarRefExprClass: - case ParenExprClass: - case ParenListExprClass: - case ShuffleVectorExprClass: - case VAArgExprClass: - return CanSubExprsThrow(C, this); - - // Some might be dependent for other reasons. - case ArraySubscriptExprClass: - case BinaryOperatorClass: - case CompoundAssignOperatorClass: - case CStyleCastExprClass: - case CXXStaticCastExprClass: - case CXXFunctionalCastExprClass: - case ImplicitCastExprClass: - case MaterializeTemporaryExprClass: - case UnaryOperatorClass: { - CanThrowResult CT = isTypeDependent() ? CT_Dependent : CT_Cannot; - return MergeCanThrow(CT, CanSubExprsThrow(C, this)); - } - - // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms. - case StmtExprClass: - return CT_Can; - - case ChooseExprClass: - if (isTypeDependent() || isValueDependent()) - return CT_Dependent; - return cast(this)->getChosenSubExpr(C)->CanThrow(C); - - case GenericSelectionExprClass: - if (cast(this)->isResultDependent()) - return CT_Dependent; - return cast(this)->getResultExpr()->CanThrow(C); - - // Some expressions are always dependent. - case CXXDependentScopeMemberExprClass: - case CXXUnresolvedConstructExprClass: - case DependentScopeDeclRefExprClass: - return CT_Dependent; - - case AtomicExprClass: - case AsTypeExprClass: - case BinaryConditionalOperatorClass: - case BlockExprClass: - case CUDAKernelCallExprClass: - case DeclRefExprClass: - case ObjCBridgedCastExprClass: - case ObjCIndirectCopyRestoreExprClass: - case ObjCProtocolExprClass: - case ObjCSelectorExprClass: - case OffsetOfExprClass: - case PackExpansionExprClass: - case PseudoObjectExprClass: - case SubstNonTypeTemplateParmExprClass: - case SubstNonTypeTemplateParmPackExprClass: - case UnaryExprOrTypeTraitExprClass: - case UnresolvedLookupExprClass: - case UnresolvedMemberExprClass: - // FIXME: Can any of the above throw? If so, when? - return CT_Cannot; - - case AddrLabelExprClass: - case ArrayTypeTraitExprClass: - case BinaryTypeTraitExprClass: - case TypeTraitExprClass: - case CXXBoolLiteralExprClass: - case CXXNoexceptExprClass: - case CXXNullPtrLiteralExprClass: - case CXXPseudoDestructorExprClass: - case CXXScalarValueInitExprClass: - case CXXThisExprClass: - case CXXUuidofExprClass: - case CharacterLiteralClass: - case ExpressionTraitExprClass: - case FloatingLiteralClass: - case GNUNullExprClass: - case ImaginaryLiteralClass: - case ImplicitValueInitExprClass: - case IntegerLiteralClass: - case ObjCEncodeExprClass: - case ObjCStringLiteralClass: - case ObjCBoolLiteralExprClass: - case OpaqueValueExprClass: - case PredefinedExprClass: - case SizeOfPackExprClass: - case StringLiteralClass: - case UnaryTypeTraitExprClass: - // These expressions can never throw. - return CT_Cannot; - -#define STMT(CLASS, PARENT) case CLASS##Class: -#define STMT_RANGE(Base, First, Last) -#define LAST_STMT_RANGE(BASE, FIRST, LAST) -#define EXPR(CLASS, PARENT) -#define ABSTRACT_STMT(STMT) -#include "clang/AST/StmtNodes.inc" - case NoStmtClass: - llvm_unreachable("Invalid class for expression"); - } - llvm_unreachable("Bogus StmtClass"); -} - Expr* Expr::IgnoreParens() { Expr* E = this; while (true) { diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 01c9fe7cd846..66a88b065ce1 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -934,6 +934,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) { case Expr::ObjCStringLiteralClass: case Expr::ObjCEncodeExprClass: case Expr::CXXTypeidExprClass: + case Expr::CXXUuidofExprClass: return true; case Expr::CallExprClass: return IsStringLiteralCall(cast(E)); @@ -1491,15 +1492,19 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived, llvm_unreachable("base class missing from derived class's bases list"); } -/// Extract the value of a character from a string literal. +/// Extract the value of a character from a string literal. CharType is used to +/// determine the expected signedness of the result -- a string literal used to +/// initialize an array of 'signed char' or 'unsigned char' might contain chars +/// of the wrong signedness. static APSInt ExtractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit, - uint64_t Index) { + uint64_t Index, QualType CharType) { // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant const StringLiteral *S = dyn_cast(Lit); assert(S && "unexpected string literal expression kind"); + assert(CharType->isIntegerType() && "unexpected character type"); APSInt Value(S->getCharByteWidth() * Info.Ctx.getCharWidth(), - Lit->getType()->getArrayElementTypeNoTypeQual()->isUnsignedIntegerType()); + CharType->isUnsignedIntegerType()); if (Index < S->getLength()) Value = S->getCodeUnit(Index); return Value; @@ -1546,7 +1551,7 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E, assert(I == N - 1 && "extracting subobject of character?"); assert(!O->hasLValuePath() || O->getLValuePath().empty()); Obj = APValue(ExtractStringLiteralCharacter( - Info, O->getLValueBase().get(), Index)); + Info, O->getLValueBase().get(), Index, SubType)); return true; } else if (O->getArrayInitializedElts() > Index) O = &O->getArrayInitializedElt(Index); @@ -2868,6 +2873,7 @@ class LValueExprEvaluator bool VisitStringLiteral(const StringLiteral *E) { return Success(E); } bool VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { return Success(E); } bool VisitCXXTypeidExpr(const CXXTypeidExpr *E); + bool VisitCXXUuidofExpr(const CXXUuidofExpr *E); bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E); bool VisitUnaryDeref(const UnaryOperator *E); bool VisitUnaryReal(const UnaryOperator *E); @@ -2973,6 +2979,10 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { return Success(E); } +bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { + return Success(E); +} + bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) { // Handle static data members. if (const VarDecl *VD = dyn_cast(E->getMemberDecl())) { @@ -3849,8 +3859,7 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // C++11 [dcl.init.string]p1: A char array [...] can be initialized by [...] // an appropriately-typed string literal enclosed in braces. - if (E->getNumInits() == 1 && E->getInit(0)->isGLValue() && - Info.Ctx.hasSameUnqualifiedType(E->getType(), E->getInit(0)->getType())) { + if (E->isStringLiteralInit()) { LValue LV; if (!EvaluateLValue(E->getInit(0), LV, Info)) return false; @@ -5079,14 +5088,37 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } } + // The comparison here must be unsigned, and performed with the same + // width as the pointer. + unsigned PtrSize = Info.Ctx.getTypeSize(LHSTy); + uint64_t CompareLHS = LHSOffset.getQuantity(); + uint64_t CompareRHS = RHSOffset.getQuantity(); + assert(PtrSize <= 64 && "Unexpected pointer width"); + uint64_t Mask = ~0ULL >> (64 - PtrSize); + CompareLHS &= Mask; + CompareRHS &= Mask; + + // If there is a base and this is a relational operator, we can only + // compare pointers within the object in question; otherwise, the result + // depends on where the object is located in memory. + if (!LHSValue.Base.isNull() && E->isRelationalOp()) { + QualType BaseTy = getType(LHSValue.Base); + if (BaseTy->isIncompleteType()) + return Error(E); + CharUnits Size = Info.Ctx.getTypeSizeInChars(BaseTy); + uint64_t OffsetLimit = Size.getQuantity(); + if (CompareLHS > OffsetLimit || CompareRHS > OffsetLimit) + return Error(E); + } + switch (E->getOpcode()) { default: llvm_unreachable("missing comparison operator"); - case BO_LT: return Success(LHSOffset < RHSOffset, E); - case BO_GT: return Success(LHSOffset > RHSOffset, E); - case BO_LE: return Success(LHSOffset <= RHSOffset, E); - case BO_GE: return Success(LHSOffset >= RHSOffset, E); - case BO_EQ: return Success(LHSOffset == RHSOffset, E); - case BO_NE: return Success(LHSOffset != RHSOffset, E); + case BO_LT: return Success(CompareLHS < CompareRHS, E); + case BO_GT: return Success(CompareLHS > CompareRHS, E); + case BO_LE: return Success(CompareLHS <= CompareRHS, E); + case BO_GE: return Success(CompareLHS >= CompareRHS, E); + case BO_EQ: return Success(CompareLHS == CompareRHS, E); + case BO_NE: return Success(CompareLHS != CompareRHS, E); } } } diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp index fd616dbc9d2f..6b9fe26ccc94 100644 --- a/lib/AST/ExternalASTSource.cpp +++ b/lib/AST/ExternalASTSource.cpp @@ -49,7 +49,10 @@ ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC, return DeclContext::lookup_result(); } -ExternalLoadResult +void ExternalASTSource::completeVisibleDeclsMap(const DeclContext *DC) { +} + +ExternalLoadResult ExternalASTSource::FindExternalLexicalDecls(const DeclContext *DC, bool (*isKindWeWant)(Decl::Kind), SmallVectorImpl &Result) { diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index d7b635454011..0d405f1f57f2 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -2280,9 +2280,7 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T, } -/// Mangles a member expression. Implicit accesses are not handled, -/// but that should be okay, because you shouldn't be able to -/// make an implicit access in a function template declaration. +/// Mangles a member expression. void CXXNameMangler::mangleMemberExpr(const Expr *base, bool isArrow, NestedNameSpecifier *qualifier, @@ -2291,8 +2289,17 @@ void CXXNameMangler::mangleMemberExpr(const Expr *base, unsigned arity) { // ::= dt // ::= pt - Out << (isArrow ? "pt" : "dt"); - mangleExpression(base); + if (base) { + if (base->isImplicitCXXThis()) { + // Note: GCC mangles member expressions to the implicit 'this' as + // *this., whereas we represent them as this->. The Itanium C++ ABI + // does not specify anything here, so we follow GCC. + Out << "dtdefpT"; + } else { + Out << (isArrow ? "pt" : "dt"); + mangleExpression(base); + } + } mangleUnresolvedName(qualifier, firstQualifierLookup, member, arity); } @@ -2346,6 +2353,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { // ::= L E # integer literal // ::= L E # floating literal // ::= L E # external name + // ::= fpT # 'this' expression QualType ImplicitlyConvertedToType; recurse: @@ -2361,7 +2369,6 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { // These all can only appear in local or variable-initialization // contexts and so should never appear in a mangling. case Expr::AddrLabelExprClass: - case Expr::CXXThisExprClass: case Expr::DesignatedInitExprClass: case Expr::ImplicitValueInitExprClass: case Expr::ParenListExprClass: @@ -2919,6 +2926,10 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { mangleExpression(cast(E)->GetTemporaryExpr()); break; } + + case Expr::CXXThisExprClass: + Out << "fpT"; + break; } } diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 6af20df4beba..e4d9f0a1ef42 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -97,8 +97,8 @@ Stmt *Stmt::IgnoreImplicit() { /// \brief Strip off all label-like statements. /// -/// This will strip off label statements, case statements, and default -/// statements recursively. +/// This will strip off label statements, case statements, attributed +/// statements and default statements recursively. const Stmt *Stmt::stripLabelLikeStatements() const { const Stmt *S = this; while (true) { @@ -106,6 +106,8 @@ const Stmt *Stmt::stripLabelLikeStatements() const { S = LS->getSubStmt(); else if (const SwitchCase *SC = dyn_cast(S)) S = SC->getSubStmt(); + else if (const AttributedStmt *AS = dyn_cast(S)) + S = AS->getSubStmt(); else return S; } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 3a44183e2031..0d1066b7e322 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -169,6 +169,23 @@ void StmtPrinter::VisitLabelStmt(LabelStmt *Node) { PrintStmt(Node->getSubStmt(), 0); } +void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) { + OS << "[["; + bool first = true; + for (AttrVec::const_iterator it = Node->getAttrs().begin(), + end = Node->getAttrs().end(); + it != end; ++it) { + if (!first) { + OS << ", "; + first = false; + } + // TODO: check this + (*it)->printPretty(OS, Context); + } + OS << "]] "; + PrintStmt(Node->getSubStmt(), 0); +} + void StmtPrinter::PrintRawIfStmt(IfStmt *If) { OS << "if ("; PrintExpr(If->getCond()); diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index e5526cea74af..e50523ae860b 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -109,6 +109,11 @@ void StmtProfiler::VisitLabelStmt(const LabelStmt *S) { VisitDecl(S->getDecl()); } +void StmtProfiler::VisitAttributedStmt(const AttributedStmt *S) { + VisitStmt(S); + // TODO: maybe visit attributes? +} + void StmtProfiler::VisitIfStmt(const IfStmt *S) { VisitStmt(S); VisitDecl(S->getConditionVariable()); @@ -758,6 +763,7 @@ void StmtProfiler::VisitCXXUuidofExpr(const CXXUuidofExpr *S) { void StmtProfiler::VisitCXXThisExpr(const CXXThisExpr *S) { VisitExpr(S); + ID.AddBoolean(S->isImplicit()); } void StmtProfiler::VisitCXXThrowExpr(const CXXThrowExpr *S) { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index c82aeaadd492..3f6a09457d1e 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1546,6 +1546,14 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args, else if (epi.NoexceptExpr->isInstantiationDependent()) setInstantiationDependent(); } + } else if (getExceptionSpecType() == EST_Uninstantiated) { + // Store the function decl from which we will resolve our + // exception specification. + FunctionDecl **slot = reinterpret_cast(argSlot + numArgs); + slot[0] = epi.ExceptionSpecDecl; + slot[1] = epi.ExceptionSpecTemplate; + // This exception specification doesn't make the type dependent, because + // it's not instantiated as part of instantiating the type. } if (epi.ConsumedArguments) { @@ -1629,6 +1637,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr()); } else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){ epi.NoexceptExpr->Profile(ID, Context, false); + } else if (epi.ExceptionSpecType == EST_Uninstantiated) { + ID.AddPointer(epi.ExceptionSpecDecl->getCanonicalDecl()); } if (epi.ConsumedArguments) { for (unsigned i = 0; i != NumArgs; ++i) diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp index 7a459726493c..107d9fb78c50 100644 --- a/lib/AST/VTableBuilder.cpp +++ b/lib/AST/VTableBuilder.cpp @@ -2157,13 +2157,12 @@ VTableLayout::VTableLayout(uint64_t NumVTableComponents, VTableThunks(new VTableThunkTy[NumVTableThunks]), AddressPoints(AddressPoints) { std::copy(VTableComponents, VTableComponents+NumVTableComponents, - this->VTableComponents); - std::copy(VTableThunks, VTableThunks+NumVTableThunks, this->VTableThunks); + this->VTableComponents.get()); + std::copy(VTableThunks, VTableThunks+NumVTableThunks, + this->VTableThunks.get()); } -VTableLayout::~VTableLayout() { - delete[] VTableComponents; -} +VTableLayout::~VTableLayout() { } VTableContext::~VTableContext() { llvm::DeleteContainerSeconds(VTableLayouts); diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index d1334a543191..2f1f1cb4e4da 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -18,6 +18,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/CharUnits.h" +#include "clang/Basic/AttrKinds.h" #include "llvm/Support/GraphWriter.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Format.h" @@ -1069,6 +1070,9 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { case Stmt::LambdaExprClass: return VisitLambdaExpr(cast(S), asc); + case Stmt::AttributedStmtClass: + return Visit(cast(S)->getSubStmt(), asc); + case Stmt::MemberExprClass: return VisitMemberExpr(cast(S), asc); @@ -1131,7 +1135,7 @@ CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) { /// VisitChildren - Visit the children of a Stmt. CFGBlock *CFGBuilder::VisitChildren(Stmt *Terminator) { - CFGBlock *lastBlock = Block; + CFGBlock *lastBlock = Block; for (Stmt::child_range I = Terminator->children(); I; ++I) if (Stmt *child = *I) if (CFGBlock *b = Visit(child)) @@ -1280,7 +1284,8 @@ static bool CanThrow(Expr *E, ASTContext &Ctx) { const FunctionType *FT = Ty->getAs(); if (FT) { if (const FunctionProtoType *Proto = dyn_cast(FT)) - if (Proto->isNothrow(Ctx)) + if (Proto->getExceptionSpecType() != EST_Uninstantiated && + Proto->isNothrow(Ctx)) return false; } return true; diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 43c3ffbaf1ea..ca2392b91588 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_USED_LIBS clangBasic clangAST clangIndex) +set(LLVM_USED_LIBS clangBasic clangAST) add_clang_library(clangAnalysis AnalysisDeclContext.cpp diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index f938b5a6045d..8c49486b0dc3 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -58,6 +58,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { Char32Type = UnsignedInt; Int64Type = SignedLongLong; SigAtomicType = SignedInt; + UseSignedCharForObjCBool = true; UseBitFieldTypeAlignment = true; UseZeroLengthBitfieldAlignment = false; ZeroLengthBitfieldBoundary = 0; diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 1ad37c4e5726..dd2a89a18b72 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -365,7 +365,7 @@ class OpenBSDTargetInfo : public OSTargetInfo { DefineStd(Builder, "unix", Opts); Builder.defineMacro("__ELF__"); if (Opts.POSIXThreads) - Builder.defineMacro("_POSIX_THREADS"); + Builder.defineMacro("_REENTRANT"); } public: OpenBSDTargetInfo(const std::string &triple) @@ -3546,7 +3546,10 @@ class MipsTargetInfoBase : public TargetInfo { virtual bool setFeatureEnabled(llvm::StringMap &Features, StringRef Name, bool Enabled) const { - if (Name == "soft-float" || Name == "single-float") { + if (Name == "soft-float" || Name == "single-float" || + Name == "o32" || Name == "n32" || Name == "n64" || Name == "eabi" || + Name == "mips32" || Name == "mips32r2" || + Name == "mips64" || Name == "mips64r2") { Features[Name] = Enabled; return true; } diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index 331024f9f200..8cb238632b78 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -32,7 +32,7 @@ std::string getClangRepositoryPath() { // If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us // pick up a tag in an SVN export, for example. - static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $"); + static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/branches/release_31/lib/Basic/Version.cpp $"); if (URL.empty()) { URL = SVNRepository.slice(SVNRepository.find(':'), SVNRepository.find("/lib/Basic")); diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 7af01ece6b7b..dfb9d61ff539 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -14,5 +14,4 @@ add_subdirectory(Serialization) add_subdirectory(Frontend) add_subdirectory(FrontendTool) add_subdirectory(Tooling) -add_subdirectory(Index) add_subdirectory(StaticAnalyzer) diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 27bb4ef5d1af..f8c7bcd4d7bc 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -491,6 +491,8 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, /// a full-expression so that the block's cleanups are pushed at the /// right place in the stack. static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) { + assert(CGF.HaveInsertPoint()); + // Allocate the block info and place it at the head of the list. CGBlockInfo &blockInfo = *new CGBlockInfo(block, CGF.CurFn->getName()); diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 4455f1a0865b..82ee4fc1ee36 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -419,16 +419,37 @@ void CodeGenTypes::GetExpandedTypes(QualType type, uint64_t NumElts = AT->getSize().getZExtValue(); for (uint64_t Elt = 0; Elt < NumElts; ++Elt) GetExpandedTypes(AT->getElementType(), expandedTypes); - } else if (const RecordType *RT = type->getAsStructureType()) { + } else if (const RecordType *RT = type->getAs()) { const RecordDecl *RD = RT->getDecl(); 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() && - "Cannot expand structure with bit-field members."); - GetExpandedTypes(FD->getType(), expandedTypes); + if (RD->isUnion()) { + // Unions can be here only in degenerative cases - all the fields are same + // after flattening. Thus we have to use the "largest" field. + const FieldDecl *LargestFD = 0; + CharUnits UnionSize = CharUnits::Zero(); + + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + const FieldDecl *FD = *i; + assert(!FD->isBitField() && + "Cannot expand structure with bit-field members."); + CharUnits FieldSize = getContext().getTypeSizeInChars(FD->getType()); + if (UnionSize < FieldSize) { + UnionSize = FieldSize; + LargestFD = FD; + } + } + if (LargestFD) + GetExpandedTypes(LargestFD->getType(), expandedTypes); + } else { + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + const FieldDecl *FD = *i; + assert(!FD->isBitField() && + "Cannot expand structure with bit-field members."); + GetExpandedTypes(FD->getType(), expandedTypes); + } } } else if (const ComplexType *CT = type->getAs()) { llvm::Type *EltTy = ConvertType(CT->getElementType()); @@ -443,32 +464,55 @@ CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV, llvm::Function::arg_iterator AI) { assert(LV.isSimple() && "Unexpected non-simple lvalue during struct expansion."); - llvm::Value *Addr = LV.getAddress(); if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) { unsigned NumElts = AT->getSize().getZExtValue(); QualType EltTy = AT->getElementType(); for (unsigned Elt = 0; Elt < NumElts; ++Elt) { - llvm::Value *EltAddr = Builder.CreateConstGEP2_32(Addr, 0, Elt); + llvm::Value *EltAddr = Builder.CreateConstGEP2_32(LV.getAddress(), 0, Elt); LValue LV = MakeAddrLValue(EltAddr, EltTy); AI = ExpandTypeFromArgs(EltTy, LV, AI); } - } else if (const RecordType *RT = Ty->getAsStructureType()) { + } else if (const RecordType *RT = Ty->getAs()) { RecordDecl *RD = RT->getDecl(); - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i) { - FieldDecl *FD = *i; - QualType FT = FD->getType(); + if (RD->isUnion()) { + // Unions can be here only in degenerative cases - all the fields are same + // after flattening. Thus we have to use the "largest" field. + const FieldDecl *LargestFD = 0; + CharUnits UnionSize = CharUnits::Zero(); - // FIXME: What are the right qualifiers here? - LValue LV = EmitLValueForField(Addr, FD, 0); - AI = ExpandTypeFromArgs(FT, LV, AI); + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + const FieldDecl *FD = *i; + assert(!FD->isBitField() && + "Cannot expand structure with bit-field members."); + CharUnits FieldSize = getContext().getTypeSizeInChars(FD->getType()); + if (UnionSize < FieldSize) { + UnionSize = FieldSize; + LargestFD = FD; + } + } + if (LargestFD) { + // FIXME: What are the right qualifiers here? + LValue SubLV = EmitLValueForField(LV, LargestFD); + AI = ExpandTypeFromArgs(LargestFD->getType(), SubLV, AI); + } + } else { + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + FieldDecl *FD = *i; + QualType FT = FD->getType(); + + // FIXME: What are the right qualifiers here? + LValue SubLV = EmitLValueForField(LV, FD); + AI = ExpandTypeFromArgs(FT, SubLV, AI); + } } } else if (const ComplexType *CT = Ty->getAs()) { QualType EltTy = CT->getElementType(); - llvm::Value *RealAddr = Builder.CreateStructGEP(Addr, 0, "real"); + llvm::Value *RealAddr = Builder.CreateStructGEP(LV.getAddress(), 0, "real"); EmitStoreThroughLValue(RValue::get(AI++), MakeAddrLValue(RealAddr, EltTy)); - llvm::Value *ImagAddr = Builder.CreateStructGEP(Addr, 1, "imag"); + llvm::Value *ImagAddr = Builder.CreateStructGEP(LV.getAddress(), 1, "imag"); EmitStoreThroughLValue(RValue::get(AI++), MakeAddrLValue(ImagAddr, EltTy)); } else { EmitStoreThroughLValue(RValue::get(AI), LV); @@ -1760,26 +1804,38 @@ void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV, EltRV = EmitLoadOfLValue(LV); ExpandTypeToArgs(EltTy, EltRV, Args, IRFuncTy); } - } else if (const RecordType *RT = Ty->getAsStructureType()) { + } else if (const RecordType *RT = Ty->getAs()) { RecordDecl *RD = RT->getDecl(); assert(RV.isAggregate() && "Unexpected rvalue during struct expansion"); - llvm::Value *Addr = RV.getAggregateAddr(); - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i) { - FieldDecl *FD = *i; - QualType FT = FD->getType(); - - // FIXME: What are the right qualifiers here? - LValue LV = EmitLValueForField(Addr, FD, 0); - RValue FldRV; - if (FT->isAnyComplexType()) - // FIXME: Volatile? - FldRV = RValue::getComplex(LoadComplexFromAddr(LV.getAddress(), false)); - else if (CodeGenFunction::hasAggregateLLVMType(FT)) - FldRV = LV.asAggregateRValue(); - else - FldRV = EmitLoadOfLValue(LV); - ExpandTypeToArgs(FT, FldRV, Args, IRFuncTy); + LValue LV = MakeAddrLValue(RV.getAggregateAddr(), Ty); + + if (RD->isUnion()) { + const FieldDecl *LargestFD = 0; + CharUnits UnionSize = CharUnits::Zero(); + + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + const FieldDecl *FD = *i; + assert(!FD->isBitField() && + "Cannot expand structure with bit-field members."); + CharUnits FieldSize = getContext().getTypeSizeInChars(FD->getType()); + if (UnionSize < FieldSize) { + UnionSize = FieldSize; + LargestFD = FD; + } + } + if (LargestFD) { + RValue FldRV = EmitRValueForField(LV, LargestFD); + ExpandTypeToArgs(LargestFD->getType(), FldRV, Args, IRFuncTy); + } + } else { + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + FieldDecl *FD = *i; + + RValue FldRV = EmitRValueForField(LV, FD); + ExpandTypeToArgs(FD->getType(), FldRV, Args, IRFuncTy); + } } } else if (Ty->isAnyComplexType()) { ComplexPairTy CV = RV.getComplexVal(); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 6303e2069d58..2aedf95e6a11 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -555,15 +555,17 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, QualType FieldType = Field->getType(); llvm::Value *ThisPtr = CGF.LoadCXXThis(); + QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl); LValue LHS; - + // If we are initializing an anonymous union field, drill down to the field. if (MemberInit->isIndirectMemberInitializer()) { LHS = CGF.EmitLValueForAnonRecordField(ThisPtr, MemberInit->getIndirectMember(), 0); FieldType = MemberInit->getIndirectMember()->getAnonField()->getType(); } else { - LHS = CGF.EmitLValueForFieldInitialization(ThisPtr, Field, 0); + LValue ThisLHSLV = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy); + LHS = CGF.EmitLValueForFieldInitialization(ThisLHSLV, Field); } // Special case: if we are in a copy or move constructor, and we are copying @@ -585,7 +587,8 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, unsigned SrcArgIndex = Args.size() - 1; llvm::Value *SrcPtr = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(Args[SrcArgIndex])); - LValue Src = CGF.EmitLValueForFieldInitialization(SrcPtr, Field, 0); + LValue ThisRHSLV = CGF.MakeNaturalAlignAddrLValue(SrcPtr, RecordTy); + LValue Src = CGF.EmitLValueForFieldInitialization(ThisRHSLV, Field); // Copy the aggregate. CGF.EmitAggregateCopy(LHS.getAddress(), Src.getAddress(), FieldType, @@ -978,7 +981,9 @@ namespace { void Emit(CodeGenFunction &CGF, Flags flags) { // Find the address of the field. llvm::Value *thisValue = CGF.LoadCXXThis(); - LValue LV = CGF.EmitLValueForField(thisValue, field, /*CVRQualifiers=*/0); + QualType RecordTy = CGF.getContext().getTagDeclType(field->getParent()); + LValue ThisLV = CGF.MakeAddrLValue(thisValue, RecordTy); + LValue LV = CGF.EmitLValueForField(ThisLV, field); assert(LV.isSimple()); CGF.emitDestroy(LV.getAddress(), field->getType(), destroyer, diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 7301d2060ba4..d286d24715eb 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -184,7 +184,6 @@ CGDebugInfo::getClassName(const RecordDecl *RD) { const TemplateArgument *Args; unsigned NumArgs; - std::string Buffer; if (TypeSourceInfo *TAW = Spec->getTypeAsWritten()) { const TemplateSpecializationType *TST = cast(TAW->getType()); @@ -195,16 +194,17 @@ CGDebugInfo::getClassName(const RecordDecl *RD) { Args = TemplateArgs.data(); NumArgs = TemplateArgs.size(); } - Buffer = RD->getIdentifier()->getNameStart(); + StringRef Name = RD->getIdentifier()->getName(); PrintingPolicy Policy(CGM.getLangOpts()); - Buffer += TemplateSpecializationType::PrintTemplateArgumentList(Args, - NumArgs, - Policy); + std::string TemplateArgList = + TemplateSpecializationType::PrintTemplateArgumentList(Args, NumArgs, Policy); // Copy this name on the side and use its reference. - char *StrPtr = DebugInfoNames.Allocate(Buffer.length()); - memcpy(StrPtr, Buffer.data(), Buffer.length()); - return StringRef(StrPtr, Buffer.length()); + size_t Length = Name.size() + TemplateArgList.size(); + char *StrPtr = DebugInfoNames.Allocate(Length); + memcpy(StrPtr, Name.data(), Name.size()); + memcpy(StrPtr + Name.size(), TemplateArgList.data(), TemplateArgList.size()); + return StringRef(StrPtr, Length); } /// getOrCreateFile - Get the file debug info descriptor for the input location. diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 8c154f070845..644777963b21 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -1171,6 +1171,10 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) { // If this was emitted as a global constant, we're done. if (emission.wasEmittedAsGlobal()) return; + // If we don't have an insertion point, we're done. Sema prevents + // us from jumping into any of these scopes anyway. + if (!HaveInsertPoint()) return; + const VarDecl &D = *emission.Variable; // Check the type for a cleanup. diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 08970fd73865..5f2b1f055dba 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -24,6 +24,7 @@ #include "clang/Frontend/CodeGenOptions.h" #include "llvm/Intrinsics.h" #include "llvm/LLVMContext.h" +#include "llvm/Support/MDBuilder.h" #include "llvm/Target/TargetData.h" using namespace clang; using namespace CodeGen; @@ -398,8 +399,8 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, break; case SubobjectAdjustment::FieldAdjustment: { - LValue LV = - CGF.EmitLValueForField(Object, Adjustment.Field, 0); + LValue LV = CGF.MakeAddrLValue(Object, E->getType()); + LV = CGF.EmitLValueForField(LV, Adjustment.Field); if (LV.isSimple()) { Object = LV.getAddress(); break; @@ -908,16 +909,8 @@ llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) { } } - if (End == Min) - return NULL; - - llvm::Value *LowAndHigh[2]; - LowAndHigh[0] = llvm::ConstantInt::get(LTy, Min); - LowAndHigh[1] = llvm::ConstantInt::get(LTy, End); - - llvm::LLVMContext &C = getLLVMContext(); - llvm::MDNode *Range = llvm::MDNode::get(C, LowAndHigh); - return Range; + llvm::MDBuilder MDHelper(getLLVMContext()); + return MDHelper.createRange(Min, End); } llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile, @@ -1577,8 +1570,12 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { // Use special handling for lambdas. if (!V) { - if (FieldDecl *FD = LambdaCaptureFields.lookup(VD)) - return EmitLValueForField(CXXABIThisValue, FD, 0); + if (FieldDecl *FD = LambdaCaptureFields.lookup(VD)) { + QualType LambdaTagType = getContext().getTagDeclType(FD->getParent()); + LValue LambdaLV = MakeNaturalAlignAddrLValue(CXXABIThisValue, + LambdaTagType); + return EmitLValueForField(LambdaLV, FD); + } assert(isa(CurCodeDecl) && E->refersToEnclosingLocal()); CharUnits alignment = getContext().getDeclAlign(VD); @@ -1973,32 +1970,19 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { } LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { - bool isNonGC = false; Expr *BaseExpr = E->getBase(); - llvm::Value *BaseValue = NULL; - 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()->getAs(); - BaseQuals = PTy->getPointeeType().getQualifiers(); - } else { - LValue BaseLV = EmitLValue(BaseExpr); - if (BaseLV.isNonGC()) - isNonGC = true; - // FIXME: this isn't right for bitfields. - BaseValue = BaseLV.getAddress(); - QualType BaseTy = BaseExpr->getType(); - BaseQuals = BaseTy.getQualifiers(); - } + LValue BaseLV; + if (E->isArrow()) + BaseLV = MakeNaturalAlignAddrLValue(EmitScalarExpr(BaseExpr), + BaseExpr->getType()->getPointeeType()); + else + BaseLV = EmitLValue(BaseExpr); NamedDecl *ND = E->getMemberDecl(); if (FieldDecl *Field = dyn_cast(ND)) { - LValue LV = EmitLValueForField(BaseValue, Field, - BaseQuals.getCVRQualifiers()); - LV.setNonGC(isNonGC); + LValue LV = EmitLValueForField(BaseLV, Field); setObjCGCLValueClass(getContext(), E, LV); return LV; } @@ -2032,8 +2016,10 @@ LValue CodeGenFunction::EmitLValueForAnonRecordField(llvm::Value *BaseValue, IndirectFieldDecl::chain_iterator I = Field->chain_begin(), IEnd = Field->chain_end(); while (true) { - LValue LV = EmitLValueForField(BaseValue, cast(*I), - CVRQualifiers); + QualType RecordTy = + getContext().getTypeDeclType(cast(*I)->getParent()); + LValue LV = EmitLValueForField(MakeAddrLValue(BaseValue, RecordTy), + cast(*I)); if (++I == IEnd) return LV; assert(LV.isSimple()); @@ -2042,19 +2028,25 @@ LValue CodeGenFunction::EmitLValueForAnonRecordField(llvm::Value *BaseValue, } } -LValue CodeGenFunction::EmitLValueForField(llvm::Value *baseAddr, - const FieldDecl *field, - unsigned cvr) { +LValue CodeGenFunction::EmitLValueForField(LValue base, + const FieldDecl *field) { if (field->isBitField()) - return EmitLValueForBitfield(baseAddr, field, cvr); + return EmitLValueForBitfield(base.getAddress(), field, + base.getVRQualifiers()); const RecordDecl *rec = field->getParent(); QualType type = field->getType(); CharUnits alignment = getContext().getDeclAlign(field); + // FIXME: It should be impossible to have an LValue without alignment for a + // complete type. + if (!base.getAlignment().isZero()) + alignment = std::min(alignment, base.getAlignment()); + bool mayAlias = rec->hasAttr(); - llvm::Value *addr = baseAddr; + llvm::Value *addr = base.getAddress(); + unsigned cvr = base.getVRQualifiers(); if (rec->isUnion()) { // For unions, there is no pointer adjustment. assert(!type->isReferenceType() && "union has reference member"); @@ -2117,30 +2109,33 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value *baseAddr, } LValue -CodeGenFunction::EmitLValueForFieldInitialization(llvm::Value *BaseValue, - const FieldDecl *Field, - unsigned CVRQualifiers) { +CodeGenFunction::EmitLValueForFieldInitialization(LValue Base, + const FieldDecl *Field) { QualType FieldType = Field->getType(); if (!FieldType->isReferenceType()) - return EmitLValueForField(BaseValue, Field, CVRQualifiers); + return EmitLValueForField(Base, Field); const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(Field->getParent()); unsigned idx = RL.getLLVMFieldNo(Field); - llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx); + llvm::Value *V = Builder.CreateStructGEP(Base.getAddress(), idx); assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs"); - // Make sure that the address is pointing to the right type. This is critical // for both unions and structs. A union needs a bitcast, a struct element // will need a bitcast if the LLVM type laid out doesn't match the desired // type. llvm::Type *llvmType = ConvertTypeForMem(FieldType); - unsigned AS = cast(V->getType())->getAddressSpace(); - V = Builder.CreateBitCast(V, llvmType->getPointerTo(AS)); - + V = EmitBitCastOfLValueToProperType(*this, V, llvmType, Field->getName()); + CharUnits Alignment = getContext().getDeclAlign(Field); + + // FIXME: It should be impossible to have an LValue without alignment for a + // complete type. + if (!Base.getAlignment().isZero()) + Alignment = std::min(Alignment, Base.getAlignment()); + return MakeAddrLValue(V, FieldType, Alignment); } @@ -2378,6 +2373,19 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr( return MakeAddrLValue(RV.getScalarVal(), E->getType()); } +RValue CodeGenFunction::EmitRValueForField(LValue LV, + const FieldDecl *FD) { + QualType FT = FD->getType(); + LValue FieldLV = EmitLValueForField(LV, FD); + if (FT->isAnyComplexType()) + return RValue::getComplex( + LoadComplexFromAddr(FieldLV.getAddress(), + FieldLV.isVolatileQualified())); + else if (CodeGenFunction::hasAggregateLLVMType(FT)) + return FieldLV.asAggregateRValue(); + + return EmitLoadOfLValue(FieldLV); +} //===--------------------------------------------------------------------===// // Expression Emission @@ -3158,11 +3166,10 @@ void CodeGenFunction::SetFPAccuracy(llvm::Value *Val, float Accuracy) { if (Accuracy == 0.0 || !isa(Val)) return; - llvm::Value *ULPs = llvm::ConstantFP::get(Builder.getFloatTy(), Accuracy); - llvm::MDNode *Node = llvm::MDNode::get(getLLVMContext(), ULPs); + llvm::MDBuilder MDHelper(getLLVMContext()); + llvm::MDNode *Node = MDHelper.createFPMath(Accuracy); - cast(Val)->setMetadata(llvm::LLVMContext::MD_fpaccuracy, - Node); + cast(Val)->setMetadata(llvm::LLVMContext::MD_fpmath, Node); } namespace { diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index b6efc1cafaaa..7b0e0f5157cf 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -238,7 +238,10 @@ void AggExprEmitter::EmitMoveFromReturnSlot(const Expr *E, RValue Src) { // Otherwise, do a final copy, assert(Dest.getAddr() != Src.getAggregateAddr()); - EmitFinalDestCopy(E, Src, /*Ignore*/ true); + std::pair TypeInfo = + CGF.getContext().getTypeInfoInChars(E->getType()); + CharUnits Alignment = std::min(TypeInfo.second, Dest.getAlignment()); + EmitFinalDestCopy(E, Src, /*Ignore*/ true, Alignment.getQuantity()); } /// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired. @@ -348,7 +351,8 @@ void AggExprEmitter::EmitStdInitializerList(llvm::Value *destPtr, CGF.ErrorUnsupported(initList, "weird std::initializer_list"); return; } - LValue start = CGF.EmitLValueForFieldInitialization(destPtr, *field, 0); + LValue DestLV = CGF.MakeNaturalAlignAddrLValue(destPtr, initList->getType()); + LValue start = CGF.EmitLValueForFieldInitialization(DestLV, *field); llvm::Value *arrayStart = Builder.CreateStructGEP(alloc, 0, "arraystart"); CGF.EmitStoreThroughLValue(RValue::get(arrayStart), start); ++field; @@ -357,7 +361,7 @@ void AggExprEmitter::EmitStdInitializerList(llvm::Value *destPtr, CGF.ErrorUnsupported(initList, "weird std::initializer_list"); return; } - LValue endOrLength = CGF.EmitLValueForFieldInitialization(destPtr, *field, 0); + LValue endOrLength = CGF.EmitLValueForFieldInitialization(DestLV, *field); if (ctx.hasSameType(field->getType(), elementPtr)) { // End pointer. llvm::Value *arrayEnd = Builder.CreateStructGEP(alloc,numInits, "arrayend"); @@ -912,28 +916,24 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { return; } - llvm::Value *DestPtr = EnsureSlot(E->getType()).getAddr(); + AggValueSlot Dest = EnsureSlot(E->getType()); + LValue DestLV = CGF.MakeAddrLValue(Dest.getAddr(), E->getType(), + Dest.getAlignment()); // Handle initialization of an array. if (E->getType()->isArrayType()) { - if (E->getNumInits() > 0) { - QualType T1 = E->getType(); - QualType T2 = E->getInit(0)->getType(); - if (CGF.getContext().hasSameUnqualifiedType(T1, T2)) { - EmitAggLoadOfLValue(E->getInit(0)); - return; - } - } + if (E->isStringLiteralInit()) + return Visit(E->getInit(0)); QualType elementType = CGF.getContext().getAsArrayType(E->getType())->getElementType(); llvm::PointerType *APType = - cast(DestPtr->getType()); + cast(Dest.getAddr()->getType()); llvm::ArrayType *AType = cast(APType->getElementType()); - EmitArrayInit(DestPtr, AType, elementType, E); + EmitArrayInit(Dest.getAddr(), AType, elementType, E); return; } @@ -966,7 +966,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { // FIXME: volatility FieldDecl *Field = E->getInitializedFieldInUnion(); - LValue FieldLoc = CGF.EmitLValueForFieldInitialization(DestPtr, Field, 0); + LValue FieldLoc = CGF.EmitLValueForFieldInitialization(DestLV, Field); if (NumInitElements) { // Store the initializer into the field EmitInitializationToLValue(E->getInit(0), FieldLoc); @@ -1004,8 +1004,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { CGF.getTypes().isZeroInitializable(E->getType())) break; - // FIXME: volatility - LValue LV = CGF.EmitLValueForFieldInitialization(DestPtr, *field, 0); + + LValue LV = CGF.EmitLValueForFieldInitialization(DestLV, *field); // We never generate write-barries for initialized fields. LV.setNonGC(true); diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index d3ba77074700..c69c8830c1e8 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -1815,13 +1815,16 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *Value, void CodeGenFunction::EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Slot) { RunCleanupsScope Scope(*this); + LValue SlotLV = MakeAddrLValue(Slot.getAddr(), E->getType(), + Slot.getAlignment()); CXXRecordDecl::field_iterator CurField = E->getLambdaClass()->field_begin(); for (LambdaExpr::capture_init_iterator i = E->capture_init_begin(), e = E->capture_init_end(); i != e; ++i, ++CurField) { // Emit initialization - LValue LV = EmitLValueForFieldInitialization(Slot.getAddr(), *CurField, 0); + + LValue LV = EmitLValueForFieldInitialization(SlotLV, *CurField); ArrayRef ArrayIndexes; if (CurField->getType()->isArrayType()) ArrayIndexes = E->getCaptureInitIndexVars(i); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index d528e0c4b72a..bc9f9ef07b28 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -758,17 +758,13 @@ class ConstExprEmitter : } llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) { - unsigned NumInitElements = ILE->getNumInits(); - if (NumInitElements == 1 && - CGM.getContext().hasSameUnqualifiedType(ILE->getType(), - ILE->getInit(0)->getType()) && - (isa(ILE->getInit(0)) || - isa(ILE->getInit(0)))) + if (ILE->isStringLiteralInit()) return Visit(ILE->getInit(0)); llvm::ArrayType *AType = cast(ConvertType(ILE->getType())); llvm::Type *ElemTy = AType->getElementType(); + unsigned NumInitElements = ILE->getNumInits(); unsigned NumElements = AType->getNumElements(); // Initialising an array requires us to automatically diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index bf42dcb8e21d..a1d078957302 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -79,6 +79,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { case Stmt::CompoundStmtClass: case Stmt::DeclStmtClass: case Stmt::LabelStmtClass: + case Stmt::AttributedStmtClass: case Stmt::GotoStmtClass: case Stmt::BreakStmtClass: case Stmt::ContinueStmtClass: @@ -173,6 +174,8 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S) { case Stmt::CompoundStmtClass: EmitCompoundStmt(cast(*S)); break; case Stmt::DeclStmtClass: EmitDeclStmt(cast(*S)); break; case Stmt::LabelStmtClass: EmitLabelStmt(cast(*S)); break; + case Stmt::AttributedStmtClass: + EmitAttributedStmt(cast(*S)); break; case Stmt::GotoStmtClass: EmitGotoStmt(cast(*S)); break; case Stmt::BreakStmtClass: EmitBreakStmt(cast(*S)); break; case Stmt::ContinueStmtClass: EmitContinueStmt(cast(*S)); break; @@ -332,6 +335,10 @@ void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) { EmitStmt(S.getSubStmt()); } +void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) { + EmitStmt(S.getSubStmt()); +} + void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) { // If this code is reachable then emit a stop point (if generating // debug info). We have to do this ourselves because we are on the diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 06e90b664858..2939062c9bbb 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -22,8 +22,9 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/Frontend/CodeGenOptions.h" -#include "llvm/Target/TargetData.h" #include "llvm/Intrinsics.h" +#include "llvm/Support/MDBuilder.h" +#include "llvm/Target/TargetData.h" using namespace clang; using namespace CodeGen; @@ -362,8 +363,12 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, LambdaThisCaptureField); if (LambdaThisCaptureField) { // If this lambda captures this, load it. - LValue ThisLValue = EmitLValueForField(CXXABIThisValue, - LambdaThisCaptureField, 0); + QualType LambdaTagType = + getContext().getTagDeclType(LambdaThisCaptureField->getParent()); + LValue LambdaLV = MakeNaturalAlignAddrLValue(CXXABIThisValue, + LambdaTagType); + LValue ThisLValue = EmitLValueForField(LambdaLV, + LambdaThisCaptureField); CXXThisValue = EmitLoadOfLValue(ThisLValue).getScalarVal(); } } else { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 3e0cd146256f..83f1e2df9f45 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1948,6 +1948,7 @@ class CodeGenFunction : public CodeGenTypeCache { void EmitLabel(const LabelDecl *D); // helper for EmitLabelStmt. void EmitLabelStmt(const LabelStmt &S); + void EmitAttributedStmt(const AttributedStmt &S); void EmitGotoStmt(const GotoStmt &S); void EmitIndirectGotoStmt(const IndirectGotoStmt &S); void EmitIfStmt(const IfStmt &S); @@ -2104,6 +2105,8 @@ class CodeGenFunction : public CodeGenTypeCache { LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E); LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e); + RValue EmitRValueForField(LValue LV, const FieldDecl *FD); + class ConstantEmission { llvm::PointerIntPair ValueAndIsReference; ConstantEmission(llvm::Constant *C, bool isReference) @@ -2143,15 +2146,13 @@ class CodeGenFunction : public CodeGenTypeCache { LValue EmitLValueForAnonRecordField(llvm::Value* Base, const IndirectFieldDecl* Field, unsigned CVRQualifiers); - LValue EmitLValueForField(llvm::Value* Base, const FieldDecl* Field, - unsigned CVRQualifiers); + LValue EmitLValueForField(LValue Base, const FieldDecl* Field); /// EmitLValueForFieldInitialization - Like EmitLValueForField, except that /// if the Field is a reference, this will return the address of the reference /// and not the address of the value stored in the reference. - LValue EmitLValueForFieldInitialization(llvm::Value* Base, - const FieldDecl* Field, - unsigned CVRQualifiers); + LValue EmitLValueForFieldInitialization(LValue Base, + const FieldDecl* Field); LValue EmitLValueForIvar(QualType ObjectTy, llvm::Value* Base, const ObjCIvarDecl *Ivar, diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index c0ccf4de4c9f..9a55c0848006 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1241,7 +1241,7 @@ CodeGenModule::CreateOrReplaceCXXRuntimeVariable(StringRef Name, /// GetAddrOfGlobalVar - Return the llvm::Constant for the address of the /// given global variable. If Ty is non-null and if the global doesn't exist, -/// then it will be greated with the specified type instead of whatever the +/// then it will be created with the specified type instead of whatever the /// normal requested type would be. llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D, llvm::Type *Ty) { diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp index 9ee3f1d2e67c..a3cadcf39248 100644 --- a/lib/CodeGen/CodeGenTBAA.cpp +++ b/lib/CodeGen/CodeGenTBAA.cpp @@ -28,7 +28,7 @@ using namespace CodeGen; CodeGenTBAA::CodeGenTBAA(ASTContext &Ctx, llvm::LLVMContext& VMContext, const LangOptions &Features, MangleContext &MContext) : Context(Ctx), VMContext(VMContext), Features(Features), MContext(MContext), - Root(0), Char(0) { + MDHelper(VMContext), Root(0), Char(0) { } CodeGenTBAA::~CodeGenTBAA() { @@ -40,7 +40,7 @@ llvm::MDNode *CodeGenTBAA::getRoot() { // (or a different version of this front-end), their TBAA trees will // remain distinct, and the optimizer will treat them conservatively. if (!Root) - Root = getTBAAInfoForNamedType("Simple C/C++ TBAA", 0); + Root = MDHelper.createTBAARoot("Simple C/C++ TBAA"); return Root; } @@ -51,33 +51,11 @@ llvm::MDNode *CodeGenTBAA::getChar() { // these special powers only cover user-accessible memory, and doesn't // include things like vtables. if (!Char) - Char = getTBAAInfoForNamedType("omnipotent char", getRoot()); + Char = MDHelper.createTBAANode("omnipotent char", getRoot()); return Char; } -/// getTBAAInfoForNamedType - Create a TBAA tree node with the given string -/// as its identifier, and the given Parent node as its tree parent. -llvm::MDNode *CodeGenTBAA::getTBAAInfoForNamedType(StringRef NameStr, - llvm::MDNode *Parent, - bool Readonly) { - // Currently there is only one flag defined - the readonly flag. - llvm::Value *Flags = 0; - if (Readonly) - Flags = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), true); - - // Set up the mdnode operand list. - llvm::Value *Ops[] = { - llvm::MDString::get(VMContext, NameStr), - Parent, - Flags - }; - - // Create the mdnode. - unsigned Len = llvm::array_lengthof(Ops) - !Flags; - return llvm::MDNode::get(VMContext, llvm::makeArrayRef(Ops, Len)); -} - static bool TypeHasMayAlias(QualType QTy) { // Tagged types have declarations, and therefore may have attributes. if (const TagType *TTy = dyn_cast(QTy)) @@ -137,7 +115,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { // "underlying types". default: return MetadataCache[Ty] = - getTBAAInfoForNamedType(BTy->getName(Features), getChar()); + MDHelper.createTBAANode(BTy->getName(Features), getChar()); } } @@ -145,7 +123,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { // TODO: Implement C++'s type "similarity" and consider dis-"similar" // pointers distinct. if (Ty->isPointerType()) - return MetadataCache[Ty] = getTBAAInfoForNamedType("any pointer", + return MetadataCache[Ty] = MDHelper.createTBAANode("any pointer", getChar()); // Enum types are distinct types. In C++ they have "underlying types", @@ -173,7 +151,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { llvm::raw_svector_ostream Out(OutName); MContext.mangleCXXRTTIName(QualType(ETy, 0), Out); Out.flush(); - return MetadataCache[Ty] = getTBAAInfoForNamedType(OutName, getChar()); + return MetadataCache[Ty] = MDHelper.createTBAANode(OutName, getChar()); } // For now, handle any other kind of type conservatively. @@ -181,5 +159,5 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { } llvm::MDNode *CodeGenTBAA::getTBAAInfoForVTablePtr() { - return getTBAAInfoForNamedType("vtable pointer", getRoot()); + return MDHelper.createTBAANode("vtable pointer", getRoot()); } diff --git a/lib/CodeGen/CodeGenTBAA.h b/lib/CodeGen/CodeGenTBAA.h index 8e08498b7e59..4a9785287d01 100644 --- a/lib/CodeGen/CodeGenTBAA.h +++ b/lib/CodeGen/CodeGenTBAA.h @@ -17,6 +17,7 @@ #include "clang/Basic/LLVM.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/Support/MDBuilder.h" namespace llvm { class LLVMContext; @@ -41,6 +42,9 @@ class CodeGenTBAA { const LangOptions &Features; MangleContext &MContext; + // MDHelper - Helper for creating metadata. + llvm::MDBuilder MDHelper; + /// MetadataCache - This maps clang::Types to llvm::MDNodes describing them. llvm::DenseMap MetadataCache; @@ -55,10 +59,6 @@ class CodeGenTBAA { /// considered to be equivalent to it. llvm::MDNode *getChar(); - llvm::MDNode *getTBAAInfoForNamedType(StringRef NameStr, - llvm::MDNode *Parent, - bool Readonly = false); - public: CodeGenTBAA(ASTContext &Ctx, llvm::LLVMContext &VMContext, const LangOptions &Features, diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 3ed1778cc90f..2b71fdd504e7 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -2527,19 +2527,16 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const { static bool isHomogeneousAggregate(QualType Ty, const Type *&Base, ASTContext &Context, uint64_t *HAMembers = 0) { - uint64_t Members; + uint64_t Members = 0; if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) { if (!isHomogeneousAggregate(AT->getElementType(), Base, Context, &Members)) return false; Members *= AT->getSize().getZExtValue(); } else if (const RecordType *RT = Ty->getAs()) { const RecordDecl *RD = RT->getDecl(); - if (RD->isUnion() || RD->hasFlexibleArrayMember()) + if (RD->hasFlexibleArrayMember()) return false; - if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { - if (!CXXRD->isAggregate()) - return false; - } + Members = 0; for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i) { @@ -2547,7 +2544,9 @@ static bool isHomogeneousAggregate(QualType Ty, const Type *&Base, uint64_t FldMembers; if (!isHomogeneousAggregate(FD->getType(), Base, Context, &FldMembers)) return false; - Members += FldMembers; + + Members = (RD->isUnion() ? + std::max(Members, FldMembers) : Members + FldMembers); } } else { Members = 1; @@ -2584,7 +2583,8 @@ static bool isHomogeneousAggregate(QualType Ty, const Type *&Base, // Homogeneous Aggregates can have at most 4 members of the base type. if (HAMembers) *HAMembers = Members; - return (Members <= 4); + + return (Members > 0 && Members <= 4); } ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const { @@ -2609,8 +2609,10 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const { if (getABIKind() == ARMABIInfo::AAPCS_VFP) { // Homogeneous Aggregates need to be expanded. const Type *Base = 0; - if (isHomogeneousAggregate(Ty, Base, getContext())) + if (isHomogeneousAggregate(Ty, Base, getContext())) { + assert(Base && "Base class should be set for homogeneous aggregate"); return ABIArgInfo::getExpand(); + } } // Otherwise, pass by coercing to a structure of the appropriate size. @@ -2776,9 +2778,11 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const { // Check for homogeneous aggregates with AAPCS-VFP. if (getABIKind() == AAPCS_VFP) { const Type *Base = 0; - if (isHomogeneousAggregate(RetTy, Base, getContext())) + if (isHomogeneousAggregate(RetTy, Base, getContext())) { + assert(Base && "Base class should be set for homogeneous aggregate"); // Homogeneous Aggregates are returned directly. return ABIArgInfo::getDirect(); + } } // Aggregates <= 4 bytes are returned in r0; other aggregates diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp index 42c84493fa6a..5553fc937e01 100644 --- a/lib/Driver/Compilation.cpp +++ b/lib/Driver/Compilation.cpp @@ -230,3 +230,7 @@ void Compilation::initCompilationForDiagnostics(void) { Redirects[1] = new const llvm::sys::Path(); Redirects[2] = new const llvm::sys::Path(); } + +StringRef Compilation::getSysRoot(void) const { + return getDriver().SysRoot; +} diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 7ab3278c7f67..3ddac69e98cb 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -49,8 +49,8 @@ Driver::Driver(StringRef ClangExecutable, bool IsProduction, DiagnosticsEngine &Diags) : Opts(createDriverOptTable()), Diags(Diags), - ClangExecutable(ClangExecutable), UseStdLib(true), - DefaultTargetTriple(DefaultTargetTriple), + ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT), + UseStdLib(true), DefaultTargetTriple(DefaultTargetTriple), DefaultImageName(DefaultImageName), DriverTitle("clang \"gcc-compatible\" driver"), CCPrintOptionsFilename(0), CCPrintHeadersFilename(0), @@ -660,9 +660,7 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { llvm::outs() << "\n"; llvm::outs() << "libraries: =" << ResourceDir; - std::string sysroot; - if (Arg *A = C.getArgs().getLastArg(options::OPT__sysroot_EQ)) - sysroot = A->getValue(C.getArgs()); + StringRef sysroot = C.getSysRoot(); for (ToolChain::path_list::const_iterator it = TC.getFilePaths().begin(), ie = TC.getFilePaths().end(); it != ie; ++it) { @@ -872,30 +870,30 @@ void Driver::BuildUniversalActions(const ToolChain &TC, // Handle debug info queries. Arg *A = Args.getLastArg(options::OPT_g_Group); - if (A && !A->getOption().matches(options::OPT_g0) && - !A->getOption().matches(options::OPT_gstabs) && - ContainsCompileOrAssembleAction(Actions.back())) { - - // Add a 'dsymutil' step if necessary, when debug info is enabled and we - // have a compile input. We need to run 'dsymutil' ourselves in such cases - // because the debug info will refer to a temporary object file which is - // will be removed at the end of the compilation process. - if (Act->getType() == types::TY_Image) { - ActionList Inputs; - Inputs.push_back(Actions.back()); - Actions.pop_back(); - Actions.push_back(new DsymutilJobAction(Inputs, types::TY_dSYM)); - } - - // Verify the output (debug information only) if we passed '-verify'. - if (Args.hasArg(options::OPT_verify)) { - ActionList VerifyInputs; - VerifyInputs.push_back(Actions.back()); - Actions.pop_back(); - Actions.push_back(new VerifyJobAction(VerifyInputs, - types::TY_Nothing)); - } + if (A && !A->getOption().matches(options::OPT_g0) && + !A->getOption().matches(options::OPT_gstabs) && + ContainsCompileOrAssembleAction(Actions.back())) { + + // Add a 'dsymutil' step if necessary, when debug info is enabled and we + // have a compile input. We need to run 'dsymutil' ourselves in such cases + // because the debug info will refer to a temporary object file which is + // will be removed at the end of the compilation process. + if (Act->getType() == types::TY_Image) { + ActionList Inputs; + Inputs.push_back(Actions.back()); + Actions.pop_back(); + Actions.push_back(new DsymutilJobAction(Inputs, types::TY_dSYM)); } + + // Verify the output (debug information only) if we passed '-verify'. + if (Args.hasArg(options::OPT_verify)) { + ActionList VerifyInputs; + VerifyInputs.push_back(Actions.back()); + Actions.pop_back(); + Actions.push_back(new VerifyJobAction(VerifyInputs, + types::TY_Nothing)); + } + } } } diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 67697569c43f..81657d80661c 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -580,7 +580,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { // If no '-miphoneos-version-min' specified on the command line and // IPHONEOS_DEPLOYMENT_TARGET is not defined, see if we can set the default - // based on isysroot. + // based on -isysroot. if (iOSTarget.empty()) { if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { StringRef first, second; @@ -1086,6 +1086,7 @@ bool Generic_GCC::GCCVersion::operator<(const GCCVersion &RHS) const { // a patch. if (RHS.Patch == -1) return true; if (Patch == -1) return false; if (Patch < RHS.Patch) return true; if (Patch > RHS.Patch) return false; + if (PatchSuffix == RHS.PatchSuffix) return false; // Finally, between completely tied version numbers, the version with the // suffix loses as we prefer full releases. @@ -1103,7 +1104,7 @@ static StringRef getGCCToolchainDir(const ArgList &Args) { /// \brief Construct a GCCInstallationDetector from the driver. /// /// This performs all of the autodetection and sets up the various paths. -/// Once constructed, a GCCInstallation is esentially immutable. +/// Once constructed, a GCCInstallationDetector is essentially immutable. /// /// FIXME: We shouldn't need an explicit TargetTriple parameter here, and /// should instead pull the target out of the driver. This is currently @@ -2063,7 +2064,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // If the GCC installation we found is inside of the sysroot, we want to // prefer libraries installed in the parent prefix of the GCC installation. // It is important to *not* use these paths when the GCC installation is - // outside of the system root as that can pick up un-intented libraries. + // outside of the system root as that can pick up unintended libraries. // This usually happens when there is an external cross compiler on the // host system, and a more minimal sysroot available that is the target of // the cross. diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index fbf4f08d4c34..47b52949546d 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -377,10 +377,11 @@ void Clang::AddPreprocessingOptions(Compilation &C, // If we have a --sysroot, and don't have an explicit -isysroot flag, add an // -isysroot to the CC1 invocation. - if (Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) { + StringRef sysroot = C.getSysRoot(); + if (sysroot != "") { if (!Args.hasArg(options::OPT_isysroot)) { CmdArgs.push_back("-isysroot"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(C.getArgs().MakeArgString(sysroot)); } } @@ -4016,9 +4017,10 @@ void darwin::Link::AddLinkArgs(Compilation &C, // Give --sysroot= preference, over the Apple specific behavior to also use // --isysroot as the syslibroot. - if (const Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) { + StringRef sysroot = C.getSysRoot(); + if (sysroot != "") { CmdArgs.push_back("-syslibroot"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(C.getArgs().MakeArgString(sysroot)); } else if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { CmdArgs.push_back("-syslibroot"); CmdArgs.push_back(A->getValue(Args)); diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index e32fa630a737..7aa96032ee36 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -643,8 +643,10 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr &Diags, DiagnosticConsumer *Client = 0; if (CaptureDiagnostics) Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics); - Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd- ArgBegin, - ArgBegin, Client); + Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd-ArgBegin, + ArgBegin, Client, + /*ShouldOwnClient=*/true, + /*ShouldCloneClient=*/false); } else if (CaptureDiagnostics) { Diags->setClient(new StoredDiagnosticConsumer(AST.StoredDiagnostics)); } diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index cab6b90d0cda..803e418e2413 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -651,6 +651,10 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { // created. This complexity should be lifted elsewhere. getTarget().setForcedLangOptions(getLangOpts()); + // rewriter project will change target built-in bool type from its default. + if (getFrontendOpts().ProgramAction == frontend::RewriteObjC) + getTarget().noSignedCharForObjCBool(); + // Validate/process some options. if (getHeaderSearchOpts().Verbose) OS << "clang -cc1 version " CLANG_VERSION_STRING diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 02947c778c32..4c5b063f7d41 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -429,7 +429,6 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::PrintDeclContext: return "-print-decl-contexts"; case frontend::PrintPreamble: return "-print-preamble"; case frontend::PrintPreprocessedInput: return "-E"; - case frontend::PubnamesDump: return "-pubnames-dump"; case frontend::RewriteMacros: return "-rewrite-macros"; case frontend::RewriteObjC: return "-rewrite-objc"; case frontend::RewriteTest: return "-rewrite-test"; @@ -1369,8 +1368,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ProgramAction = frontend::PrintPreamble; break; case OPT_E: Opts.ProgramAction = frontend::PrintPreprocessedInput; break; - case OPT_pubnames_dump: - Opts.ProgramAction = frontend::PubnamesDump; break; case OPT_rewrite_macros: Opts.ProgramAction = frontend::RewriteMacros; break; case OPT_rewrite_objc: diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index b4a439d4237e..737ee4a098bb 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -25,7 +25,6 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" -#include using namespace clang; @@ -355,77 +354,6 @@ ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, return new ASTConsumer(); } -namespace { - class PubnamesDumpConsumer : public ASTConsumer { - Preprocessor &PP; - - /// \brief Determine whether the given identifier provides a 'public' name. - bool isPublicName(IdentifierInfo *II) { - // If there are any top-level declarations associated with this - // identifier, it is a public name. - if (II->getFETokenInfo()) - return true; - - // If this identifier is the name of a non-builtin macro that isn't - // defined on the command line or implicitly by the front end, it is a - // public name. - if (II->hasMacroDefinition()) { - if (MacroInfo *M = PP.getMacroInfo(II)) - if (!M->isBuiltinMacro()) { - SourceLocation Loc = M->getDefinitionLoc(); - FileID File = PP.getSourceManager().getFileID(Loc); - if (PP.getSourceManager().getFileEntryForID(File)) - return true; - } - } - - return false; - } - - public: - PubnamesDumpConsumer(Preprocessor &PP) : PP(PP) { } - - virtual void HandleTranslationUnit(ASTContext &Ctx) { - std::set Pubnames; - - // Add the names of any non-builtin macros. - for (IdentifierTable::iterator I = Ctx.Idents.begin(), - IEnd = Ctx.Idents.end(); - I != IEnd; ++I) { - if (isPublicName(I->second)) - Pubnames.insert(I->first()); - } - - // If there is an external identifier lookup source, consider those - // identifiers as well. - if (IdentifierInfoLookup *External - = Ctx.Idents.getExternalIdentifierLookup()) { - OwningPtr Iter(External->getIdentifiers()); - do { - StringRef Name = Iter->Next(); - if (Name.empty()) - break; - - if (isPublicName(PP.getIdentifierInfo(Name))) - Pubnames.insert(Name); - } while (true); - } - - // Print the names, in lexicographical order. - for (std::set::iterator N = Pubnames.begin(), - NEnd = Pubnames.end(); - N != NEnd; ++N) { - llvm::outs() << *N << '\n'; - } - } - }; -} - -ASTConsumer *PubnamesDumpAction::CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) { - return new PubnamesDumpConsumer(CI.getPreprocessor()); -} - //===----------------------------------------------------------------------===// // Preprocessor Actions //===----------------------------------------------------------------------===// diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp index 9f5dcb483803..65fb1ae13f21 100644 --- a/lib/Frontend/TextDiagnostic.cpp +++ b/lib/Frontend/TextDiagnostic.cpp @@ -10,13 +10,17 @@ #include "clang/Frontend/TextDiagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/ConvertUTF.h" #include "clang/Frontend/DiagnosticOptions.h" #include "clang/Lex/Lexer.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Locale.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include + using namespace clang; static const enum raw_ostream::Colors noteColor = @@ -36,23 +40,269 @@ static const enum raw_ostream::Colors savedColor = /// \brief Number of spaces to indent when word-wrapping. const unsigned WordWrapIndentation = 6; +int bytesSincePreviousTabOrLineBegin(StringRef SourceLine, size_t i) { + int bytes = 0; + while (0,bool> +printableTextForNextCharacter(StringRef SourceLine, size_t *i, + unsigned TabStop) { + assert(i && "i must not be null"); + assert(*i expandedTab; + expandedTab.assign(NumSpaces, ' '); + return std::make_pair(expandedTab, true); + } + + // FIXME: this data is copied from the private implementation of ConvertUTF.h + static const char trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 + }; + + unsigned char const *begin, *end; + begin = reinterpret_cast(&*(SourceLine.begin() + *i)); + end = begin + SourceLine.size(); + + if (isLegalUTF8Sequence(begin, end)) { + UTF32 c; + UTF32 *cptr = &c; + unsigned char const *original_begin = begin; + char trailingBytes = trailingBytesForUTF8[(unsigned char)SourceLine[*i]]; + unsigned char const *cp_end = begin+trailingBytes+1; + + ConversionResult res = ConvertUTF8toUTF32(&begin, cp_end, &cptr, cptr+1, + strictConversion); + (void)res; + assert(conversionOK==res); + assert(0 < begin-original_begin + && "we must be further along in the string now"); + *i += begin-original_begin; + + if (!llvm::sys::locale::isPrint(c)) { + // If next character is valid UTF-8, but not printable + SmallString<16> expandedCP(""); + while (c) { + expandedCP.insert(expandedCP.begin()+3, llvm::hexdigit(c%16)); + c/=16; + } + while (expandedCP.size() < 8) + expandedCP.insert(expandedCP.begin()+3, llvm::hexdigit(0)); + return std::make_pair(expandedCP, false); + } + + // If next character is valid UTF-8, and printable + return std::make_pair(SmallString<16>(original_begin, cp_end), true); + + } + + // If next byte is not valid UTF-8 (and therefore not printable) + SmallString<16> expandedByte(""); + unsigned char byte = SourceLine[*i]; + expandedByte[1] = llvm::hexdigit(byte / 16); + expandedByte[2] = llvm::hexdigit(byte % 16); + ++(*i); + return std::make_pair(expandedByte, false); +} + +void expandTabs(std::string &SourceLine, unsigned TabStop) { + size_t i = SourceLine.size(); + while (i>0) { + i--; + if (SourceLine[i]!='\t') + continue; + size_t tmp_i = i; + std::pair,bool> res + = printableTextForNextCharacter(SourceLine, &tmp_i, TabStop); + SourceLine.replace(i, 1, res.first.c_str()); + } +} + +/// This function takes a raw source line and produces a mapping from the bytes +/// of the printable representation of the line to the columns those printable +/// characters will appear at (numbering the first column as 0). +/// +/// If a byte 'i' corresponds to muliple columns (e.g. the byte contains a tab +/// character) then the the array will map that byte to the first column the +/// tab appears at and the next value in the map will have been incremented +/// more than once. +/// +/// If a byte is the first in a sequence of bytes that together map to a single +/// entity in the output, then the array will map that byte to the appropriate +/// column while the subsequent bytes will be -1. +/// +/// The last element in the array does not correspond to any byte in the input +/// and instead is the number of columns needed to display the source +/// +/// example: (given a tabstop of 8) +/// +/// "a \t \u3042" -> {0,1,2,8,9,-1,-1,11} +/// +/// (\u3042 is represented in UTF-8 by three bytes and takes two columns to +/// display) +void byteToColumn(StringRef SourceLine, unsigned TabStop, + SmallVectorImpl &out) { + out.clear(); + + if (SourceLine.empty()) { + out.resize(1u,0); + return; + } + + out.resize(SourceLine.size()+1, -1); + + int columns = 0; + size_t i = 0; + while (i,bool> res + = printableTextForNextCharacter(SourceLine, &i, TabStop); + columns += llvm::sys::locale::columnWidth(res.first); + } + out.back() = columns; +} + +/// This function takes a raw source line and produces a mapping from columns +/// to the byte of the source line that produced the character displaying at +/// that column. This is the inverse of the mapping produced by byteToColumn() +/// +/// The last element in the array is the number of bytes in the source string +/// +/// example: (given a tabstop of 8) +/// +/// "a \t \u3042" -> {0,1,2,-1,-1,-1,-1,-1,3,4,-1,7} +/// +/// (\u3042 is represented in UTF-8 by three bytes and takes two columns to +/// display) +void columnToByte(StringRef SourceLine, unsigned TabStop, + SmallVectorImpl &out) { + out.clear(); + + if (SourceLine.empty()) { + out.resize(1u, 0); + return; + } + + int columns = 0; + size_t i = 0; + while (i,bool> res + = printableTextForNextCharacter(SourceLine, &i, TabStop); + columns += llvm::sys::locale::columnWidth(res.first); + } + out.resize(columns+1, -1); + out.back() = i; +} + +struct SourceColumnMap { + SourceColumnMap(StringRef SourceLine, unsigned TabStop) + : m_SourceLine(SourceLine) { + + ::byteToColumn(SourceLine, TabStop, m_byteToColumn); + ::columnToByte(SourceLine, TabStop, m_columnToByte); + + assert(m_byteToColumn.size()==SourceLine.size()+1); + assert(0 < m_byteToColumn.size() && 0 < m_columnToByte.size()); + assert(m_byteToColumn.size() + == static_cast(m_columnToByte.back()+1)); + assert(static_cast(m_byteToColumn.back()+1) + == m_columnToByte.size()); + } + int columns() const { return m_byteToColumn.back(); } + int bytes() const { return m_columnToByte.back(); } + int byteToColumn(int n) const { + assert(0<=n && n(m_byteToColumn.size())); + return m_byteToColumn[n]; + } + int columnToByte(int n) const { + assert(0<=n && n(m_columnToByte.size())); + return m_columnToByte[n]; + } + StringRef getSourceLine() const { + return m_SourceLine; + } + +private: + const std::string m_SourceLine; + SmallVector m_byteToColumn; + SmallVector m_columnToByte; +}; + +// used in assert in selectInterestingSourceRegion() +namespace { +struct char_out_of_range { + const char lower,upper; + char_out_of_range(char lower, char upper) : + lower(lower), upper(upper) {} + bool operator()(char c) { return c < lower || upper < c; } +}; +} + /// \brief When the source code line we want to print is too long for /// the terminal, select the "interesting" region. static void selectInterestingSourceRegion(std::string &SourceLine, std::string &CaretLine, std::string &FixItInsertionLine, - unsigned EndOfCaretToken, - unsigned Columns) { - unsigned MaxSize = std::max(SourceLine.size(), - std::max(CaretLine.size(), - FixItInsertionLine.size())); - if (MaxSize > SourceLine.size()) - SourceLine.resize(MaxSize, ' '); - if (MaxSize > CaretLine.size()) - CaretLine.resize(MaxSize, ' '); - if (!FixItInsertionLine.empty() && MaxSize > FixItInsertionLine.size()) - FixItInsertionLine.resize(MaxSize, ' '); - + unsigned Columns, + const SourceColumnMap &map) { + unsigned MaxColumns = std::max(map.columns(), + std::max(CaretLine.size(), + FixItInsertionLine.size())); + // if the number of columns is less than the desired number we're done + if (MaxColumns <= Columns) + return; + + // no special characters allowed in CaretLine or FixItInsertionLine + assert(CaretLine.end() == + std::find_if(CaretLine.begin(), CaretLine.end(), + char_out_of_range(' ','~'))); + assert(FixItInsertionLine.end() == + std::find_if(FixItInsertionLine.begin(), FixItInsertionLine.end(), + char_out_of_range(' ','~'))); + // Find the slice that we need to display the full caret line // correctly. unsigned CaretStart = 0, CaretEnd = CaretLine.size(); @@ -64,10 +314,8 @@ static void selectInterestingSourceRegion(std::string &SourceLine, if (!isspace(CaretLine[CaretEnd - 1])) break; - // Make sure we don't chop the string shorter than the caret token - // itself. - if (CaretEnd < EndOfCaretToken) - CaretEnd = EndOfCaretToken; + // caret has already been inserted into CaretLine so the above whitespace + // check is guaranteed to include the caret // If we have a fix-it line, make sure the slice includes all of the // fix-it information. @@ -81,10 +329,8 @@ static void selectInterestingSourceRegion(std::string &SourceLine, if (!isspace(FixItInsertionLine[FixItEnd - 1])) break; - if (FixItStart < CaretStart) - CaretStart = FixItStart; - if (FixItEnd > CaretEnd) - CaretEnd = FixItEnd; + CaretStart = std::min(FixItStart, CaretStart); + CaretEnd = std::max(FixItEnd, CaretEnd); } // CaretLine[CaretStart, CaretEnd) contains all of the interesting @@ -92,62 +338,72 @@ static void selectInterestingSourceRegion(std::string &SourceLine, // number of columns we have, try to grow the slice to encompass // more context. - // If the end of the interesting region comes before we run out of - // space in the terminal, start at the beginning of the line. - if (Columns > 3 && CaretEnd < Columns - 3) - CaretStart = 0; + unsigned SourceStart = map.columnToByte(std::min(CaretStart, + map.columns())); + unsigned SourceEnd = map.columnToByte(std::min(CaretEnd, + map.columns())); + + unsigned CaretColumnsOutsideSource = CaretEnd-CaretStart + - (map.byteToColumn(SourceEnd)-map.byteToColumn(SourceStart)); + + char const *front_ellipse = " ..."; + char const *front_space = " "; + char const *back_ellipse = "..."; + unsigned ellipses_space = strlen(front_ellipse) + strlen(back_ellipse); unsigned TargetColumns = Columns; - if (TargetColumns > 8) - TargetColumns -= 8; // Give us extra room for the ellipses. - unsigned SourceLength = SourceLine.size(); - while ((CaretEnd - CaretStart) < TargetColumns) { + // Give us extra room for the ellipses + // and any of the caret line that extends past the source + if (TargetColumns > ellipses_space+CaretColumnsOutsideSource) + TargetColumns -= ellipses_space+CaretColumnsOutsideSource; + + while (SourceStart>0 || SourceEnd 1) { - unsigned NewStart = CaretStart - 1; + + if (SourceStart>0) { + unsigned NewStart = SourceStart-1; // Skip over any whitespace we see here; we're looking for // another bit of interesting text. - while (NewStart && isspace(SourceLine[NewStart])) + while (NewStart && + (map.byteToColumn(NewStart)==-1 || isspace(SourceLine[NewStart]))) --NewStart; // Skip over this bit of "interesting" text. - while (NewStart && !isspace(SourceLine[NewStart])) + while (NewStart && + (map.byteToColumn(NewStart)!=-1 && !isspace(SourceLine[NewStart]))) --NewStart; // Move up to the non-whitespace character we just saw. if (NewStart) ++NewStart; - // If we're still within our limit, update the starting - // position within the source/caret line. - if (CaretEnd - NewStart <= TargetColumns) { - CaretStart = NewStart; + unsigned NewColumns = map.byteToColumn(SourceEnd) - + map.byteToColumn(NewStart); + if (NewColumns <= TargetColumns) { + SourceStart = NewStart; ExpandedRegion = true; } } - // Move the end of the interesting region right until we've - // pulled in something else interesting. - if (CaretEnd != SourceLength) { - assert(CaretEnd < SourceLength && "Unexpected caret position!"); - unsigned NewEnd = CaretEnd; + if (SourceEnd CaretEnd) - FixItInsertionLine.erase(CaretEnd, std::string::npos); - if (CaretStart > 2) { - SourceLine.replace(0, CaretStart, " ..."); - CaretLine.replace(0, CaretStart, " "); - if (FixItInsertionLine.size() >= CaretStart) - FixItInsertionLine.replace(0, CaretStart, " "); + assert(CaretStart!=(unsigned)-1 && CaretEnd!=(unsigned)-1 && + SourceStart!=(unsigned)-1 && SourceEnd!=(unsigned)-1); + assert(SourceStart <= SourceEnd); + assert(CaretStart <= CaretEnd); + + unsigned BackColumnsRemoved + = map.byteToColumn(SourceLine.size())-map.byteToColumn(SourceEnd); + unsigned FrontColumnsRemoved = CaretStart; + unsigned ColumnsKept = CaretEnd-CaretStart; + + // We checked up front that the line needed truncation + assert(FrontColumnsRemoved+ColumnsKept+BackColumnsRemoved > Columns); + + // The line needs some trunctiona, and we'd prefer to keep the front + // if possible, so remove the back + if (BackColumnsRemoved) + SourceLine.replace(SourceEnd, std::string::npos, back_ellipse); + + // If that's enough then we're done + if (FrontColumnsRemoved+ColumnsKept <= Columns) + return; + + // Otherwise remove the front as well + if (FrontColumnsRemoved) { + SourceLine.replace(0, SourceStart, front_ellipse); + CaretLine.replace(0, CaretStart, front_space); + if (!FixItInsertionLine.empty()) + FixItInsertionLine.replace(0, CaretStart, front_space); } } @@ -564,10 +840,13 @@ void TextDiagnostic::emitSnippetAndCaret( // Get information about the buffer it points into. bool Invalid = false; - const char *BufStart = SM.getBufferData(FID, &Invalid).data(); + StringRef BufData = SM.getBufferData(FID, &Invalid); if (Invalid) return; + const char *BufStart = BufData.data(); + const char *BufEnd = BufStart + BufData.size(); + unsigned LineNo = SM.getLineNumber(FID, FileOffset); unsigned ColNo = SM.getColumnNumber(FID, FileOffset); unsigned CaretEndColNo @@ -581,7 +860,7 @@ void TextDiagnostic::emitSnippetAndCaret( // Compute the line end. Scan forward from the error position to the end of // the line. const char *LineEnd = TokPtr; - while (*LineEnd != '\n' && *LineEnd != '\r' && *LineEnd != '\0') + while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd!=BufEnd) ++LineEnd; // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past @@ -596,19 +875,30 @@ void TextDiagnostic::emitSnippetAndCaret( // length as the line of source code. std::string CaretLine(LineEnd-LineStart, ' '); + const SourceColumnMap sourceColMap(SourceLine, DiagOpts.TabStop); + // Highlight all of the characters covered by Ranges with ~ characters. for (SmallVectorImpl::iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) - highlightRange(*I, LineNo, FID, SourceLine, CaretLine); + highlightRange(*I, LineNo, FID, sourceColMap, CaretLine); // Next, insert the caret itself. - if (ColNo-1 < CaretLine.size()) - CaretLine[ColNo-1] = '^'; - else - CaretLine.push_back('^'); + ColNo = sourceColMap.byteToColumn(ColNo-1); + if (CaretLine.size() Columns) - selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine, - CaretEndColNo, Columns); - // Finally, remove any blank spaces from the end of CaretLine. while (CaretLine[CaretLine.size()-1] == ' ') CaretLine.erase(CaretLine.end()-1); // Emit what we have computed. - OS << SourceLine << '\n'; + emitSnippet(SourceLine); if (DiagOpts.ShowColors) OS.changeColor(caretColor, true); @@ -658,13 +937,49 @@ void TextDiagnostic::emitSnippetAndCaret( emitParseableFixits(Hints); } +void TextDiagnostic::emitSnippet(StringRef line) +{ + if (line.empty()) + return; + + size_t i = 0; + + std::string to_print; + bool print_reversed = false; + + while (i,bool> res + = printableTextForNextCharacter(line, &i, DiagOpts.TabStop); + bool was_printable = res.second; + + if (DiagOpts.ShowColors + && was_printable==print_reversed) { + if (print_reversed) + OS.reverseColor(); + OS << to_print; + to_print.clear(); + if (DiagOpts.ShowColors) + OS.resetColor(); + } + + print_reversed = !was_printable; + to_print += res.first.str(); + } + + if (print_reversed && DiagOpts.ShowColors) + OS.reverseColor(); + OS << to_print; + if (print_reversed && DiagOpts.ShowColors) + OS.resetColor(); + + OS << '\n'; +} + /// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo. void TextDiagnostic::highlightRange(const CharSourceRange &R, unsigned LineNo, FileID FID, - const std::string &SourceLine, + const SourceColumnMap &map, std::string &CaretLine) { - assert(CaretLine.size() == SourceLine.size() && - "Expect a correspondence between source and caret line!"); if (!R.isValid()) return; SourceLocation Begin = SM.getExpansionLoc(R.getBegin()); @@ -694,7 +1009,7 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R, } // Compute the column number of the end. - unsigned EndColNo = CaretLine.size(); + unsigned EndColNo = map.getSourceLine().size(); if (EndLineNo == LineNo) { EndColNo = SM.getExpansionColumnNumber(End); if (EndColNo) { @@ -714,15 +1029,17 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R, // Check that a token range does not highlight only whitespace. if (R.isTokenRange()) { // Pick the first non-whitespace column. - while (StartColNo < SourceLine.size() && - (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t')) + while (StartColNo < map.getSourceLine().size() && + (map.getSourceLine()[StartColNo] == ' ' || + map.getSourceLine()[StartColNo] == '\t')) ++StartColNo; // Pick the last non-whitespace column. - if (EndColNo > SourceLine.size()) - EndColNo = SourceLine.size(); + if (EndColNo > map.getSourceLine().size()) + EndColNo = map.getSourceLine().size(); while (EndColNo-1 && - (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t')) + (map.getSourceLine()[EndColNo-1] == ' ' || + map.getSourceLine()[EndColNo-1] == '\t')) --EndColNo; // If the start/end passed each other, then we are trying to highlight a @@ -731,15 +1048,24 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R, assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); } + assert(StartColNo <= map.getSourceLine().size() && "Invalid range!"); + assert(EndColNo <= map.getSourceLine().size() && "Invalid range!"); + // Fill the range with ~'s. - for (unsigned i = StartColNo; i < EndColNo; ++i) - CaretLine[i] = '~'; + StartColNo = map.byteToColumn(StartColNo); + EndColNo = map.byteToColumn(EndColNo); + + assert(StartColNo <= EndColNo && "Invalid range!"); + if (CaretLine.size() < EndColNo) + CaretLine.resize(EndColNo,' '); + std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~'); } -std::string TextDiagnostic::buildFixItInsertionLine(unsigned LineNo, - const char *LineStart, - const char *LineEnd, - ArrayRef Hints) { +std::string TextDiagnostic::buildFixItInsertionLine( + unsigned LineNo, + const SourceColumnMap &map, + ArrayRef Hints) { + std::string FixItInsertionLine; if (Hints.empty() || !DiagOpts.ShowFixits) return FixItInsertionLine; @@ -755,13 +1081,32 @@ std::string TextDiagnostic::buildFixItInsertionLine(unsigned LineNo, // Insert the new code into the line just below the code // that the user wrote. unsigned HintColNo - = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second); + = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1; + // hint must start inside the source or right at the end + assert(HintColNo(map.bytes())+1); + HintColNo = map.byteToColumn(HintColNo); + + // FIXME: if the fixit includes tabs or other characters that do not + // take up a single column per byte when displayed then + // I->CodeToInsert.size() is not a column number and we're mixing + // units (columns + bytes). We should get printable versions + // of each fixit before using them. unsigned LastColumnModified - = HintColNo - 1 + I->CodeToInsert.size(); + = HintColNo + I->CodeToInsert.size(); + + if (LastColumnModified > static_cast(map.bytes())) { + unsigned LastExistingColumn = map.byteToColumn(map.bytes()); + unsigned AddedColumns = LastColumnModified-LastExistingColumn; + LastColumnModified = LastExistingColumn + AddedColumns; + } else { + LastColumnModified = map.byteToColumn(LastColumnModified); + } + if (LastColumnModified > FixItInsertionLine.size()) FixItInsertionLine.resize(LastColumnModified, ' '); + assert(HintColNo+I->CodeToInsert.size() <= FixItInsertionLine.size()); std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(), - FixItInsertionLine.begin() + HintColNo - 1); + FixItInsertionLine.begin() + HintColNo); } else { FixItInsertionLine.clear(); break; @@ -769,72 +1114,11 @@ std::string TextDiagnostic::buildFixItInsertionLine(unsigned LineNo, } } - if (FixItInsertionLine.empty()) - return FixItInsertionLine; - - // Now that we have the entire fixit line, expand the tabs in it. - // Since we don't want to insert spaces in the middle of a word, - // find each word and the column it should line up with and insert - // spaces until they match. - unsigned FixItPos = 0; - unsigned LinePos = 0; - unsigned TabExpandedCol = 0; - unsigned LineLength = LineEnd - LineStart; - - while (FixItPos < FixItInsertionLine.size() && LinePos < LineLength) { - // Find the next word in the FixIt line. - while (FixItPos < FixItInsertionLine.size() && - FixItInsertionLine[FixItPos] == ' ') - ++FixItPos; - unsigned CharDistance = FixItPos - TabExpandedCol; - - // Walk forward in the source line, keeping track of - // the tab-expanded column. - for (unsigned I = 0; I < CharDistance; ++I, ++LinePos) - if (LinePos >= LineLength || LineStart[LinePos] != '\t') - ++TabExpandedCol; - else - TabExpandedCol = - (TabExpandedCol/DiagOpts.TabStop + 1) * DiagOpts.TabStop; - - // Adjust the fixit line to match this column. - FixItInsertionLine.insert(FixItPos, TabExpandedCol-FixItPos, ' '); - FixItPos = TabExpandedCol; - - // Walk to the end of the word. - while (FixItPos < FixItInsertionLine.size() && - FixItInsertionLine[FixItPos] != ' ') - ++FixItPos; - } + expandTabs(FixItInsertionLine, DiagOpts.TabStop); return FixItInsertionLine; } -void TextDiagnostic::expandTabs(std::string &SourceLine, - std::string &CaretLine) { - // Scan the source line, looking for tabs. If we find any, manually expand - // them to spaces and update the CaretLine to match. - for (unsigned i = 0; i != SourceLine.size(); ++i) { - if (SourceLine[i] != '\t') continue; - - // Replace this tab with at least one space. - SourceLine[i] = ' '; - - // Compute the number of spaces we need to insert. - unsigned TabStop = DiagOpts.TabStop; - assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop && - "Invalid -ftabstop value"); - unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1); - assert(NumSpaces < TabStop && "Invalid computation of space amt"); - - // Insert spaces into the SourceLine. - SourceLine.insert(i+1, NumSpaces, ' '); - - // Insert spaces or ~'s into CaretLine. - CaretLine.insert(i+1, NumSpaces, CaretLine[i] == '~' ? '~' : ' '); - } -} - void TextDiagnostic::emitParseableFixits(ArrayRef Hints) { if (!DiagOpts.ShowParseableFixits) return; @@ -878,4 +1162,3 @@ void TextDiagnostic::emitParseableFixits(ArrayRef Hints) { OS << "\"\n"; } } - diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 20665051808b..07d2b8d19f24 100644 --- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -72,7 +72,6 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { case PrintDeclContext: return new DeclContextPrintAction(); case PrintPreamble: return new PrintPreambleAction(); case PrintPreprocessedInput: return new PrintPreprocessedAction(); - case PubnamesDump: return new PubnamesDumpAction(); case RewriteMacros: return new RewriteMacrosAction(); case RewriteObjC: return new RewriteObjCAction(); case RewriteTest: return new RewriteTestAction(); diff --git a/lib/Headers/avx2intrin.h b/lib/Headers/avx2intrin.h index d165f1fbe2dd..884c46d4d689 100644 --- a/lib/Headers/avx2intrin.h +++ b/lib/Headers/avx2intrin.h @@ -822,7 +822,9 @@ _mm256_permutevar8x32_epi32(__m256i a, __m256i b) #define _mm256_permute4x64_pd(V, M) __extension__ ({ \ __m256d __V = (V); \ - (__m256d)__builtin_ia32_permdf256((__v4df)__V, (M)); }) + (__m256d)__builtin_shufflevector((__v4df)__V, (__v4df) _mm256_setzero_pd(), \ + (M) & 0x3, ((M) & 0xc) >> 2, \ + ((M) & 0x30) >> 4, ((M) & 0xc0) >> 6); }) static __inline__ __m256 __attribute__((__always_inline__, __nodebug__)) _mm256_permutevar8x32_ps(__m256 a, __m256 b) @@ -832,16 +834,14 @@ _mm256_permutevar8x32_ps(__m256 a, __m256 b) #define _mm256_permute4x64_epi64(V, M) __extension__ ({ \ __m256i __V = (V); \ - (__m256i)__builtin_ia32_permdi256(__V, (M)); }) + (__m256i)__builtin_shufflevector((__v4di)__V, (__v4di) _mm256_setzero_si256(), \ + (M) & 0x3, ((M) & 0xc) >> 2, \ + ((M) & 0x30) >> 4, ((M) & 0xc0) >> 6); }) #define _mm256_permute2x128_si256(V1, V2, M) __extension__ ({ \ __m256i __V1 = (V1); \ __m256i __V2 = (V2); \ - __builtin_shufflevector(__V1, __V2, \ - ((M) & 0x3) * 2, \ - ((M) & 0x3) * 2 + 1, \ - (((M) & 0x30) >> 4) * 2, \ - (((M) & 0x30) >> 4) * 2 + 1); }) + (__m256i)__builtin_ia32_permti256(__V1, __V2, (M)); }) #define _mm256_extracti128_si256(A, O) __extension__ ({ \ __m256i __A = (A); \ diff --git a/lib/Headers/avxintrin.h b/lib/Headers/avxintrin.h index 7a0ec3fbd636..ee7f83572f5e 100644 --- a/lib/Headers/avxintrin.h +++ b/lib/Headers/avxintrin.h @@ -289,37 +289,17 @@ _mm256_permutevar_ps(__m256 a, __m256i c) #define _mm256_permute2f128_pd(V1, V2, M) __extension__ ({ \ __m256d __V1 = (V1); \ __m256d __V2 = (V2); \ - (__m256d)__builtin_shufflevector((__v4df)__V1, (__v4df)__V2, \ - ((M) & 0x3) * 2, \ - ((M) & 0x3) * 2 + 1, \ - (((M) & 0x30) >> 4) * 2, \ - (((M) & 0x30) >> 4) * 2 + 1); }) + (__m256d)__builtin_ia32_vperm2f128_pd256((__v4df)__V1, (__v4df)__V2, (M)); }) #define _mm256_permute2f128_ps(V1, V2, M) __extension__ ({ \ __m256 __V1 = (V1); \ __m256 __V2 = (V2); \ - (__m256)__builtin_shufflevector((__v8sf)__V1, (__v8sf)__V2, \ - ((M) & 0x3) * 4, \ - ((M) & 0x3) * 4 + 1, \ - ((M) & 0x3) * 4 + 2, \ - ((M) & 0x3) * 4 + 3, \ - (((M) & 0x30) >> 4) * 4, \ - (((M) & 0x30) >> 4) * 4 + 1, \ - (((M) & 0x30) >> 4) * 4 + 2, \ - (((M) & 0x30) >> 4) * 4 + 3); }) + (__m256)__builtin_ia32_vperm2f128_ps256((__v8sf)__V1, (__v8sf)__V2, (M)); }) #define _mm256_permute2f128_si256(V1, V2, M) __extension__ ({ \ __m256i __V1 = (V1); \ __m256i __V2 = (V2); \ - (__m256i)__builtin_shufflevector((__v8si)__V1, (__v8si)__V2, \ - ((M) & 0x3) * 4, \ - ((M) & 0x3) * 4 + 1, \ - ((M) & 0x3) * 4 + 2, \ - ((M) & 0x3) * 4 + 3, \ - (((M) & 0x30) >> 4) * 4, \ - (((M) & 0x30) >> 4) * 4 + 1, \ - (((M) & 0x30) >> 4) * 4 + 2, \ - (((M) & 0x30) >> 4) * 4 + 3); }) + (__m256i)__builtin_ia32_vperm2f128_si256((__v8si)__V1, (__v8si)__V2, (M)); }) /* Vector Blend */ #define _mm256_blend_pd(V1, V2, M) __extension__ ({ \ diff --git a/lib/Index/ASTLocation.cpp b/lib/Index/ASTLocation.cpp deleted file mode 100644 index fce6099dac2c..000000000000 --- a/lib/Index/ASTLocation.cpp +++ /dev/null @@ -1,114 +0,0 @@ -//===--- ASTLocation.cpp - A pair ------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// ASTLocation is Decl or a Stmt and its immediate Decl parent. -// -//===----------------------------------------------------------------------===// - -#include "clang/Index/ASTLocation.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/Stmt.h" -#include "clang/AST/Expr.h" -#include "clang/AST/ExprObjC.h" -using namespace clang; -using namespace idx; - -static Decl *getDeclFromExpr(Stmt *E) { - if (DeclRefExpr *RefExpr = dyn_cast(E)) - return RefExpr->getDecl(); - if (MemberExpr *ME = dyn_cast(E)) - return ME->getMemberDecl(); - if (ObjCIvarRefExpr *RE = dyn_cast(E)) - return RE->getDecl(); - - if (CallExpr *CE = dyn_cast(E)) - return getDeclFromExpr(CE->getCallee()); - if (CastExpr *CE = dyn_cast(E)) - return getDeclFromExpr(CE->getSubExpr()); - - return 0; -} - -Decl *ASTLocation::getReferencedDecl() { - if (isInvalid()) - return 0; - - switch (getKind()) { - case N_Type: - return 0; - case N_Decl: - return D; - case N_NamedRef: - return NDRef.ND; - case N_Stmt: - return getDeclFromExpr(Stm); - } - - llvm_unreachable("Invalid ASTLocation Kind!"); -} - -SourceRange ASTLocation::getSourceRange() const { - if (isInvalid()) - return SourceRange(); - - switch (getKind()) { - case N_Decl: - return D->getSourceRange(); - case N_Stmt: - return Stm->getSourceRange(); - case N_NamedRef: - return SourceRange(AsNamedRef().Loc, AsNamedRef().Loc); - case N_Type: - return AsTypeLoc().getLocalSourceRange(); - } - - llvm_unreachable("Invalid ASTLocation Kind!"); -} - -void ASTLocation::print(raw_ostream &OS) const { - if (isInvalid()) { - OS << "<< Invalid ASTLocation >>\n"; - return; - } - - ASTContext &Ctx = getParentDecl()->getASTContext(); - - switch (getKind()) { - case N_Decl: - OS << "[Decl: " << AsDecl()->getDeclKindName() << " "; - if (const NamedDecl *ND = dyn_cast(AsDecl())) - OS << *ND; - break; - - case N_Stmt: - OS << "[Stmt: " << AsStmt()->getStmtClassName() << " "; - AsStmt()->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOpts())); - break; - - case N_NamedRef: - OS << "[NamedRef: " << AsNamedRef().ND->getDeclKindName() << " "; - OS << *AsNamedRef().ND; - break; - - case N_Type: { - QualType T = AsTypeLoc().getType(); - OS << "[Type: " << T->getTypeClassName() << " " << T.getAsString(); - } - } - - OS << "] <"; - - SourceRange Range = getSourceRange(); - SourceManager &SourceMgr = Ctx.getSourceManager(); - Range.getBegin().print(OS, SourceMgr); - OS << ", "; - Range.getEnd().print(OS, SourceMgr); - OS << ">\n"; -} diff --git a/lib/Index/ASTVisitor.h b/lib/Index/ASTVisitor.h deleted file mode 100644 index 0b8425b2f337..000000000000 --- a/lib/Index/ASTVisitor.h +++ /dev/null @@ -1,143 +0,0 @@ -//===--- ASTVisitor.h - Visitor for an ASTContext ---------------*- 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 ASTVisitor interface. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INDEX_ASTVISITOR_H -#define LLVM_CLANG_INDEX_ASTVISITOR_H - -#include "clang/AST/DeclVisitor.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/AST/TypeLocVisitor.h" - -namespace clang { - -namespace idx { - -/// \brief Traverses the full AST, both Decls and Stmts. -template -class ASTVisitor : public DeclVisitor, - public StmtVisitor, - public TypeLocVisitor { -public: - ASTVisitor() : CurrentDecl(0) { } - - Decl *CurrentDecl; - - typedef ASTVisitor Base; - typedef DeclVisitor BaseDeclVisitor; - typedef StmtVisitor BaseStmtVisitor; - typedef TypeLocVisitor BaseTypeLocVisitor; - - using BaseStmtVisitor::Visit; - - //===--------------------------------------------------------------------===// - // DeclVisitor - //===--------------------------------------------------------------------===// - - void Visit(Decl *D) { - Decl *PrevDecl = CurrentDecl; - CurrentDecl = D; - BaseDeclVisitor::Visit(D); - CurrentDecl = PrevDecl; - } - - void VisitDeclaratorDecl(DeclaratorDecl *D) { - BaseDeclVisitor::VisitDeclaratorDecl(D); - if (TypeSourceInfo *TInfo = D->getTypeSourceInfo()) - Visit(TInfo->getTypeLoc()); - } - - void VisitFunctionDecl(FunctionDecl *D) { - BaseDeclVisitor::VisitFunctionDecl(D); - if (D->isThisDeclarationADefinition()) - Visit(D->getBody()); - } - - void VisitObjCMethodDecl(ObjCMethodDecl *D) { - BaseDeclVisitor::VisitObjCMethodDecl(D); - if (D->getBody()) - Visit(D->getBody()); - } - - void VisitBlockDecl(BlockDecl *D) { - BaseDeclVisitor::VisitBlockDecl(D); - Visit(D->getBody()); - } - - void VisitVarDecl(VarDecl *D) { - BaseDeclVisitor::VisitVarDecl(D); - if (Expr *Init = D->getInit()) - Visit(Init); - } - - void VisitDecl(Decl *D) { - if (isa(D) || isa(D) || isa(D)) - return; - - if (DeclContext *DC = dyn_cast(D)) - static_cast(this)->VisitDeclContext(DC); - } - - void VisitDeclContext(DeclContext *DC) { - for (DeclContext::decl_iterator - I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) - Visit(*I); - } - - //===--------------------------------------------------------------------===// - // StmtVisitor - //===--------------------------------------------------------------------===// - - void VisitDeclStmt(DeclStmt *Node) { - for (DeclStmt::decl_iterator - I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I) - Visit(*I); - } - - void VisitBlockExpr(BlockExpr *Node) { - // The BlockDecl is also visited by 'VisitDeclContext()'. No need to visit it twice. - } - - void VisitStmt(Stmt *Node) { - for (Stmt::child_range I = Node->children(); I; ++I) - if (*I) - Visit(*I); - } - - //===--------------------------------------------------------------------===// - // TypeLocVisitor - //===--------------------------------------------------------------------===// - - void Visit(TypeLoc TL) { - for (; TL; TL = TL.getNextTypeLoc()) - BaseTypeLocVisitor::Visit(TL); - } - - void VisitArrayLoc(ArrayTypeLoc TL) { - BaseTypeLocVisitor::VisitArrayTypeLoc(TL); - if (TL.getSizeExpr()) - Visit(TL.getSizeExpr()); - } - - void VisitFunctionTypeLoc(FunctionTypeLoc TL) { - BaseTypeLocVisitor::VisitFunctionTypeLoc(TL); - for (unsigned i = 0; i != TL.getNumArgs(); ++i) - Visit(TL.getArg(i)); - } - -}; - -} // namespace idx - -} // namespace clang - -#endif diff --git a/lib/Index/Analyzer.cpp b/lib/Index/Analyzer.cpp deleted file mode 100644 index f77e6ef92d68..000000000000 --- a/lib/Index/Analyzer.cpp +++ /dev/null @@ -1,470 +0,0 @@ -//===--- Analyzer.cpp - Analysis for indexing information -------*- 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 Analyzer interface. -// -//===----------------------------------------------------------------------===// - -#include "clang/Index/Analyzer.h" -#include "clang/Index/Entity.h" -#include "clang/Index/TranslationUnit.h" -#include "clang/Index/Handlers.h" -#include "clang/Index/ASTLocation.h" -#include "clang/Index/GlobalSelector.h" -#include "clang/Index/DeclReferenceMap.h" -#include "clang/Index/SelectorMap.h" -#include "clang/Index/IndexProvider.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/ExprObjC.h" -#include "llvm/ADT/SmallSet.h" -using namespace clang; -using namespace idx; - -namespace { - -//===----------------------------------------------------------------------===// -// DeclEntityAnalyzer Implementation -//===----------------------------------------------------------------------===// - -class DeclEntityAnalyzer : public TranslationUnitHandler { - Entity Ent; - TULocationHandler &TULocHandler; - -public: - DeclEntityAnalyzer(Entity ent, TULocationHandler &handler) - : Ent(ent), TULocHandler(handler) { } - - virtual void Handle(TranslationUnit *TU) { - assert(TU && "Passed null translation unit"); - - Decl *D = Ent.getDecl(TU->getASTContext()); - assert(D && "Couldn't resolve Entity"); - - for (Decl::redecl_iterator I = D->redecls_begin(), - E = D->redecls_end(); I != E; ++I) - TULocHandler.Handle(TULocation(TU, ASTLocation(*I))); - } -}; - -//===----------------------------------------------------------------------===// -// RefEntityAnalyzer Implementation -//===----------------------------------------------------------------------===// - -class RefEntityAnalyzer : public TranslationUnitHandler { - Entity Ent; - TULocationHandler &TULocHandler; - -public: - RefEntityAnalyzer(Entity ent, TULocationHandler &handler) - : Ent(ent), TULocHandler(handler) { } - - virtual void Handle(TranslationUnit *TU) { - assert(TU && "Passed null translation unit"); - - Decl *D = Ent.getDecl(TU->getASTContext()); - assert(D && "Couldn't resolve Entity"); - NamedDecl *ND = dyn_cast(D); - if (!ND) - return; - - DeclReferenceMap &RefMap = TU->getDeclReferenceMap(); - for (DeclReferenceMap::astlocation_iterator - I = RefMap.refs_begin(ND), E = RefMap.refs_end(ND); I != E; ++I) - TULocHandler.Handle(TULocation(TU, *I)); - } -}; - -//===----------------------------------------------------------------------===// -// RefSelectorAnalyzer Implementation -//===----------------------------------------------------------------------===// - -/// \brief Accepts an ObjC method and finds all message expressions that this -/// method may respond to. -class RefSelectorAnalyzer : public TranslationUnitHandler { - Program &Prog; - TULocationHandler &TULocHandler; - - // The original ObjCInterface associated with the method. - Entity IFaceEnt; - GlobalSelector GlobSel; - bool IsInstanceMethod; - - /// \brief Super classes of the ObjCInterface. - typedef llvm::SmallSet EntitiesSetTy; - EntitiesSetTy HierarchyEntities; - -public: - RefSelectorAnalyzer(ObjCMethodDecl *MD, - Program &prog, TULocationHandler &handler) - : Prog(prog), TULocHandler(handler) { - assert(MD); - - // FIXME: Protocol methods. - assert(!isa(MD->getDeclContext()) && - "Protocol methods not supported yet"); - - ObjCInterfaceDecl *IFD = MD->getClassInterface(); - assert(IFD); - IFaceEnt = Entity::get(IFD, Prog); - GlobSel = GlobalSelector::get(MD->getSelector(), Prog); - IsInstanceMethod = MD->isInstanceMethod(); - - for (ObjCInterfaceDecl *Cls = IFD->getSuperClass(); - Cls; Cls = Cls->getSuperClass()) - HierarchyEntities.insert(Entity::get(Cls, Prog)); - } - - virtual void Handle(TranslationUnit *TU) { - assert(TU && "Passed null translation unit"); - - ASTContext &Ctx = TU->getASTContext(); - // Null means it doesn't exist in this translation unit. - ObjCInterfaceDecl *IFace = - cast_or_null(IFaceEnt.getDecl(Ctx)); - Selector Sel = GlobSel.getSelector(Ctx); - - SelectorMap &SelMap = TU->getSelectorMap(); - for (SelectorMap::astlocation_iterator - I = SelMap.refs_begin(Sel), E = SelMap.refs_end(Sel); I != E; ++I) { - if (ValidReference(*I, IFace)) - TULocHandler.Handle(TULocation(TU, *I)); - } - } - - /// \brief Determines whether the given message expression is likely to end - /// up at the given interface decl. - /// - /// It returns true "eagerly", meaning it will return false only if it can - /// "prove" statically that the interface cannot accept this message. - bool ValidReference(ASTLocation ASTLoc, ObjCInterfaceDecl *IFace) { - assert(ASTLoc.isStmt()); - - // FIXME: Finding @selector references should be through another Analyzer - // method, like FindSelectors. - if (isa(ASTLoc.AsStmt())) - return false; - - ObjCInterfaceDecl *MsgD = 0; - ObjCMessageExpr *Msg = cast(ASTLoc.AsStmt()); - - switch (Msg->getReceiverKind()) { - case ObjCMessageExpr::Instance: { - const ObjCObjectPointerType *OPT = - Msg->getInstanceReceiver()->getType()->getAsObjCInterfacePointerType(); - - // Can be anything! Accept it as a possibility.. - if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) - return true; - - // Expecting class method. - if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) - return !IsInstanceMethod; - - MsgD = OPT->getInterfaceDecl(); - assert(MsgD); - - // Should be an instance method. - if (!IsInstanceMethod) - return false; - break; - } - - case ObjCMessageExpr::Class: { - // Expecting class method. - if (IsInstanceMethod) - return false; - - MsgD = Msg->getClassReceiver()->getAs()->getInterface(); - break; - } - - case ObjCMessageExpr::SuperClass: - // Expecting class method. - if (IsInstanceMethod) - return false; - - MsgD = Msg->getSuperType()->getAs()->getInterface(); - break; - - case ObjCMessageExpr::SuperInstance: - // Expecting instance method. - if (!IsInstanceMethod) - return false; - - MsgD = Msg->getSuperType()->getAs() - ->getInterfaceDecl(); - break; - } - - assert(MsgD); - - // Same interface ? We have a winner! - if (declaresSameEntity(MsgD, IFace)) - return true; - - // If the message interface is a superclass of the original interface, - // accept this message as a possibility. - if (HierarchyEntities.count(Entity::get(MsgD, Prog))) - return true; - - // If the message interface is a subclass of the original interface, accept - // the message unless there is a subclass in the hierarchy that will - // "steal" the message (thus the message "will go" to the subclass and not - /// the original interface). - if (IFace) { - Selector Sel = Msg->getSelector(); - for (ObjCInterfaceDecl *Cls = MsgD; Cls; Cls = Cls->getSuperClass()) { - if (declaresSameEntity(Cls, IFace)) - return true; - if (Cls->getMethod(Sel, IsInstanceMethod)) - return false; - } - } - - // The interfaces are unrelated, don't accept the message. - return false; - } -}; - -//===----------------------------------------------------------------------===// -// MessageAnalyzer Implementation -//===----------------------------------------------------------------------===// - -/// \brief Accepts an ObjC message expression and finds all methods that may -/// respond to it. -class MessageAnalyzer : public TranslationUnitHandler { - Program &Prog; - TULocationHandler &TULocHandler; - - // The ObjCInterface associated with the message. Can be null/invalid. - Entity MsgIFaceEnt; - GlobalSelector GlobSel; - bool CanBeInstanceMethod; - bool CanBeClassMethod; - - /// \brief Super classes of the ObjCInterface. - typedef llvm::SmallSet EntitiesSetTy; - EntitiesSetTy HierarchyEntities; - - /// \brief The interface in the message interface hierarchy that "intercepts" - /// the selector. - Entity ReceiverIFaceEnt; - -public: - MessageAnalyzer(ObjCMessageExpr *Msg, - Program &prog, TULocationHandler &handler) - : Prog(prog), TULocHandler(handler), - CanBeInstanceMethod(false), - CanBeClassMethod(false) { - - assert(Msg); - - ObjCInterfaceDecl *MsgD = 0; - - while (true) { - switch (Msg->getReceiverKind()) { - case ObjCMessageExpr::Instance: { - const ObjCObjectPointerType *OPT = - Msg->getInstanceReceiver()->getType() - ->getAsObjCInterfacePointerType(); - - if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) { - CanBeInstanceMethod = CanBeClassMethod = true; - break; - } - - if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) { - CanBeClassMethod = true; - break; - } - - MsgD = OPT->getInterfaceDecl(); - assert(MsgD); - CanBeInstanceMethod = true; - break; - } - - case ObjCMessageExpr::Class: - CanBeClassMethod = true; - MsgD = Msg->getClassReceiver()->getAs()->getInterface(); - break; - - case ObjCMessageExpr::SuperClass: - CanBeClassMethod = true; - MsgD = Msg->getSuperType()->getAs()->getInterface(); - break; - - case ObjCMessageExpr::SuperInstance: - CanBeInstanceMethod = true; - MsgD = Msg->getSuperType()->getAs() - ->getInterfaceDecl(); - break; - } - } - - assert(CanBeInstanceMethod || CanBeClassMethod); - - Selector sel = Msg->getSelector(); - assert(!sel.isNull()); - - MsgIFaceEnt = Entity::get(MsgD, Prog); - GlobSel = GlobalSelector::get(sel, Prog); - - if (MsgD) { - for (ObjCInterfaceDecl *Cls = MsgD->getSuperClass(); - Cls; Cls = Cls->getSuperClass()) - HierarchyEntities.insert(Entity::get(Cls, Prog)); - - // Find the interface in the hierarchy that "receives" the message. - for (ObjCInterfaceDecl *Cls = MsgD; Cls; Cls = Cls->getSuperClass()) { - bool isReceiver = false; - - ObjCInterfaceDecl::lookup_const_iterator Meth, MethEnd; - for (llvm::tie(Meth, MethEnd) = Cls->lookup(sel); - Meth != MethEnd; ++Meth) { - if (ObjCMethodDecl *MD = dyn_cast(*Meth)) - if ((MD->isInstanceMethod() && CanBeInstanceMethod) || - (MD->isClassMethod() && CanBeClassMethod)) { - isReceiver = true; - break; - } - } - - if (isReceiver) { - ReceiverIFaceEnt = Entity::get(Cls, Prog); - break; - } - } - } - } - - virtual void Handle(TranslationUnit *TU) { - assert(TU && "Passed null translation unit"); - ASTContext &Ctx = TU->getASTContext(); - - // Null means it doesn't exist in this translation unit or there was no - // interface that was determined to receive the original message. - ObjCInterfaceDecl *ReceiverIFace = - cast_or_null(ReceiverIFaceEnt.getDecl(Ctx)); - - // No subclass for the original receiver interface, so it remains the - // receiver. - if (ReceiverIFaceEnt.isValid() && ReceiverIFace == 0) - return; - - // Null means it doesn't exist in this translation unit or there was no - // interface associated with the message in the first place. - ObjCInterfaceDecl *MsgIFace = - cast_or_null(MsgIFaceEnt.getDecl(Ctx)); - - Selector Sel = GlobSel.getSelector(Ctx); - SelectorMap &SelMap = TU->getSelectorMap(); - for (SelectorMap::method_iterator - I = SelMap.methods_begin(Sel), E = SelMap.methods_end(Sel); - I != E; ++I) { - ObjCMethodDecl *D = *I; - if (ValidMethod(D, MsgIFace, ReceiverIFace)) { - for (ObjCMethodDecl::redecl_iterator - RI = D->redecls_begin(), RE = D->redecls_end(); RI != RE; ++RI) - TULocHandler.Handle(TULocation(TU, ASTLocation(*RI))); - } - } - } - - /// \brief Determines whether the given method is likely to accept the - /// original message. - /// - /// It returns true "eagerly", meaning it will return false only if it can - /// "prove" statically that the method cannot accept the original message. - bool ValidMethod(ObjCMethodDecl *D, ObjCInterfaceDecl *MsgIFace, - ObjCInterfaceDecl *ReceiverIFace) { - assert(D); - - // FIXME: Protocol methods ? - if (isa(D->getDeclContext())) - return false; - - // No specific interface associated with the message. Can be anything. - if (MsgIFaceEnt.isInvalid()) - return true; - - if ((!CanBeInstanceMethod && D->isInstanceMethod()) || - (!CanBeClassMethod && D->isClassMethod())) - return false; - - ObjCInterfaceDecl *IFace = D->getClassInterface(); - assert(IFace); - - // If the original message interface is the same or a superclass of the - // given interface, accept the method as a possibility. - if (MsgIFace && MsgIFace->isSuperClassOf(IFace)) - return true; - - if (ReceiverIFace) { - // The given interface, "overrides" the receiver. - if (ReceiverIFace->isSuperClassOf(IFace)) - return true; - } else { - // No receiver was found for the original message. - assert(ReceiverIFaceEnt.isInvalid()); - - // If the original message interface is a subclass of the given interface, - // accept the message. - if (HierarchyEntities.count(Entity::get(IFace, Prog))) - return true; - } - - // The interfaces are unrelated, or the receiver interface wasn't - // "overriden". - return false; - } -}; - -} // end anonymous namespace - -//===----------------------------------------------------------------------===// -// Analyzer Implementation -//===----------------------------------------------------------------------===// - -void Analyzer::FindDeclarations(Decl *D, TULocationHandler &Handler) { - assert(D && "Passed null declaration"); - Entity Ent = Entity::get(D, Prog); - if (Ent.isInvalid()) - return; - - DeclEntityAnalyzer DEA(Ent, Handler); - Idxer.GetTranslationUnitsFor(Ent, DEA); -} - -void Analyzer::FindReferences(Decl *D, TULocationHandler &Handler) { - assert(D && "Passed null declaration"); - if (ObjCMethodDecl *MD = dyn_cast(D)) { - RefSelectorAnalyzer RSA(MD, Prog, Handler); - GlobalSelector Sel = GlobalSelector::get(MD->getSelector(), Prog); - Idxer.GetTranslationUnitsFor(Sel, RSA); - return; - } - - Entity Ent = Entity::get(D, Prog); - if (Ent.isInvalid()) - return; - - RefEntityAnalyzer REA(Ent, Handler); - Idxer.GetTranslationUnitsFor(Ent, REA); -} - -/// \brief Find methods that may respond to the given message and pass them -/// to Handler. -void Analyzer::FindObjCMethods(ObjCMessageExpr *Msg, - TULocationHandler &Handler) { - assert(Msg); - MessageAnalyzer MsgAnalyz(Msg, Prog, Handler); - GlobalSelector GlobSel = GlobalSelector::get(Msg->getSelector(), Prog); - Idxer.GetTranslationUnitsFor(GlobSel, MsgAnalyz); -} diff --git a/lib/Index/CMakeLists.txt b/lib/Index/CMakeLists.txt deleted file mode 100644 index 9bf35e5efe4d..000000000000 --- a/lib/Index/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -set(LLVM_USED_LIBS clangBasic clangAST) - -add_clang_library(clangIndex - ASTLocation.cpp - Analyzer.cpp - GlobalCallGraph.cpp - DeclReferenceMap.cpp - Entity.cpp - GlobalSelector.cpp - Handlers.cpp - IndexProvider.cpp - Indexer.cpp - Program.cpp - SelectorMap.cpp - ) - -add_dependencies(clangIndex ClangAttrClasses ClangAttrList - ClangDeclNodes ClangStmtNodes) diff --git a/lib/Index/DeclReferenceMap.cpp b/lib/Index/DeclReferenceMap.cpp deleted file mode 100644 index 3fd4336230e2..000000000000 --- a/lib/Index/DeclReferenceMap.cpp +++ /dev/null @@ -1,90 +0,0 @@ -//===--- DeclReferenceMap.cpp - Map Decls to their references -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// DeclReferenceMap creates a mapping from Decls to the ASTLocations that -// reference them. -// -//===----------------------------------------------------------------------===// - -#include "clang/Index/DeclReferenceMap.h" -#include "clang/Index/ASTLocation.h" -#include "ASTVisitor.h" -using namespace clang; -using namespace idx; - -namespace { - -class RefMapper : public ASTVisitor { - DeclReferenceMap::MapTy ⤅ - -public: - RefMapper(DeclReferenceMap::MapTy &map) : Map(map) { } - - void VisitDeclRefExpr(DeclRefExpr *Node); - void VisitMemberExpr(MemberExpr *Node); - void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); - - void VisitTypedefTypeLoc(TypedefTypeLoc TL); - void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL); -}; - -} // anonymous namespace - -//===----------------------------------------------------------------------===// -// RefMapper Implementation -//===----------------------------------------------------------------------===// - -void RefMapper::VisitDeclRefExpr(DeclRefExpr *Node) { - NamedDecl *PrimD = cast(Node->getDecl()->getCanonicalDecl()); - Map.insert(std::make_pair(PrimD, ASTLocation(CurrentDecl, Node))); -} - -void RefMapper::VisitMemberExpr(MemberExpr *Node) { - NamedDecl *PrimD = cast(Node->getMemberDecl()->getCanonicalDecl()); - Map.insert(std::make_pair(PrimD, ASTLocation(CurrentDecl, Node))); -} - -void RefMapper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { - Map.insert(std::make_pair(Node->getDecl(), ASTLocation(CurrentDecl, Node))); -} - -void RefMapper::VisitTypedefTypeLoc(TypedefTypeLoc TL) { - NamedDecl *ND = TL.getTypedefNameDecl(); - Map.insert(std::make_pair(ND, ASTLocation(CurrentDecl, ND, TL.getNameLoc()))); -} - -void RefMapper::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { - NamedDecl *ND = TL.getIFaceDecl(); - Map.insert(std::make_pair(ND, ASTLocation(CurrentDecl, ND, TL.getNameLoc()))); -} - -//===----------------------------------------------------------------------===// -// DeclReferenceMap Implementation -//===----------------------------------------------------------------------===// - -DeclReferenceMap::DeclReferenceMap(ASTContext &Ctx) { - RefMapper(Map).Visit(Ctx.getTranslationUnitDecl()); -} - -DeclReferenceMap::astlocation_iterator -DeclReferenceMap::refs_begin(NamedDecl *D) const { - NamedDecl *Prim = cast(D->getCanonicalDecl()); - return astlocation_iterator(Map.lower_bound(Prim)); -} - -DeclReferenceMap::astlocation_iterator -DeclReferenceMap::refs_end(NamedDecl *D) const { - NamedDecl *Prim = cast(D->getCanonicalDecl()); - return astlocation_iterator(Map.upper_bound(Prim)); -} - -bool DeclReferenceMap::refs_empty(NamedDecl *D) const { - NamedDecl *Prim = cast(D->getCanonicalDecl()); - return refs_begin(Prim) == refs_end(Prim); -} diff --git a/lib/Index/Entity.cpp b/lib/Index/Entity.cpp deleted file mode 100644 index fbab6d8684fd..000000000000 --- a/lib/Index/Entity.cpp +++ /dev/null @@ -1,270 +0,0 @@ -//===--- Entity.cpp - Cross-translation-unit "token" for decls ------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Entity is a ASTContext-independent way to refer to declarations that are -// visible across translation units. -// -//===----------------------------------------------------------------------===// - -#include "EntityImpl.h" -#include "ProgramImpl.h" -#include "clang/Index/Program.h" -#include "clang/Index/GlobalSelector.h" -#include "clang/AST/Decl.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/DeclVisitor.h" -using namespace clang; -using namespace idx; - -// FIXME: Entity is really really basic currently, mostly written to work -// on variables and functions. Should support types and other decls eventually.. - - -//===----------------------------------------------------------------------===// -// EntityGetter -//===----------------------------------------------------------------------===// - -namespace clang { -namespace idx { - -/// \brief Gets the Entity associated with a Decl. -class EntityGetter : public DeclVisitor { - Program &Prog; - ProgramImpl &ProgImpl; - -public: - EntityGetter(Program &prog, ProgramImpl &progImpl) - : Prog(prog), ProgImpl(progImpl) { } - - // Get an Entity. - Entity getEntity(Entity Parent, DeclarationName Name, - unsigned IdNS, bool isObjCInstanceMethod); - - // Get an Entity associated with the name in the global namespace. - Entity getGlobalEntity(StringRef Name); - - Entity VisitNamedDecl(NamedDecl *D); - Entity VisitVarDecl(VarDecl *D); - Entity VisitFieldDecl(FieldDecl *D); - Entity VisitFunctionDecl(FunctionDecl *D); - Entity VisitTypeDecl(TypeDecl *D); -}; - -} -} - -Entity EntityGetter::getEntity(Entity Parent, DeclarationName Name, - unsigned IdNS, bool isObjCInstanceMethod) { - llvm::FoldingSetNodeID ID; - EntityImpl::Profile(ID, Parent, Name, IdNS, isObjCInstanceMethod); - - ProgramImpl::EntitySetTy &Entities = ProgImpl.getEntities(); - void *InsertPos = 0; - if (EntityImpl *Ent = Entities.FindNodeOrInsertPos(ID, InsertPos)) - return Entity(Ent); - - void *Buf = ProgImpl.Allocate(sizeof(EntityImpl)); - EntityImpl *New = - new (Buf) EntityImpl(Parent, Name, IdNS, isObjCInstanceMethod); - Entities.InsertNode(New, InsertPos); - - return Entity(New); -} - -Entity EntityGetter::getGlobalEntity(StringRef Name) { - IdentifierInfo *II = &ProgImpl.getIdents().get(Name); - DeclarationName GlobName(II); - unsigned IdNS = Decl::IDNS_Ordinary; - return getEntity(Entity(), GlobName, IdNS, false); -} - -Entity EntityGetter::VisitNamedDecl(NamedDecl *D) { - Entity Parent; - if (!D->getDeclContext()->isTranslationUnit()) { - Parent = Visit(cast(D->getDeclContext())); - // FIXME: Anonymous structs ? - if (Parent.isInvalid()) - return Entity(); - } - if (Parent.isValid() && Parent.isInternalToTU()) - return Entity(D); - - // FIXME: Only works for DeclarationNames that are identifiers and selectors. - // Treats other DeclarationNames as internal Decls for now.. - - DeclarationName LocalName = D->getDeclName(); - if (!LocalName) - return Entity(D); - - DeclarationName GlobName; - - if (IdentifierInfo *II = LocalName.getAsIdentifierInfo()) { - IdentifierInfo *GlobII = &ProgImpl.getIdents().get(II->getName()); - GlobName = DeclarationName(GlobII); - } else { - Selector LocalSel = LocalName.getObjCSelector(); - - // Treats other DeclarationNames as internal Decls for now.. - if (LocalSel.isNull()) - return Entity(D); - - Selector GlobSel = - (uintptr_t)GlobalSelector::get(LocalSel, Prog).getAsOpaquePtr(); - GlobName = DeclarationName(GlobSel); - } - - assert(GlobName); - - unsigned IdNS = D->getIdentifierNamespace(); - - ObjCMethodDecl *MD = dyn_cast(D); - bool isObjCInstanceMethod = MD && MD->isInstanceMethod(); - return getEntity(Parent, GlobName, IdNS, isObjCInstanceMethod); -} - -Entity EntityGetter::VisitVarDecl(VarDecl *D) { - // Local variables have no linkage, make invalid Entities. - if (D->hasLocalStorage()) - return Entity(); - - // If it's static it cannot be referred to by another translation unit. - if (D->getStorageClass() == SC_Static) - return Entity(D); - - return VisitNamedDecl(D); -} - -Entity EntityGetter::VisitFunctionDecl(FunctionDecl *D) { - // If it's static it cannot be referred to by another translation unit. - if (D->getStorageClass() == SC_Static) - return Entity(D); - - return VisitNamedDecl(D); -} - -Entity EntityGetter::VisitFieldDecl(FieldDecl *D) { - // Make FieldDecl an invalid Entity since it has no linkage. - return Entity(); -} - -Entity EntityGetter::VisitTypeDecl(TypeDecl *D) { - // Although in C++ class name has external linkage, usually the definition of - // the class is available in the same translation unit when it's needed. So we - // make all of them invalid Entity. - return Entity(); -} - -//===----------------------------------------------------------------------===// -// EntityImpl Implementation -//===----------------------------------------------------------------------===// - -Decl *EntityImpl::getDecl(ASTContext &AST) { - DeclContext *DC = - Parent.isInvalid() ? AST.getTranslationUnitDecl() - : cast(Parent.getDecl(AST)); - if (!DC) - return 0; // Couldn't get the parent context. - - DeclarationName LocalName; - - if (IdentifierInfo *GlobII = Name.getAsIdentifierInfo()) { - IdentifierInfo &II = AST.Idents.get(GlobII->getName()); - LocalName = DeclarationName(&II); - } else { - Selector GlobSel = Name.getObjCSelector(); - assert(!GlobSel.isNull() && "A not handled yet declaration name"); - GlobalSelector GSel = - GlobalSelector::getFromOpaquePtr(GlobSel.getAsOpaquePtr()); - LocalName = GSel.getSelector(AST); - } - - assert(LocalName); - - DeclContext::lookup_result Res = DC->lookup(LocalName); - for (DeclContext::lookup_iterator I = Res.first, E = Res.second; I!=E; ++I) { - Decl *D = *I; - if (D->getIdentifierNamespace() == IdNS) { - if (ObjCMethodDecl *MD = dyn_cast(D)) { - if (MD->isInstanceMethod() == IsObjCInstanceMethod) - return MD; - } else - return D; - } - } - - return 0; // Failed to find a decl using this Entity. -} - -/// \brief Get an Entity associated with the given Decl. -/// \returns Null if an Entity cannot refer to this Decl. -Entity EntityImpl::get(Decl *D, Program &Prog, ProgramImpl &ProgImpl) { - assert(D && "Passed null Decl"); - return EntityGetter(Prog, ProgImpl).Visit(D); -} - -/// \brief Get an Entity associated with a global name. -Entity EntityImpl::get(StringRef Name, Program &Prog, - ProgramImpl &ProgImpl) { - return EntityGetter(Prog, ProgImpl).getGlobalEntity(Name); -} - -std::string EntityImpl::getPrintableName() { - return Name.getAsString(); -} - -//===----------------------------------------------------------------------===// -// Entity Implementation -//===----------------------------------------------------------------------===// - -Entity::Entity(Decl *D) : Val(D->getCanonicalDecl()) { } - -/// \brief Find the Decl that can be referred to by this entity. -Decl *Entity::getDecl(ASTContext &AST) const { - if (isInvalid()) - return 0; - - if (Decl *D = Val.dyn_cast()) - // Check that the passed AST is actually the one that this Decl belongs to. - return (&D->getASTContext() == &AST) ? D : 0; - - return Val.get()->getDecl(AST); -} - -std::string Entity::getPrintableName() const { - if (isInvalid()) - return "<< Invalid >>"; - - if (Decl *D = Val.dyn_cast()) { - if (NamedDecl *ND = dyn_cast(D)) - return ND->getNameAsString(); - else - return std::string(); - } - - return Val.get()->getPrintableName(); -} - -/// \brief Get an Entity associated with the given Decl. -/// \returns Null if an Entity cannot refer to this Decl. -Entity Entity::get(Decl *D, Program &Prog) { - if (D == 0) - return Entity(); - ProgramImpl &ProgImpl = *static_cast(Prog.Impl); - return EntityImpl::get(D, Prog, ProgImpl); -} - -Entity Entity::get(StringRef Name, Program &Prog) { - ProgramImpl &ProgImpl = *static_cast(Prog.Impl); - return EntityImpl::get(Name, Prog, ProgImpl); -} - -unsigned -llvm::DenseMapInfo::getHashValue(Entity E) { - return DenseMapInfo::getHashValue(E.getAsOpaquePtr()); -} diff --git a/lib/Index/EntityImpl.h b/lib/Index/EntityImpl.h deleted file mode 100644 index 6d6a0c6d2b69..000000000000 --- a/lib/Index/EntityImpl.h +++ /dev/null @@ -1,71 +0,0 @@ -//===--- EntityImpl.h - Internal Entity implementation---------*- C++ -*-=====// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Internal implementation for the Entity class -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INDEX_ENTITYIMPL_H -#define LLVM_CLANG_INDEX_ENTITYIMPL_H - -#include "clang/Index/Entity.h" -#include "clang/AST/DeclarationName.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/StringSet.h" - -namespace clang { - -namespace idx { - class ProgramImpl; - -class EntityImpl : public llvm::FoldingSetNode { - Entity Parent; - DeclarationName Name; - - /// \brief Identifier namespace. - unsigned IdNS; - - /// \brief If Name is a selector, this keeps track whether it's for an - /// instance method. - bool IsObjCInstanceMethod; - -public: - EntityImpl(Entity parent, DeclarationName name, unsigned idNS, - bool isObjCInstanceMethod) - : Parent(parent), Name(name), IdNS(idNS), - IsObjCInstanceMethod(isObjCInstanceMethod) { } - - /// \brief Find the Decl that can be referred to by this entity. - Decl *getDecl(ASTContext &AST); - - /// \brief Get an Entity associated with the given Decl. - /// \returns Null if an Entity cannot refer to this Decl. - static Entity get(Decl *D, Program &Prog, ProgramImpl &ProgImpl); - static Entity get(StringRef Name, Program &Prog, ProgramImpl &ProgImpl); - - std::string getPrintableName(); - - void Profile(llvm::FoldingSetNodeID &ID) const { - Profile(ID, Parent, Name, IdNS, IsObjCInstanceMethod); - } - static void Profile(llvm::FoldingSetNodeID &ID, Entity Parent, - DeclarationName Name, unsigned IdNS, - bool isObjCInstanceMethod) { - ID.AddPointer(Parent.getAsOpaquePtr()); - ID.AddPointer(Name.getAsOpaquePtr()); - ID.AddInteger(IdNS); - ID.AddBoolean(isObjCInstanceMethod); - } -}; - -} // namespace idx - -} // namespace clang - -#endif diff --git a/lib/Index/GlobalCallGraph.cpp b/lib/Index/GlobalCallGraph.cpp deleted file mode 100644 index a21b52ae6027..000000000000 --- a/lib/Index/GlobalCallGraph.cpp +++ /dev/null @@ -1,152 +0,0 @@ -//== GlobalCallGraph.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/Index/GlobalCallGraph.h" - -#include "clang/AST/ASTContext.h" -#include "clang/AST/StmtVisitor.h" - -#include "llvm/Support/GraphWriter.h" - -using namespace clang::idx; -using clang::FunctionDecl; -using clang::DeclContext; -using clang::ASTContext; - -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_range I = S->children(); I; ++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(Program &P) : Prog(P), 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(ASTContext& Ctx) { - 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->doesThisDeclarationHaveABody()) { - // 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(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(); - } - os << '\n'; - } - } -} - -void CallGraph::dump() { - print(llvm::errs()); -} - -void CallGraph::ViewCallGraph() const { - llvm::ViewGraph(*this, "CallGraph"); -} - -namespace llvm { - -template <> -struct DOTGraphTraits : public DefaultDOTGraphTraits { - - DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} - - static std::string getNodeLabel(const CallGraphNode *Node, - const CallGraph &CG) { - return Node->getName(); - - } - -}; - -} diff --git a/lib/Index/GlobalSelector.cpp b/lib/Index/GlobalSelector.cpp deleted file mode 100644 index 2fe6f95ec9be..000000000000 --- a/lib/Index/GlobalSelector.cpp +++ /dev/null @@ -1,71 +0,0 @@ -//===-- GlobalSelector.cpp - Cross-translation-unit "token" for selectors -===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// GlobalSelector is a ASTContext-independent way to refer to selectors. -// -//===----------------------------------------------------------------------===// - -#include "clang/Index/GlobalSelector.h" -#include "ProgramImpl.h" -#include "clang/Index/Program.h" -#include "clang/AST/ASTContext.h" -using namespace clang; -using namespace idx; - -/// \brief Get the ASTContext-specific selector. -Selector GlobalSelector::getSelector(ASTContext &AST) const { - if (isInvalid()) - return Selector(); - - Selector GlobSel = Selector(reinterpret_cast(Val)); - - SmallVector Ids; - for (unsigned i = 0, e = GlobSel.isUnarySelector() ? 1 : GlobSel.getNumArgs(); - i != e; ++i) { - IdentifierInfo *GlobII = GlobSel.getIdentifierInfoForSlot(i); - IdentifierInfo *II = &AST.Idents.get(GlobII->getName()); - Ids.push_back(II); - } - - return AST.Selectors.getSelector(GlobSel.getNumArgs(), Ids.data()); -} - -/// \brief Get a printable name for debugging purpose. -std::string GlobalSelector::getPrintableName() const { - if (isInvalid()) - return "<< Invalid >>"; - - Selector GlobSel = Selector(reinterpret_cast(Val)); - return GlobSel.getAsString(); -} - -/// \brief Get a GlobalSelector for the ASTContext-specific selector. -GlobalSelector GlobalSelector::get(Selector Sel, Program &Prog) { - if (Sel.isNull()) - return GlobalSelector(); - - ProgramImpl &ProgImpl = *static_cast(Prog.Impl); - - SmallVector Ids; - for (unsigned i = 0, e = Sel.isUnarySelector() ? 1 : Sel.getNumArgs(); - i != e; ++i) { - IdentifierInfo *II = Sel.getIdentifierInfoForSlot(i); - IdentifierInfo *GlobII = &ProgImpl.getIdents().get(II->getName()); - Ids.push_back(GlobII); - } - - Selector GlobSel = ProgImpl.getSelectors().getSelector(Sel.getNumArgs(), - Ids.data()); - return GlobalSelector(GlobSel.getAsOpaquePtr()); -} - -unsigned -llvm::DenseMapInfo::getHashValue(GlobalSelector Sel) { - return DenseMapInfo::getHashValue(Sel.getAsOpaquePtr()); -} diff --git a/lib/Index/Handlers.cpp b/lib/Index/Handlers.cpp deleted file mode 100644 index 1e9a27d297c3..000000000000 --- a/lib/Index/Handlers.cpp +++ /dev/null @@ -1,22 +0,0 @@ -//===--- Handlers.cpp - Interfaces for receiving information ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Abstract interfaces for receiving information. -// -//===----------------------------------------------------------------------===// - -#include "clang/Index/Handlers.h" -#include "clang/Index/Entity.h" -using namespace clang; -using namespace idx; - -// Out-of-line to give the virtual tables a home. -EntityHandler::~EntityHandler() { } -TranslationUnitHandler::~TranslationUnitHandler() { } -TULocationHandler::~TULocationHandler() { } diff --git a/lib/Index/IndexProvider.cpp b/lib/Index/IndexProvider.cpp deleted file mode 100644 index eea098875707..000000000000 --- a/lib/Index/IndexProvider.cpp +++ /dev/null @@ -1,20 +0,0 @@ -//===- IndexProvider.cpp - Maps information to translation units -*- C++ -*-==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Maps information to TranslationUnits. -// -//===----------------------------------------------------------------------===// - -#include "clang/Index/IndexProvider.h" -#include "clang/Index/Entity.h" -using namespace clang; -using namespace idx; - -// Out-of-line to give the virtual table a home. -IndexProvider::~IndexProvider() { } diff --git a/lib/Index/Indexer.cpp b/lib/Index/Indexer.cpp deleted file mode 100644 index ebba43c4747e..000000000000 --- a/lib/Index/Indexer.cpp +++ /dev/null @@ -1,121 +0,0 @@ -//===--- Indexer.cpp - IndexProvider implementation -------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// IndexProvider implementation. -// -//===----------------------------------------------------------------------===// - -#include "clang/Index/Indexer.h" -#include "clang/Index/Program.h" -#include "clang/Index/Handlers.h" -#include "clang/Index/TranslationUnit.h" -#include "ASTVisitor.h" -#include "clang/AST/DeclBase.h" -using namespace clang; -using namespace idx; - -namespace { - -class EntityIndexer : public EntityHandler { - TranslationUnit *TU; - Indexer::MapTy ⤅ - Indexer::DefMapTy &DefMap; - -public: - EntityIndexer(TranslationUnit *tu, Indexer::MapTy &map, - Indexer::DefMapTy &defmap) - : TU(tu), Map(map), DefMap(defmap) { } - - virtual void Handle(Entity Ent) { - if (Ent.isInternalToTU()) - return; - Map[Ent].insert(TU); - - Decl *D = Ent.getDecl(TU->getASTContext()); - if (FunctionDecl *FD = dyn_cast(D)) - if (FD->doesThisDeclarationHaveABody()) - DefMap[Ent] = std::make_pair(FD, TU); - } -}; - -class SelectorIndexer : public ASTVisitor { - Program &Prog; - TranslationUnit *TU; - Indexer::SelMapTy ⤅ - -public: - SelectorIndexer(Program &prog, TranslationUnit *tu, Indexer::SelMapTy &map) - : Prog(prog), TU(tu), Map(map) { } - - void VisitObjCMethodDecl(ObjCMethodDecl *D) { - Map[GlobalSelector::get(D->getSelector(), Prog)].insert(TU); - Base::VisitObjCMethodDecl(D); - } - - void VisitObjCMessageExpr(ObjCMessageExpr *Node) { - Map[GlobalSelector::get(Node->getSelector(), Prog)].insert(TU); - Base::VisitObjCMessageExpr(Node); - } -}; - -} // anonymous namespace - -void Indexer::IndexAST(TranslationUnit *TU) { - assert(TU && "Passed null TranslationUnit"); - ASTContext &Ctx = TU->getASTContext(); - CtxTUMap[&Ctx] = TU; - EntityIndexer Idx(TU, Map, DefMap); - Prog.FindEntities(Ctx, Idx); - - SelectorIndexer SelIdx(Prog, TU, SelMap); - SelIdx.Visit(Ctx.getTranslationUnitDecl()); -} - -void Indexer::GetTranslationUnitsFor(Entity Ent, - TranslationUnitHandler &Handler) { - assert(Ent.isValid() && "Expected valid Entity"); - - if (Ent.isInternalToTU()) { - Decl *D = Ent.getInternalDecl(); - CtxTUMapTy::iterator I = CtxTUMap.find(&D->getASTContext()); - if (I != CtxTUMap.end()) - Handler.Handle(I->second); - return; - } - - MapTy::iterator I = Map.find(Ent); - if (I == Map.end()) - return; - - TUSetTy &Set = I->second; - for (TUSetTy::iterator I = Set.begin(), E = Set.end(); I != E; ++I) - Handler.Handle(*I); -} - -void Indexer::GetTranslationUnitsFor(GlobalSelector Sel, - TranslationUnitHandler &Handler) { - assert(Sel.isValid() && "Expected valid GlobalSelector"); - - SelMapTy::iterator I = SelMap.find(Sel); - if (I == SelMap.end()) - return; - - TUSetTy &Set = I->second; - for (TUSetTy::iterator I = Set.begin(), E = Set.end(); I != E; ++I) - Handler.Handle(*I); -} - -std::pair -Indexer::getDefinitionFor(Entity Ent) { - DefMapTy::iterator I = DefMap.find(Ent); - if (I == DefMap.end()) - return std::make_pair((FunctionDecl *)0, (TranslationUnit *)0); - else - return I->second; -} diff --git a/lib/Index/Makefile b/lib/Index/Makefile deleted file mode 100644 index 8607d781e5d7..000000000000 --- a/lib/Index/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -##===- clang/lib/Index/Makefile ----------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# This implements the Indexer library for the C-Language front-end. -# -##===----------------------------------------------------------------------===## - -CLANG_LEVEL := ../.. -LIBRARYNAME := clangIndex - -include $(CLANG_LEVEL)/Makefile - diff --git a/lib/Index/Program.cpp b/lib/Index/Program.cpp deleted file mode 100644 index 4efad2c5e92b..000000000000 --- a/lib/Index/Program.cpp +++ /dev/null @@ -1,50 +0,0 @@ -//===--- Program.cpp - Entity originator and misc -------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Storage for Entities and utility functions -// -//===----------------------------------------------------------------------===// - -#include "clang/Index/Program.h" -#include "ProgramImpl.h" -#include "clang/Index/Handlers.h" -#include "clang/Index/TranslationUnit.h" -#include "clang/AST/DeclBase.h" -#include "clang/AST/ASTContext.h" -#include "llvm/Support/raw_ostream.h" -using namespace clang; -using namespace idx; - -// Out-of-line to give the virtual tables a home. -TranslationUnit::~TranslationUnit() { } - -Program::Program() : Impl(new ProgramImpl()) { } - -Program::~Program() { - delete static_cast(Impl); -} - -static void FindEntitiesInDC(DeclContext *DC, Program &Prog, - EntityHandler &Handler) { - for (DeclContext::decl_iterator - I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { - if (I->getLocation().isInvalid()) - continue; - Entity Ent = Entity::get(*I, Prog); - if (Ent.isValid()) - Handler.Handle(Ent); - if (DeclContext *SubDC = dyn_cast(*I)) - FindEntitiesInDC(SubDC, Prog, Handler); - } -} - -/// \brief Traverses the AST and passes all the entities to the Handler. -void Program::FindEntities(ASTContext &Ctx, EntityHandler &Handler) { - FindEntitiesInDC(Ctx.getTranslationUnitDecl(), *this, Handler); -} diff --git a/lib/Index/ProgramImpl.h b/lib/Index/ProgramImpl.h deleted file mode 100644 index 57b9ce3115e9..000000000000 --- a/lib/Index/ProgramImpl.h +++ /dev/null @@ -1,56 +0,0 @@ -//===--- ProgramImpl.h - Internal Program implementation---------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Internal implementation for the Program class -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INDEX_PROGRAMIMPL_H -#define LLVM_CLANG_INDEX_PROGRAMIMPL_H - -#include "EntityImpl.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/LangOptions.h" - -namespace clang { - -namespace idx { - class EntityListener; - -class ProgramImpl { -public: - typedef llvm::FoldingSet EntitySetTy; - -private: - EntitySetTy Entities; - llvm::BumpPtrAllocator BumpAlloc; - - IdentifierTable Identifiers; - SelectorTable Selectors; - - ProgramImpl(const ProgramImpl&); // do not implement - ProgramImpl &operator=(const ProgramImpl &); // do not implement - -public: - ProgramImpl() : Identifiers(LangOptions()) { } - - EntitySetTy &getEntities() { return Entities; } - IdentifierTable &getIdents() { return Identifiers; } - SelectorTable &getSelectors() { return Selectors; } - - void *Allocate(unsigned Size, unsigned Align = 8) { - return BumpAlloc.Allocate(Size, Align); - } -}; - -} // namespace idx - -} // namespace clang - -#endif diff --git a/lib/Index/SelectorMap.cpp b/lib/Index/SelectorMap.cpp deleted file mode 100644 index 0f11e31a0dec..000000000000 --- a/lib/Index/SelectorMap.cpp +++ /dev/null @@ -1,84 +0,0 @@ -//===- SelectorMap.cpp - Maps selectors to methods and messages -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// SelectorMap creates a mapping from selectors to ObjC method declarations -// and ObjC message expressions. -// -//===----------------------------------------------------------------------===// - -#include "clang/Index/SelectorMap.h" -#include "ASTVisitor.h" -using namespace clang; -using namespace idx; - -namespace { - -class SelMapper : public ASTVisitor { - SelectorMap::SelMethMapTy &SelMethMap; - SelectorMap::SelRefMapTy &SelRefMap; - -public: - SelMapper(SelectorMap::SelMethMapTy &MethMap, - SelectorMap::SelRefMapTy &RefMap) - : SelMethMap(MethMap), SelRefMap(RefMap) { } - - void VisitObjCMethodDecl(ObjCMethodDecl *D); - void VisitObjCMessageExpr(ObjCMessageExpr *Node); - void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); -}; - -} // anonymous namespace - -//===----------------------------------------------------------------------===// -// SelMapper Implementation -//===----------------------------------------------------------------------===// - -void SelMapper::VisitObjCMethodDecl(ObjCMethodDecl *D) { - if (D->getCanonicalDecl() == D) - SelMethMap.insert(std::make_pair(D->getSelector(), D)); - Base::VisitObjCMethodDecl(D); -} - -void SelMapper::VisitObjCMessageExpr(ObjCMessageExpr *Node) { - ASTLocation ASTLoc(CurrentDecl, Node); - SelRefMap.insert(std::make_pair(Node->getSelector(), ASTLoc)); -} - -void SelMapper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { - ASTLocation ASTLoc(CurrentDecl, Node); - SelRefMap.insert(std::make_pair(Node->getSelector(), ASTLoc)); -} - -//===----------------------------------------------------------------------===// -// SelectorMap Implementation -//===----------------------------------------------------------------------===// - -SelectorMap::SelectorMap(ASTContext &Ctx) { - SelMapper(SelMethMap, SelRefMap).Visit(Ctx.getTranslationUnitDecl()); -} - -SelectorMap::method_iterator -SelectorMap::methods_begin(Selector Sel) const { - return method_iterator(SelMethMap.lower_bound(Sel)); -} - -SelectorMap::method_iterator -SelectorMap::methods_end(Selector Sel) const { - return method_iterator(SelMethMap.upper_bound(Sel)); -} - -SelectorMap::astlocation_iterator -SelectorMap::refs_begin(Selector Sel) const { - return astlocation_iterator(SelRefMap.lower_bound(Sel)); -} - -SelectorMap::astlocation_iterator -SelectorMap::refs_end(Selector Sel) const { - return astlocation_iterator(SelRefMap.upper_bound(Sel)); -} diff --git a/lib/Makefile b/lib/Makefile index a73c6e6d62e9..2eb72a91e68b 100755 --- a/lib/Makefile +++ b/lib/Makefile @@ -10,7 +10,7 @@ CLANG_LEVEL := .. PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis \ StaticAnalyzer Edit Rewrite ARCMigrate Serialization Frontend \ - FrontendTool Tooling Index Driver + FrontendTool Tooling Driver include $(CLANG_LEVEL)/Makefile diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index c000f69e6e15..f04d76723b6f 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -59,7 +59,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, } } - HandleMemberFunctionDefaultArgs(D, FnD); + HandleMemberFunctionDeclDelays(D, FnD); D.complete(FnD); @@ -348,6 +348,77 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { LM.DefaultArgs[I].Toks = 0; } } + + // Parse a delayed exception-specification, if there is one. + if (CachedTokens *Toks = LM.ExceptionSpecTokens) { + // Save the current token position. + SourceLocation origLoc = Tok.getLocation(); + + // Parse the default argument from its saved token stream. + Toks->push_back(Tok); // So that the current token doesn't get lost + PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false); + + // Consume the previously-pushed token. + ConsumeAnyToken(); + + // C++11 [expr.prim.general]p3: + // If a declaration declares a member function or member function + // template of a class X, the expression this is a prvalue of type + // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq + // and the end of the function-definition, member-declarator, or + // declarator. + CXXMethodDecl *Method; + if (FunctionTemplateDecl *FunTmpl + = dyn_cast(LM.Method)) + Method = cast(FunTmpl->getTemplatedDecl()); + else + Method = cast(LM.Method); + + Sema::CXXThisScopeRAII ThisScope(Actions, Method->getParent(), + Method->getTypeQualifiers(), + getLangOpts().CPlusPlus0x); + + // Parse the exception-specification. + SourceRange SpecificationRange; + SmallVector DynamicExceptions; + SmallVector DynamicExceptionRanges; + ExprResult NoexceptExpr; + CachedTokens *ExceptionSpecTokens; + + ExceptionSpecificationType EST + = tryParseExceptionSpecification(/*Delayed=*/false, SpecificationRange, + DynamicExceptions, + DynamicExceptionRanges, NoexceptExpr, + ExceptionSpecTokens); + + // Clean up the remaining tokens. + if (Tok.is(tok::cxx_exceptspec_end)) + ConsumeToken(); + else if (EST != EST_None) + Diag(Tok.getLocation(), diag::err_except_spec_unparsed); + + // Attach the exception-specification to the method. + if (EST != EST_None) + Actions.actOnDelayedExceptionSpecification(LM.Method, EST, + SpecificationRange, + DynamicExceptions, + DynamicExceptionRanges, + NoexceptExpr.isUsable()? + NoexceptExpr.get() : 0); + + assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, + Tok.getLocation()) && + "tryParseExceptionSpecification went over the exception tokens!"); + + // There could be leftover tokens (e.g. because of an error). + // Skip through until we reach the original token position. + while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) + ConsumeAnyToken(); + + delete LM.ExceptionSpecTokens; + LM.ExceptionSpecTokens = 0; + } + PrototypeScope.Exit(); // Finish the delayed C++ method declaration. @@ -447,9 +518,9 @@ void Parser::ParseLexedMemberInitializers(ParsingClass &Class) { if (HasTemplateScope) Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); - // Set or update the scope flags to include Scope::ThisScope. + // Set or update the scope flags. bool AlreadyHasClassScope = Class.TopLevelClass; - unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope|Scope::ThisScope; + unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope; ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope); ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope); @@ -457,10 +528,20 @@ void Parser::ParseLexedMemberInitializers(ParsingClass &Class) { Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); - for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) { - Class.LateParsedDeclarations[i]->ParseLexedMemberInitializers(); - } + { + // C++11 [expr.prim.general]p4: + // Otherwise, if a member-declarator declares a non-static data member + // (9.2) of a class X, the expression this is a prvalue of type "pointer + // to X" within the optional brace-or-equal-initializer. It shall not + // appear elsewhere in the member-declarator. + Sema::CXXThisScopeRAII ThisScope(Actions, Class.TagOrTemplate, + /*TypeQuals=*/(unsigned)0); + for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) { + Class.LateParsedDeclarations[i]->ParseLexedMemberInitializers(); + } + } + if (!AlreadyHasClassScope) Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); @@ -481,6 +562,7 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { ConsumeAnyToken(); SourceLocation EqualLoc; + ExprResult Init = ParseCXXMemberInitializer(MI.Field, /*IsFunction=*/false, EqualLoc); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index cf3dca20d901..932ffb440fd2 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -729,9 +729,9 @@ void Parser::ParseLexedAttributes(ParsingClass &Class) { if (HasTemplateScope) Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); - // Set or update the scope flags to include Scope::ThisScope. + // Set or update the scope flags. bool AlreadyHasClassScope = Class.TopLevelClass; - unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope|Scope::ThisScope; + unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope; ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope); ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope); @@ -739,11 +739,16 @@ void Parser::ParseLexedAttributes(ParsingClass &Class) { if (!AlreadyHasClassScope) Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); - - for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i) { - Class.LateParsedDeclarations[i]->ParseLexedAttributes(); + { + // Allow 'this' within late-parsed attributes. + Sema::CXXThisScopeRAII ThisScope(Actions, Class.TagOrTemplate, + /*TypeQuals=*/0); + + for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i){ + Class.LateParsedDeclarations[i]->ParseLexedAttributes(); + } } - + if (!AlreadyHasClassScope) Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); @@ -756,6 +761,7 @@ void Parser::ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D, for (unsigned i = 0, ni = LAs.size(); i < ni; ++i) { LAs[i]->addDecl(D); ParseLexedAttribute(*LAs[i], EnterScope, OnDefinition); + delete LAs[i]; } LAs.clear(); } @@ -958,7 +964,7 @@ void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { /// [C++] namespace-definition /// [C++] using-directive /// [C++] using-declaration -/// [C++0x/C11] static_assert-declaration +/// [C++11/C11] static_assert-declaration /// others... [FIXME] /// Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, @@ -4191,6 +4197,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, SmallVector DynamicExceptions; SmallVector DynamicExceptionRanges; ExprResult NoexceptExpr; + CachedTokens *ExceptionSpecTokens = 0; ParsedAttributes FnAttrs(AttrFactory); ParsedType TrailingReturnType; @@ -4241,11 +4248,34 @@ void Parser::ParseFunctionDeclarator(Declarator &D, EndLoc = RefQualifierLoc; } + // C++11 [expr.prim.general]p3: + // If a declaration declares a member function or member function + // template of a class X, the expression this is a prvalue of type + // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq + // and the end of the function-definition, member-declarator, or + // declarator. + bool IsCXX11MemberFunction = + getLangOpts().CPlusPlus0x && + (D.getContext() == Declarator::MemberContext || + (D.getContext() == Declarator::FileContext && + D.getCXXScopeSpec().isValid() && + Actions.CurContext->isRecord())); + Sema::CXXThisScopeRAII ThisScope(Actions, + dyn_cast(Actions.CurContext), + DS.getTypeQualifiers(), + IsCXX11MemberFunction); + // Parse exception-specification[opt]. - ESpecType = MaybeParseExceptionSpecification(ESpecRange, - DynamicExceptions, - DynamicExceptionRanges, - NoexceptExpr); + bool Delayed = (D.getContext() == Declarator::MemberContext && + D.getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_typedef && + !D.getDeclSpec().isFriendSpecified()); + ESpecType = tryParseExceptionSpecification(Delayed, + ESpecRange, + DynamicExceptions, + DynamicExceptionRanges, + NoexceptExpr, + ExceptionSpecTokens); if (ESpecType != EST_None) EndLoc = ESpecRange.getEnd(); @@ -4280,6 +4310,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, DynamicExceptions.size(), NoexceptExpr.isUsable() ? NoexceptExpr.get() : 0, + ExceptionSpecTokens, Tracker.getOpenLocation(), EndLoc, D, TrailingReturnType), @@ -4481,7 +4512,6 @@ void Parser::ParseParameterDeclarationClause( // If we're inside a class definition, cache the tokens // corresponding to the default argument. We'll actually parse // them when we see the end of the class definition. - // FIXME: Templates will require something similar. // FIXME: Can we use a smart pointer for Toks? DefArgToks = new CachedTokens; diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index b2a65ff0f326..b9b51d751822 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1534,13 +1534,35 @@ AccessSpecifier Parser::getAccessSpecifierIfPresent() const { } } -void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, - Decl *ThisDecl) { +/// \brief If the given declarator has any parts for which parsing has to be +/// delayed, e.g., default arguments or an exception-specification, create a +/// late-parsed method declaration record to handle the parsing at the end of +/// the class definition. +void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo, + Decl *ThisDecl) { // We just declared a member function. If this member function - // has any default arguments, we'll need to parse them later. + // has any default arguments or an exception-specification, we'll need to + // parse them later. LateParsedMethodDeclaration *LateMethod = 0; DeclaratorChunk::FunctionTypeInfo &FTI = DeclaratorInfo.getFunctionTypeInfo(); + + // If there was a delayed exception-specification, hold onto its tokens. + if (FTI.getExceptionSpecType() == EST_Delayed) { + // Push this method onto the stack of late-parsed method + // declarations. + LateMethod = new LateParsedMethodDeclaration(this, ThisDecl); + getCurrentClass().LateParsedDeclarations.push_back(LateMethod); + LateMethod->TemplateScope = getCurScope()->isTemplateParamScope(); + + // Stash the exception-specification tokens in the late-pased mthod. + LateMethod->ExceptionSpecTokens = FTI.ExceptionSpecTokens; + FTI.ExceptionSpecTokens = 0; + + // Reserve space for the parameters. + LateMethod->DefaultArgs.reserve(FTI.NumArgs); + } + for (unsigned ParamIdx = 0; ParamIdx < FTI.NumArgs; ++ParamIdx) { if (LateMethod || FTI.ArgInfo[ParamIdx].DefaultArgTokens) { if (!LateMethod) { @@ -1558,7 +1580,7 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, LateParsedDefaultArgument(FTI.ArgInfo[I].Param)); } - // Add this parameter to the list of parameters (it or may + // Add this parameter to the list of parameters (it may or may // not have a default argument). LateMethod->DefaultArgs.push_back( LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param, @@ -1824,7 +1846,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Parse the first declarator. ParseDeclarator(DeclaratorInfo); - // Error parsing the declarator? + // Error parsin g the declarator? if (!DeclaratorInfo.hasName()) { // If so, skip until the semi-colon or a }. SkipUntil(tok::r_brace, true, true); @@ -2046,7 +2068,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (DeclaratorInfo.isFunctionDeclarator() && DeclaratorInfo.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef) { - HandleMemberFunctionDefaultArgs(DeclaratorInfo, ThisDecl); + HandleMemberFunctionDeclDelays(DeclaratorInfo, ThisDecl); } DeclaratorInfo.complete(ThisDecl); @@ -2334,13 +2356,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, T.getCloseLocation(), attrs.getList()); - // C++0x [class.mem]p2: Within the class member-specification, the class is - // regarded as complete within function bodies, default arguments, exception- - // specifications, and brace-or-equal-initializers for non-static data - // members (including such things in nested classes). - // - // FIXME: Only function bodies and brace-or-equal-initializers are currently - // handled. Fix the others! + // C++11 [class.mem]p2: + // Within the class member-specification, the class is regarded as complete + // within function bodies, default arguments, exception-specifications, and + // brace-or-equal-initializers for non-static data members (including such + // things in nested classes). if (TagDecl && NonNestedClass) { // We are not inside a nested class. This class and its nested classes // are complete and we can parse the delayed portions of method @@ -2535,12 +2555,63 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { /// 'noexcept' /// 'noexcept' '(' constant-expression ')' ExceptionSpecificationType -Parser::MaybeParseExceptionSpecification(SourceRange &SpecificationRange, +Parser::tryParseExceptionSpecification(bool Delayed, + SourceRange &SpecificationRange, SmallVectorImpl &DynamicExceptions, SmallVectorImpl &DynamicExceptionRanges, - ExprResult &NoexceptExpr) { + ExprResult &NoexceptExpr, + CachedTokens *&ExceptionSpecTokens) { ExceptionSpecificationType Result = EST_None; + ExceptionSpecTokens = 0; + + // Handle delayed parsing of exception-specifications. + if (Delayed) { + if (Tok.isNot(tok::kw_throw) && Tok.isNot(tok::kw_noexcept)) + return EST_None; + // Consume and cache the starting token. + bool IsNoexcept = Tok.is(tok::kw_noexcept); + Token StartTok = Tok; + SpecificationRange = SourceRange(ConsumeToken()); + + // Check for a '('. + if (!Tok.is(tok::l_paren)) { + // If this is a bare 'noexcept', we're done. + if (IsNoexcept) { + Diag(Tok, diag::warn_cxx98_compat_noexcept_decl); + NoexceptExpr = 0; + return EST_BasicNoexcept; + } + + Diag(Tok, diag::err_expected_lparen_after) << "throw"; + return EST_DynamicNone; + } + + // Cache the tokens for the exception-specification. + ExceptionSpecTokens = new CachedTokens; + ExceptionSpecTokens->push_back(StartTok); // 'throw' or 'noexcept' + ExceptionSpecTokens->push_back(Tok); // '(' + SpecificationRange.setEnd(ConsumeParen()); // '(' + + if (!ConsumeAndStoreUntil(tok::r_paren, *ExceptionSpecTokens, + /*StopAtSemi=*/true, + /*ConsumeFinalToken=*/true)) { + NoexceptExpr = 0; + delete ExceptionSpecTokens; + ExceptionSpecTokens = 0; + return IsNoexcept? EST_BasicNoexcept : EST_DynamicNone; + } + SpecificationRange.setEnd(Tok.getLocation()); + + // Add the 'stop' token. + Token End; + End.startToken(); + End.setKind(tok::cxx_exceptspec_end); + End.setLocation(Tok.getLocation()); + ExceptionSpecTokens->push_back(End); + return EST_Delayed; + } + // See if there's a dynamic specification. if (Tok.is(tok::kw_throw)) { Result = ParseDynamicExceptionSpecification(SpecificationRange, diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 7f3a815edc0e..b6a027b0d794 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1926,11 +1926,9 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // unless they've already reported an error. if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) { Diag(Tok, diag::ext_gnu_statement_expr); - Actions.ActOnStartStmtExpr(); - ParsedAttributes attrs(AttrFactory); - StmtResult Stmt(ParseCompoundStatement(attrs, true)); + StmtResult Stmt(ParseCompoundStatement(true)); ExprType = CompoundStmt; // If the substmt parsed correctly, build the AST node. @@ -2394,7 +2392,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { SourceLocation(), EST_None, SourceLocation(), - 0, 0, 0, 0, + 0, 0, 0, 0, 0, CaretLoc, CaretLoc, ParamInfo), attrs, CaretLoc); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 2af74824ebcf..ae6ad0b275b6 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -780,10 +780,13 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( llvm::SmallVector DynamicExceptions; llvm::SmallVector DynamicExceptionRanges; ExprResult NoexceptExpr; - ESpecType = MaybeParseExceptionSpecification(ESpecRange, - DynamicExceptions, - DynamicExceptionRanges, - NoexceptExpr); + CachedTokens *ExceptionSpecTokens; + ESpecType = tryParseExceptionSpecification(/*Delayed=*/false, + ESpecRange, + DynamicExceptions, + DynamicExceptionRanges, + NoexceptExpr, + ExceptionSpecTokens); if (ESpecType != EST_None) DeclEndLoc = ESpecRange.getEnd(); @@ -818,6 +821,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( DynamicExceptions.size(), NoexceptExpr.isUsable() ? NoexceptExpr.get() : 0, + 0, DeclLoc, DeclEndLoc, D, TrailingReturnType), Attr, DeclEndLoc); @@ -863,6 +867,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( /*ExceptionRanges=*/0, /*NumExceptions=*/0, /*NoexceptExpr=*/0, + /*ExceptionSpecTokens=*/0, DeclLoc, DeclEndLoc, D, TrailingReturnType), Attr, DeclEndLoc); @@ -872,8 +877,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using // it. unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope; - if (getCurScope()->getFlags() & Scope::ThisScope) - ScopeFlags |= Scope::ThisScope; ParseScope BodyScope(this, ScopeFlags); Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope()); @@ -1711,7 +1714,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, // Form a parsed representation of the template-id to be stored in the // UnqualifiedId. TemplateIdAnnotation *TemplateId - = TemplateIdAnnotation::Allocate(TemplateArgs.size()); + = TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds); if (Id.getKind() == UnqualifiedId::IK_Identifier) { TemplateId->Name = Id.Identifier; diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index fdb978866762..44320dfcb3bf 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -78,13 +78,30 @@ using namespace clang; StmtResult Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement, SourceLocation *TrailingElseLoc) { - const char *SemiError = 0; - StmtResult Res; ParenBraceBracketBalancer BalancerRAIIObj(*this); - ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX0XAttributes(attrs, 0, /*MightBeObjCMessageSend*/ true); + ParsedAttributesWithRange Attrs(AttrFactory); + MaybeParseCXX0XAttributes(Attrs, 0, /*MightBeObjCMessageSend*/ true); + + StmtResult Res = ParseStatementOrDeclarationAfterAttributes(Stmts, + OnlyStatement, TrailingElseLoc, Attrs); + + assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) && + "attributes on empty statement"); + + if (Attrs.empty() || Res.isInvalid()) + return Res; + + return Actions.ProcessStmtAttributes(Res.get(), Attrs.getList(), Attrs.Range); +} + +StmtResult +Parser::ParseStatementOrDeclarationAfterAttributes(StmtVector &Stmts, + bool OnlyStatement, SourceLocation *TrailingElseLoc, + ParsedAttributesWithRange &Attrs) { + const char *SemiError = 0; + StmtResult Res; // Cases in this switch statement should fall through if the parser expects // the token to end in a semicolon (in which case SemiError should be set), @@ -95,6 +112,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement, switch (Kind) { case tok::at: // May be a @try or @throw statement { + ProhibitAttributes(Attrs); // TODO: is it correct? AtLoc = ConsumeToken(); // consume @ return ParseObjCAtStatement(AtLoc); } @@ -108,7 +126,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement, Token Next = NextToken(); if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement // identifier ':' statement - return ParseLabeledStatement(attrs); + return ParseLabeledStatement(Attrs); } if (Next.isNot(tok::coloncolon)) { @@ -210,7 +228,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement, if ((getLangOpts().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy Decl = ParseDeclaration(Stmts, Declarator::BlockContext, - DeclEnd, attrs); + DeclEnd, Attrs); return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd); } @@ -219,54 +237,54 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement, return StmtError(); } - return ParseExprStatement(attrs); + return ParseExprStatement(); } case tok::kw_case: // C99 6.8.1: labeled-statement - return ParseCaseStatement(attrs); + return ParseCaseStatement(); case tok::kw_default: // C99 6.8.1: labeled-statement - return ParseDefaultStatement(attrs); + return ParseDefaultStatement(); case tok::l_brace: // C99 6.8.2: compound-statement - return ParseCompoundStatement(attrs); + return ParseCompoundStatement(); case tok::semi: { // C99 6.8.3p3: expression[opt] ';' bool HasLeadingEmptyMacro = Tok.hasLeadingEmptyMacro(); return Actions.ActOnNullStmt(ConsumeToken(), HasLeadingEmptyMacro); } case tok::kw_if: // C99 6.8.4.1: if-statement - return ParseIfStatement(attrs, TrailingElseLoc); + return ParseIfStatement(TrailingElseLoc); case tok::kw_switch: // C99 6.8.4.2: switch-statement - return ParseSwitchStatement(attrs, TrailingElseLoc); + return ParseSwitchStatement(TrailingElseLoc); case tok::kw_while: // C99 6.8.5.1: while-statement - return ParseWhileStatement(attrs, TrailingElseLoc); + return ParseWhileStatement(TrailingElseLoc); case tok::kw_do: // C99 6.8.5.2: do-statement - Res = ParseDoStatement(attrs); + Res = ParseDoStatement(); SemiError = "do/while"; break; case tok::kw_for: // C99 6.8.5.3: for-statement - return ParseForStatement(attrs, TrailingElseLoc); + return ParseForStatement(TrailingElseLoc); case tok::kw_goto: // C99 6.8.6.1: goto-statement - Res = ParseGotoStatement(attrs); + Res = ParseGotoStatement(); SemiError = "goto"; break; case tok::kw_continue: // C99 6.8.6.2: continue-statement - Res = ParseContinueStatement(attrs); + Res = ParseContinueStatement(); SemiError = "continue"; break; case tok::kw_break: // C99 6.8.6.3: break-statement - Res = ParseBreakStatement(attrs); + Res = ParseBreakStatement(); SemiError = "break"; break; case tok::kw_return: // C99 6.8.6.4: return-statement - Res = ParseReturnStatement(attrs); + Res = ParseReturnStatement(); SemiError = "return"; break; case tok::kw_asm: { - ProhibitAttributes(attrs); + ProhibitAttributes(Attrs); bool msAsm = false; Res = ParseAsmStatement(msAsm); Res = Actions.ActOnFinishFullStmt(Res.get()); @@ -276,16 +294,19 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement, } case tok::kw_try: // C++ 15: try-block - return ParseCXXTryBlock(attrs); + return ParseCXXTryBlock(); case tok::kw___try: - return ParseSEHTryBlock(attrs); + ProhibitAttributes(Attrs); // TODO: is it correct? + return ParseSEHTryBlock(); case tok::annot_pragma_vis: + ProhibitAttributes(Attrs); HandlePragmaVisibility(); return StmtEmpty(); case tok::annot_pragma_pack: + ProhibitAttributes(Attrs); HandlePragmaPack(); return StmtEmpty(); } @@ -306,11 +327,10 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement, } /// \brief Parse an expression statement. -StmtResult Parser::ParseExprStatement(ParsedAttributes &Attrs) { +StmtResult Parser::ParseExprStatement() { // If a case keyword is missing, this is where it should be inserted. Token OldToken = Tok; - // FIXME: Use the attributes // expression[opt] ';' ExprResult Expr(ParseExpression()); if (Expr.isInvalid()) { @@ -331,7 +351,7 @@ StmtResult Parser::ParseExprStatement(ParsedAttributes &Attrs) { << FixItHint::CreateInsertion(OldToken.getLocation(), "case "); // Recover parsing as a case statement. - return ParseCaseStatement(Attrs, /*MissingCase=*/true, Expr); + return ParseCaseStatement(/*MissingCase=*/true, Expr); } // Otherwise, eat the semicolon. @@ -339,7 +359,7 @@ StmtResult Parser::ParseExprStatement(ParsedAttributes &Attrs) { return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get())); } -StmtResult Parser::ParseSEHTryBlock(ParsedAttributes & Attrs) { +StmtResult Parser::ParseSEHTryBlock() { assert(Tok.is(tok::kw___try) && "Expected '__try'"); SourceLocation Loc = ConsumeToken(); return ParseSEHTryBlockCommon(Loc); @@ -358,13 +378,12 @@ StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) { if(Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok,diag::err_expected_lbrace)); - ParsedAttributesWithRange attrs(AttrFactory); - StmtResult TryBlock(ParseCompoundStatement(attrs)); + StmtResult TryBlock(ParseCompoundStatement()); if(TryBlock.isInvalid()) return move(TryBlock); StmtResult Handler; - if (Tok.is(tok::identifier) && + if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == getSEHExceptKeyword()) { SourceLocation Loc = ConsumeToken(); Handler = ParseSEHExceptBlock(Loc); @@ -418,8 +437,7 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) { if(ExpectAndConsume(tok::r_paren,diag::err_expected_rparen)) return StmtError(); - ParsedAttributesWithRange attrs(AttrFactory); - StmtResult Block(ParseCompoundStatement(attrs)); + StmtResult Block(ParseCompoundStatement()); if(Block.isInvalid()) return move(Block); @@ -437,8 +455,7 @@ StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyBlock) { raii2(Ident___abnormal_termination, false), raii3(Ident_AbnormalTermination, false); - ParsedAttributesWithRange attrs(AttrFactory); - StmtResult Block(ParseCompoundStatement(attrs)); + StmtResult Block(ParseCompoundStatement()); if(Block.isInvalid()) return move(Block); @@ -451,7 +468,7 @@ StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyBlock) { /// identifier ':' statement /// [GNU] identifier ':' attributes[opt] statement /// -StmtResult Parser::ParseLabeledStatement(ParsedAttributes &attrs) { +StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs) { assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() && "Not an identifier!"); @@ -463,7 +480,8 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &attrs) { // identifier ':' statement SourceLocation ColonLoc = ConsumeToken(); - // Read label attributes, if present. + // Read label attributes, if present. attrs will contain both C++11 and GNU + // attributes (if present) after this point. MaybeParseGNUAttributes(attrs); StmtResult SubStmt(ParseStatement()); @@ -474,8 +492,10 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &attrs) { LabelDecl *LD = Actions.LookupOrCreateLabel(IdentTok.getIdentifierInfo(), IdentTok.getLocation()); - if (AttributeList *Attrs = attrs.getList()) + if (AttributeList *Attrs = attrs.getList()) { Actions.ProcessDeclAttributeList(Actions.CurScope, LD, Attrs); + attrs.clear(); + } return Actions.ActOnLabelStmt(IdentTok.getLocation(), LD, ColonLoc, SubStmt.get()); @@ -486,10 +506,8 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &attrs) { /// 'case' constant-expression ':' statement /// [GNU] 'case' constant-expression '...' constant-expression ':' statement /// -StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase, - ExprResult Expr) { +StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) { assert((MissingCase || Tok.is(tok::kw_case)) && "Not a case stmt!"); - // FIXME: Use attributes? // It is very very common for code to contain many case statements recursively // nested, as in (but usually without indentation): @@ -625,9 +643,7 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase, /// 'default' ':' statement /// Note that this does not parse the 'statement' at the end. /// -StmtResult Parser::ParseDefaultStatement(ParsedAttributes &attrs) { - //FIXME: Use attributes? - +StmtResult Parser::ParseDefaultStatement() { assert(Tok.is(tok::kw_default) && "Not a default stmt!"); SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'. @@ -668,9 +684,8 @@ StmtResult Parser::ParseDefaultStatement(ParsedAttributes &attrs) { SubStmt.get(), getCurScope()); } -StmtResult Parser::ParseCompoundStatement(ParsedAttributes &Attr, - bool isStmtExpr) { - return ParseCompoundStatement(Attr, isStmtExpr, Scope::DeclScope); +StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) { + return ParseCompoundStatement(isStmtExpr, Scope::DeclScope); } /// ParseCompoundStatement - Parse a "{}" block. @@ -700,11 +715,8 @@ StmtResult Parser::ParseCompoundStatement(ParsedAttributes &Attr, /// [OMP] barrier-directive /// [OMP] flush-directive /// -StmtResult Parser::ParseCompoundStatement(ParsedAttributes &attrs, - bool isStmtExpr, +StmtResult Parser::ParseCompoundStatement(bool isStmtExpr, unsigned ScopeFlags) { - //FIXME: Use attributes? - assert(Tok.is(tok::l_brace) && "Not a compount stmt!"); // Enter a scope to hold everything within the compound stmt. Compound @@ -894,10 +906,7 @@ bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult, /// [C++] 'if' '(' condition ')' statement /// [C++] 'if' '(' condition ')' statement 'else' statement /// -StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs, - SourceLocation *TrailingElseLoc) { - // FIXME: Use attributes? - +StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { assert(Tok.is(tok::kw_if) && "Not an if stmt!"); SourceLocation IfLoc = ConsumeToken(); // eat the 'if'. @@ -1028,10 +1037,7 @@ StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs, /// switch-statement: /// 'switch' '(' expression ')' statement /// [C++] 'switch' '(' condition ')' statement -StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs, - SourceLocation *TrailingElseLoc) { - // FIXME: Use attributes? - +StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) { assert(Tok.is(tok::kw_switch) && "Not a switch stmt!"); SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'. @@ -1119,10 +1125,7 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs, /// while-statement: [C99 6.8.5.1] /// 'while' '(' expression ')' statement /// [C++] 'while' '(' condition ')' statement -StmtResult Parser::ParseWhileStatement(ParsedAttributes &attrs, - SourceLocation *TrailingElseLoc) { - // FIXME: Use attributes? - +StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) { assert(Tok.is(tok::kw_while) && "Not a while stmt!"); SourceLocation WhileLoc = Tok.getLocation(); ConsumeToken(); // eat the 'while'. @@ -1194,9 +1197,7 @@ StmtResult Parser::ParseWhileStatement(ParsedAttributes &attrs, /// do-statement: [C99 6.8.5.2] /// 'do' statement 'while' '(' expression ')' ';' /// Note: this lets the caller parse the end ';'. -StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) { - // FIXME: Use attributes? - +StmtResult Parser::ParseDoStatement() { assert(Tok.is(tok::kw_do) && "Not a do stmt!"); SourceLocation DoLoc = ConsumeToken(); // eat the 'do'. @@ -1277,10 +1278,7 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) { /// [C++0x] for-range-initializer: /// [C++0x] expression /// [C++0x] braced-init-list [TODO] -StmtResult Parser::ParseForStatement(ParsedAttributes &attrs, - SourceLocation *TrailingElseLoc) { - // FIXME: Use attributes? - +StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { assert(Tok.is(tok::kw_for) && "Not a for stmt!"); SourceLocation ForLoc = ConsumeToken(); // eat the 'for'. @@ -1535,9 +1533,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs, /// /// Note: this lets the caller parse the end ';'. /// -StmtResult Parser::ParseGotoStatement(ParsedAttributes &attrs) { - // FIXME: Use attributes? - +StmtResult Parser::ParseGotoStatement() { assert(Tok.is(tok::kw_goto) && "Not a goto stmt!"); SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'. @@ -1571,9 +1567,7 @@ StmtResult Parser::ParseGotoStatement(ParsedAttributes &attrs) { /// /// Note: this lets the caller parse the end ';'. /// -StmtResult Parser::ParseContinueStatement(ParsedAttributes &attrs) { - // FIXME: Use attributes? - +StmtResult Parser::ParseContinueStatement() { SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'. return Actions.ActOnContinueStmt(ContinueLoc, getCurScope()); } @@ -1584,9 +1578,7 @@ StmtResult Parser::ParseContinueStatement(ParsedAttributes &attrs) { /// /// Note: this lets the caller parse the end ';'. /// -StmtResult Parser::ParseBreakStatement(ParsedAttributes &attrs) { - // FIXME: Use attributes? - +StmtResult Parser::ParseBreakStatement() { SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'. return Actions.ActOnBreakStmt(BreakLoc, getCurScope()); } @@ -1594,9 +1586,7 @@ StmtResult Parser::ParseBreakStatement(ParsedAttributes &attrs) { /// ParseReturnStatement /// jump-statement: /// 'return' expression[opt] ';' -StmtResult Parser::ParseReturnStatement(ParsedAttributes &attrs) { - // FIXME: Use attributes? - +StmtResult Parser::ParseReturnStatement() { assert(Tok.is(tok::kw_return) && "Not a return stmt!"); SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'. @@ -2043,9 +2033,7 @@ bool Parser::trySkippingFunctionBody() { /// try-block: /// 'try' compound-statement handler-seq /// -StmtResult Parser::ParseCXXTryBlock(ParsedAttributes &attrs) { - // FIXME: Add attributes? - +StmtResult Parser::ParseCXXTryBlock() { assert(Tok.is(tok::kw_try) && "Expected 'try'"); SourceLocation TryLoc = ConsumeToken(); @@ -2072,17 +2060,17 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected_lbrace)); // FIXME: Possible draft standard bug: attribute-specifier should be allowed? - ParsedAttributesWithRange attrs(AttrFactory); - StmtResult TryBlock(ParseCompoundStatement(attrs, /*isStmtExpr=*/false, + + StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false, Scope::DeclScope|Scope::TryScope)); if (TryBlock.isInvalid()) return move(TryBlock); // Borland allows SEH-handlers with 'try' - if((Tok.is(tok::identifier) && - Tok.getIdentifierInfo() == getSEHExceptKeyword()) || - Tok.is(tok::kw___finally)) { + if ((Tok.is(tok::identifier) && + Tok.getIdentifierInfo() == getSEHExceptKeyword()) || + Tok.is(tok::kw___finally)) { // TODO: Factor into common return ParseSEHHandlerCommon(...) StmtResult Handler; if(Tok.getIdentifierInfo() == getSEHExceptKeyword()) { @@ -2103,6 +2091,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { } else { StmtVector Handlers(Actions); + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); ProhibitAttributes(attrs); @@ -2168,8 +2157,7 @@ StmtResult Parser::ParseCXXCatchBlock() { return StmtError(Diag(Tok, diag::err_expected_lbrace)); // FIXME: Possible draft standard bug: attribute-specifier should be allowed? - ParsedAttributes attrs(AttrFactory); - StmtResult Block(ParseCompoundStatement(attrs)); + StmtResult Block(ParseCompoundStatement()); if (Block.isInvalid()) return move(Block); @@ -2188,24 +2176,23 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) { if (Result.Behavior == IEB_Dependent) { if (!Tok.is(tok::l_brace)) { Diag(Tok, diag::err_expected_lbrace); - return; + return; } - - ParsedAttributes Attrs(AttrFactory); - StmtResult Compound = ParseCompoundStatement(Attrs); + + StmtResult Compound = ParseCompoundStatement(); if (Compound.isInvalid()) return; - + StmtResult DepResult = Actions.ActOnMSDependentExistsStmt(Result.KeywordLoc, Result.IsIfExists, - Result.SS, + Result.SS, Result.Name, Compound.get()); if (DepResult.isUsable()) Stmts.push_back(DepResult.get()); return; } - + BalancedDelimiterTracker Braces(*this, tok::l_brace); if (Braces.consumeOpen()) { Diag(Tok, diag::err_expected_lbrace); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 61cd9f2119a6..5c3e2ba589ff 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -652,6 +652,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { // end of the template-parameter-list rather than a greater-than // operator. GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); DefaultArg = ParseAssignmentExpression(); if (DefaultArg.isInvalid()) @@ -838,7 +839,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // later. Tok.setKind(tok::annot_template_id); TemplateIdAnnotation *TemplateId - = TemplateIdAnnotation::Allocate(TemplateArgs.size()); + = TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds); TemplateId->TemplateNameLoc = TemplateNameLoc; if (TemplateName.getKind() == UnqualifiedId::IK_Identifier) { TemplateId->Name = TemplateName.Identifier; diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 054a8fd6a55f..f1b99fb0a129 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -397,6 +397,8 @@ Parser::~Parser() { PP.RemovePragmaHandler("STDC", FPContractHandler.get()); FPContractHandler.reset(); PP.clearCodeCompletionHandler(); + + assert(TemplateIds.empty() && "Still alive TemplateIdAnnotations around?"); } /// Initialize - Warm up the parser. @@ -470,10 +472,30 @@ void Parser::Initialize() { } } +namespace { + /// \brief RAIIObject to destroy the contents of a SmallVector of + /// TemplateIdAnnotation pointers and clear the vector. + class DestroyTemplateIdAnnotationsRAIIObj { + SmallVectorImpl &Container; + public: + DestroyTemplateIdAnnotationsRAIIObj(SmallVectorImpl + &Container) + : Container(Container) {} + + ~DestroyTemplateIdAnnotationsRAIIObj() { + for (SmallVectorImpl::iterator I = + Container.begin(), E = Container.end(); + I != E; ++I) + (*I)->Destroy(); + Container.clear(); + } + }; +} + /// ParseTopLevelDecl - Parse one top-level declaration, return whatever the /// action tells us to. This returns true if the EOF was encountered. bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { - DelayedCleanupPoint CleanupRAII(TopLevelDeclCleanupPool); + DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(TemplateIds); // Skip over the EOF token, flagging end of previous input for incremental // processing @@ -543,7 +565,7 @@ void Parser::ParseTranslationUnit() { Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, ParsingDeclSpec *DS) { - DelayedCleanupPoint CleanupRAII(TopLevelDeclCleanupPool); + DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(TemplateIds); ParenBraceBracketBalancer BalancerRAIIObj(*this); if (PP.isCodeCompletionReached()) { @@ -1201,8 +1223,6 @@ TemplateIdAnnotation *Parser::takeTemplateIdAnnotation(const Token &tok) { assert(tok.is(tok::annot_template_id) && "Expected template-id token"); TemplateIdAnnotation * Id = static_cast(tok.getAnnotationValue()); - TopLevelDeclCleanupPool.delayMemberFunc< TemplateIdAnnotation, - &TemplateIdAnnotation::Destroy>(Id); return Id; } diff --git a/lib/Rewrite/RewriteModernObjC.cpp b/lib/Rewrite/RewriteModernObjC.cpp index 57109dee9a0a..94fba64e17a7 100644 --- a/lib/Rewrite/RewriteModernObjC.cpp +++ b/lib/Rewrite/RewriteModernObjC.cpp @@ -304,7 +304,6 @@ namespace { void RewriteFunctionDecl(FunctionDecl *FD); void RewriteBlockPointerType(std::string& Str, QualType Type); void RewriteBlockPointerTypeVariable(std::string& Str, ValueDecl *VD); - void RewriteBlockLiteralFunctionDecl(FunctionDecl *FD); void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl); void RewriteTypeOfDecl(VarDecl *VD); void RewriteObjCQualifiedInterfaceTypes(Expr *E); @@ -2246,31 +2245,7 @@ void RewriteModernObjC::RewriteBlockPointerTypeVariable(std::string& Str, } } - -void RewriteModernObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) { - SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); - const FunctionType *funcType = FD->getType()->getAs(); - const FunctionProtoType *proto = dyn_cast(funcType); - if (!proto) - return; - QualType Type = proto->getResultType(); - std::string FdStr = Type.getAsString(Context->getPrintingPolicy()); - FdStr += " "; - FdStr += FD->getName(); - FdStr += "("; - unsigned numArgs = proto->getNumArgs(); - for (unsigned i = 0; i < numArgs; i++) { - QualType ArgType = proto->getArgType(i); - RewriteBlockPointerType(FdStr, ArgType); - if (i+1 < numArgs) - FdStr += ", "; - } - FdStr += ");\n"; - InsertText(FunLocStart, FdStr); - CurFunctionDeclToDeclareForBlock = 0; -} - -// SynthSuperContructorFunctionDecl - id objc_super(id obj, id super); +// SynthSuperContructorFunctionDecl - id __rw_objc_super(id obj, id super); void RewriteModernObjC::SynthSuperContructorFunctionDecl() { if (SuperContructorFunctionDecl) return; @@ -2311,21 +2286,13 @@ void RewriteModernObjC::SynthMsgSendFunctionDecl() { SC_None, false); } -// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...); +// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(void); void RewriteModernObjC::SynthMsgSendSuperFunctionDecl() { IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper"); - SmallVector ArgTys; - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("objc_super")); - QualType argT = Context->getPointerType(Context->getTagDeclType(RD)); - assert(!argT.isNull() && "Can't build 'struct objc_super *' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); + SmallVector ArgTys; + ArgTys.push_back(Context->VoidTy); QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size(), + &ArgTys[0], 1, true /*isVariadic*/); MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), @@ -2357,22 +2324,14 @@ void RewriteModernObjC::SynthMsgSendStretFunctionDecl() { } // SynthMsgSendSuperStretFunctionDecl - -// id objc_msgSendSuper_stret(struct objc_super *, SEL op, ...); +// id objc_msgSendSuper_stret(void); void RewriteModernObjC::SynthMsgSendSuperStretFunctionDecl() { IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper_stret"); - SmallVector ArgTys; - RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), SourceLocation(), - &Context->Idents.get("objc_super")); - QualType argT = Context->getPointerType(Context->getTagDeclType(RD)); - assert(!argT.isNull() && "Can't build 'struct objc_super *' type"); - ArgTys.push_back(argT); - argT = Context->getObjCSelType(); - assert(!argT.isNull() && "Can't find 'SEL' type"); - ArgTys.push_back(argT); + SmallVector ArgTys; + ArgTys.push_back(Context->VoidTy); QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(), - &ArgTys[0], ArgTys.size(), + &ArgTys[0], 1, true /*isVariadic*/); MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), @@ -2925,18 +2884,20 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral return CE; } -// struct objc_super { struct objc_object *receiver; struct objc_class *super; }; +// struct __rw_objc_super { +// struct objc_object *object; struct objc_object *superClass; +// }; QualType RewriteModernObjC::getSuperStructType() { if (!SuperStructDecl) { SuperStructDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, SourceLocation(), SourceLocation(), - &Context->Idents.get("objc_super")); + &Context->Idents.get("__rw_objc_super")); QualType FieldTypes[2]; - // struct objc_object *receiver; + // struct objc_object *object; FieldTypes[0] = Context->getObjCIdType(); - // struct objc_class *super; - FieldTypes[1] = Context->getObjCClassType(); + // struct objc_object *superClass; + FieldTypes[1] = Context->getObjCIdType(); // Create fields for (unsigned i = 0; i < 2; ++i) { @@ -3073,7 +3034,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), CK_BitCast, Cls)); - // struct objc_super + // struct __rw_objc_super QualType superType = getSuperStructType(); Expr *SuperRep; @@ -3091,7 +3052,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, // the structure definition in the header. The rewriter has it's own // internal definition (__rw_objc_super) that is uses. This is why // we need the cast below. For example: - // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) + // (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) // SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), @@ -3101,7 +3062,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, Context->getPointerType(superType), CK_BitCast, SuperRep); } else { - // (struct objc_super) { } + // (struct __rw_objc_super) { } InitListExpr *ILE = new (Context) InitListExpr(*Context, SourceLocation(), &InitExprs[0], InitExprs.size(), @@ -3111,7 +3072,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, superType, VK_LValue, ILE, false); - // struct objc_super * + // struct __rw_objc_super * SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary, @@ -3183,7 +3144,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, // set 'super class', using class_getSuperclass(). NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), CK_BitCast, Cls)); - // struct objc_super + // struct __rw_objc_super QualType superType = getSuperStructType(); Expr *SuperRep; @@ -3200,7 +3161,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, // the structure definition in the header. The rewriter has it's own // internal definition (__rw_objc_super) that is uses. This is why // we need the cast below. For example: - // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) + // (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) // SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), @@ -3210,7 +3171,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, Context->getPointerType(superType), CK_BitCast, SuperRep); } else { - // (struct objc_super) { } + // (struct __rw_objc_super) { } InitListExpr *ILE = new (Context) InitListExpr(*Context, SourceLocation(), &InitExprs[0], InitExprs.size(), @@ -4022,11 +3983,25 @@ std::string RewriteModernObjC::SynthesizeBlockDescriptor(std::string DescTag, return S; } +/// getFunctionSourceLocation - returns start location of a function +/// definition. Complication arises when function has declared as +/// extern "C" or extern "C" {...} +static SourceLocation getFunctionSourceLocation (FunctionDecl *FD) { + if (!FD->isExternC() || FD->isMain()) + return FD->getTypeSpecStartLoc(); + const DeclContext *DC = FD->getDeclContext(); + if (const LinkageSpecDecl *LSD = dyn_cast(DC)) { + SourceLocation BodyRBrace = LSD->getRBraceLoc(); + // if it is extern "C" {...}, return function decl's own location. + if (BodyRBrace.isValid()) + return FD->getTypeSpecStartLoc(); + return LSD->getExternLoc(); + } + return FD->getTypeSpecStartLoc(); +} + void RewriteModernObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, StringRef FunName) { - // Insert declaration for the function in which block literal is used. - if (CurFunctionDeclToDeclareForBlock && !Blocks.empty()) - RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); bool RewriteSC = (GlobalVarDecl && !Blocks.empty() && GlobalVarDecl->getStorageClass() == SC_Static && @@ -4135,7 +4110,7 @@ void RewriteModernObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, } void RewriteModernObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) { - SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); + SourceLocation FunLocStart = getFunctionSourceLocation(FD); StringRef FuncName = FD->getName(); SynthesizeBlockLiterals(FunLocStart, FuncName); @@ -4170,11 +4145,15 @@ void RewriteModernObjC::GetBlockDeclRefExprs(Stmt *S) { GetBlockDeclRefExprs(*CI); } // Handle specific things. - if (DeclRefExpr *DRE = dyn_cast(S)) - if (DRE->refersToEnclosingLocal() && - HasLocalVariableExternalStorage(DRE->getDecl())) { - BlockDeclRefs.push_back(DRE); + if (DeclRefExpr *DRE = dyn_cast(S)) { + if (DRE->refersToEnclosingLocal()) { + // FIXME: Handle enums. + if (!isa(DRE->getDecl())) + BlockDeclRefs.push_back(DRE); + if (HasLocalVariableExternalStorage(DRE->getDecl())) + BlockDeclRefs.push_back(DRE); } + } return; } @@ -4474,19 +4453,18 @@ void RewriteModernObjC::RewriteCastExpr(CStyleCastExpr *CE) { void RewriteModernObjC::RewriteImplicitCastObjCExpr(CastExpr *IC) { CastKind CastKind = IC->getCastKind(); + if (CastKind != CK_BlockPointerToObjCPointerCast && + CastKind != CK_AnyPointerToBlockPointerCast) + return; - if (CastKind == CK_BlockPointerToObjCPointerCast) { - CStyleCastExpr * CastExpr = - NoTypeInfoCStyleCastExpr(Context, IC->getType(), CK_BitCast, IC); - ReplaceStmt(IC, CastExpr); - } - else if (CastKind == CK_AnyPointerToBlockPointerCast) { - QualType BlockT = IC->getType(); - (void)convertBlockPointerToFunctionPointer(BlockT); - CStyleCastExpr * CastExpr = - NoTypeInfoCStyleCastExpr(Context, BlockT, CK_BitCast, IC); - ReplaceStmt(IC, CastExpr); - } + QualType QT = IC->getType(); + (void)convertBlockPointerToFunctionPointer(QT); + std::string TypeString(QT.getAsString(Context->getPrintingPolicy())); + std::string Str = "("; + Str += TypeString; + Str += ")"; + InsertText(IC->getSubExpr()->getLocStart(), &Str[0], Str.size()); + return; } @@ -4742,10 +4720,6 @@ std::string RewriteModernObjC::SynthesizeByrefCopyDestroyHelper(VarDecl *VD, /// /// void RewriteModernObjC::RewriteByRefVar(VarDecl *ND) { - // Insert declaration for the function in which block literal is - // used. - if (CurFunctionDeclToDeclareForBlock) - RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); int flag = 0; int isa = 0; SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); @@ -4784,7 +4758,7 @@ void RewriteModernObjC::RewriteByRefVar(VarDecl *ND) { // Insert this type in global scope. It is needed by helper function. SourceLocation FunLocStart; if (CurFunctionDef) - FunLocStart = CurFunctionDef->getTypeSpecStartLoc(); + FunLocStart = getFunctionSourceLocation(CurFunctionDef); else { assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null"); FunLocStart = CurMethodDef->getLocStart(); @@ -5375,6 +5349,7 @@ Stmt *RewriteModernObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { RewriteImplicitCastObjCExpr(ICE); } #if 0 + if (ImplicitCastExpr *ICE = dyn_cast(S)) { CastExpr *Replacement = new (Context) CastExpr(ICE->getType(), ICE->getSubExpr(), @@ -5627,13 +5602,11 @@ void RewriteModernObjC::Initialize(ASTContext &context) { // These are currently generated. Preamble += "\n#pragma section(\".objc_classlist$B\", long, read, write)\n"; Preamble += "#pragma section(\".objc_catlist$B\", long, read, write)\n"; - Preamble += "#pragma section(\".objc_protolist$B\", long, read, write)\n"; Preamble += "#pragma section(\".objc_imageinfo$B\", long, read, write)\n"; Preamble += "#pragma section(\".objc_nlclslist$B\", long, read, write)\n"; Preamble += "#pragma section(\".objc_nlcatlist$B\", long, read, write)\n"; Preamble += "#pragma section(\".objc_protorefs$B\", long, read, write)\n"; // These are generated but not necessary for functionality. - Preamble += "#pragma section(\".datacoal_nt$B\", long, read, write)\n"; Preamble += "#pragma section(\".cat_cls_meth$B\", long, read, write)\n"; Preamble += "#pragma section(\".inst_meth$B\", long, read, write)\n"; Preamble += "#pragma section(\".cls_meth$B\", long, read, write)\n"; @@ -6604,7 +6577,7 @@ void RewriteModernObjC::RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, // Writer out root metadata for current protocol: struct _protocol_t Result += "\n"; if (LangOpts.MicrosoftExt) - Result += "__declspec(allocate(\".datacoal_nt$B\")) "; + Result += "static "; Result += "struct _protocol_t _OBJC_PROTOCOL_"; Result += PDecl->getNameAsString(); Result += " __attribute__ ((used, section (\"__DATA,__datacoal_nt,coalesced\"))) = {\n"; @@ -6662,11 +6635,8 @@ void RewriteModernObjC::RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, else Result += "\t0\n};\n"; - // Use this protocol meta-data to build protocol list table in section - // .objc_protolist$B - // Unspecified visibility means 'private extern'. if (LangOpts.MicrosoftExt) - Result += "__declspec(allocate(\".objc_protolist$B\")) "; + Result += "static "; Result += "struct _protocol_t *"; Result += "_OBJC_LABEL_PROTOCOL_$_"; Result += PDecl->getNameAsString(); Result += " = &_OBJC_PROTOCOL_"; Result += PDecl->getNameAsString(); diff --git a/lib/Rewrite/RewriteRope.cpp b/lib/Rewrite/RewriteRope.cpp index 6c211b28fd99..cc8de1b11a18 100644 --- a/lib/Rewrite/RewriteRope.cpp +++ b/lib/Rewrite/RewriteRope.cpp @@ -407,6 +407,11 @@ namespace { Size = LHS->size() + RHS->size(); } + ~RopePieceBTreeInterior() { + for (unsigned i = 0, e = getNumChildren(); i != e; ++i) + Children[i]->Destroy(); + } + bool isFull() const { return NumChildren == 2*WidthFactor; } unsigned getNumChildren() const { return NumChildren; } diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 5d297f9831d1..07734c7c7b57 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -40,6 +40,7 @@ add_clang_library(clangSema SemaOverload.cpp SemaPseudoObject.cpp SemaStmt.cpp + SemaStmtAttr.cpp SemaTemplate.cpp SemaTemplateDeduction.cpp SemaTemplateInstantiate.cpp diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index b531accf868a..fe63e359a19a 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -162,6 +162,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, SourceRange *ExceptionRanges, unsigned NumExceptions, Expr *NoexceptExpr, + CachedTokens *ExceptionSpecTokens, SourceLocation LocalRangeBegin, SourceLocation LocalRangeEnd, Declarator &TheDeclarator, @@ -226,6 +227,10 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, case EST_ComputedNoexcept: I.Fun.NoexceptExpr = NoexceptExpr; break; + + case EST_Delayed: + I.Fun.ExceptionSpecTokens = ExceptionSpecTokens; + break; } return I; } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index fcdfcace0ce8..30a9cd751a66 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -103,6 +103,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, AnalysisWarnings(*this) { TUScope = 0; + LoadedExternalKnownNamespaces = false; for (unsigned I = 0; I != NSAPI::NumNSNumberLiteralMethods; ++I) NSNumberLiteralMethods[I] = 0; diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index dea5e76d9e13..01c141e57f92 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -779,6 +779,13 @@ static AccessResult HasAccess(Sema &S, // that the naming class has to be derived from the effective // context. + // Emulate a MSVC bug where the creation of pointer-to-member + // to protected member of base class is allowed but only from + // a static function member functions. + if (S.getLangOpts().MicrosoftMode && !EC.Functions.empty()) + if (CXXMethodDecl* MD = dyn_cast(EC.Functions.front())) + if (MD->isStatic()) return AR_accessible; + // Despite the standard's confident wording, there is a case // where you can have an instance member that's neither in a // pointer-to-member expression nor in a member access: when diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 8b314b524f47..1550993079a7 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4471,6 +4471,11 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier, return false; } +static bool hasDelayedExceptionSpec(CXXMethodDecl *Method) { + const FunctionProtoType *Proto =Method->getType()->getAs(); + return Proto && Proto->getExceptionSpecType() == EST_Delayed; +} + /// AddOverriddenMethods - See if a method overrides any in the base classes, /// and if so, check that it's a valid override and remember it. bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { @@ -4486,7 +4491,8 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { if (CXXMethodDecl *OldMD = dyn_cast(*I)) { MD->addOverriddenMethod(OldMD->getCanonicalDecl()); if (!CheckOverridingFunctionReturnType(MD, OldMD) && - !CheckOverridingFunctionExceptionSpec(MD, OldMD) && + (hasDelayedExceptionSpec(MD) || + !CheckOverridingFunctionExceptionSpec(MD, OldMD)) && !CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) { AddedAny = true; } @@ -5834,6 +5840,9 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, } } } + + if (Method->isStatic()) + checkThisInStaticMemberFunctionType(Method); } // Extra checking for C++ overloaded operators (C++ [over.oper]). @@ -7176,8 +7185,7 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, } } -Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, - Declarator &D) { +Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { assert(getCurFunctionDecl() == 0 && "Function parsing confused"); assert(D.isFunctionDeclarator() && "Not a function declarator!"); Scope *ParentScope = FnBodyScope->getParent(); @@ -7350,6 +7358,10 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { } } + // Ensure that the function's exception specification is instantiated. + if (const FunctionProtoType *FPT = FD->getType()->getAs()) + ResolveExceptionSpec(D->getLocation(), FPT); + // Checking attributes of current function definition // dllimport attribute. DLLImportAttr *DA = FD->getAttr(); @@ -7554,7 +7566,11 @@ void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D, // Always attach attributes to the underlying decl. if (TemplateDecl *TD = dyn_cast(D)) D = TD->getTemplatedDecl(); - ProcessDeclAttributeList(S, D, Attrs.getList()); + ProcessDeclAttributeList(S, D, Attrs.getList()); + + if (CXXMethodDecl *Method = dyn_cast_or_null(D)) + if (Method->isStatic()) + checkThisInStaticMemberFunctionAttributes(Method); } @@ -7619,7 +7635,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, SourceLocation(), SourceLocation(), SourceLocation(), EST_None, SourceLocation(), - 0, 0, 0, 0, Loc, Loc, D), + 0, 0, 0, 0, 0, Loc, Loc, D), DS.getAttributes(), SourceLocation()); D.SetIdentifier(&II, Loc); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 847f03c948a3..1d251b9eb74b 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -25,6 +25,7 @@ #include "clang/AST/DeclVisitor.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/RecordLayout.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" @@ -124,14 +125,17 @@ namespace { } } -void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) { - assert(Context && "ImplicitExceptionSpecification without an ASTContext"); +void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, + CXXMethodDecl *Method) { // If we have an MSAny or unknown spec already, don't bother. if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed) return; const FunctionProtoType *Proto = Method->getType()->getAs(); + Proto = Self->ResolveExceptionSpec(CallLoc, Proto); + if (!Proto) + return; ExceptionSpecificationType EST = Proto->getExceptionSpecType(); @@ -163,7 +167,8 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) { // Check out noexcept specs. if (EST == EST_ComputedNoexcept) { - FunctionProtoType::NoexceptResult NR = Proto->getNoexceptSpec(*Context); + FunctionProtoType::NoexceptResult NR = + Proto->getNoexceptSpec(Self->Context); assert(NR != FunctionProtoType::NR_NoNoexcept && "Must have noexcept result for EST_ComputedNoexcept."); assert(NR != FunctionProtoType::NR_Dependent && @@ -187,7 +192,7 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) { for (FunctionProtoType::exception_iterator E = Proto->exception_begin(), EEnd = Proto->exception_end(); E != EEnd; ++E) - if (ExceptionsSeen.insert(Context->getCanonicalType(*E))) + if (ExceptionsSeen.insert(Self->Context.getCanonicalType(*E))) Exceptions.push_back(*E); } @@ -216,7 +221,7 @@ void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) { // implicit definition. For now, we assume that any non-nothrow expression can // throw any exception. - if (E->CanThrow(*Context)) + if (Self->canThrow(E)) ComputedEST = EST_None; } @@ -3921,7 +3926,7 @@ void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) { HadError = true; } - ImplicitExceptionSpecification Spec(Context); + ImplicitExceptionSpecification Spec(*this); bool Const; llvm::tie(Spec, Const) = ComputeDefaultedCopyCtorExceptionSpecAndConst(CD->getParent()); @@ -4030,7 +4035,7 @@ void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) { HadError = true; } - ImplicitExceptionSpecification Spec(Context); + ImplicitExceptionSpecification Spec(*this); bool Const; llvm::tie(Spec, Const) = ComputeDefaultedCopyCtorExceptionSpecAndConst(MD->getParent()); @@ -5920,10 +5925,12 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, case UnqualifiedId::IK_ConstructorName: case UnqualifiedId::IK_ConstructorTemplateId: - // C++0x inherited constructors. + // C++11 inheriting constructors. Diag(Name.getLocStart(), getLangOpts().CPlusPlus0x ? - diag::warn_cxx98_compat_using_decl_constructor : + // FIXME: Produce warn_cxx98_compat_using_decl_constructor + // instead once inheriting constructors work. + diag::err_using_decl_constructor_unsupported : diag::err_using_decl_constructor) << SS.getRange(); @@ -6813,7 +6820,7 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] - ImplicitExceptionSpecification ExceptSpec(Context); + ImplicitExceptionSpecification ExceptSpec(*this); if (ClassDecl->isInvalidDecl()) return ExceptSpec; @@ -6830,7 +6837,7 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. if (Constructor) - ExceptSpec.CalledDecl(Constructor); + ExceptSpec.CalledDecl(B->getLocStart(), Constructor); } } @@ -6844,7 +6851,7 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. if (Constructor) - ExceptSpec.CalledDecl(Constructor); + ExceptSpec.CalledDecl(B->getLocStart(), Constructor); } } @@ -6867,7 +6874,7 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // might just be ill-formed because this function attempts to refer to // a deleted function here. if (Constructor) - ExceptSpec.CalledDecl(Constructor); + ExceptSpec.CalledDecl(F->getLocation(), Constructor); } } @@ -6989,6 +6996,7 @@ void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) { const FunctionProtoType *CtorTy = CtorDecl->getType()->castAs(); if (CtorTy->getExceptionSpecType() == EST_Delayed) { + // FIXME: Don't do this unless the exception spec is needed. ImplicitExceptionSpecification Spec = ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl); FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); @@ -7189,7 +7197,7 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) { // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have // an exception-specification. - ImplicitExceptionSpecification ExceptSpec(Context); + ImplicitExceptionSpecification ExceptSpec(*this); if (ClassDecl->isInvalidDecl()) return ExceptSpec; @@ -7201,7 +7209,7 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) { continue; if (const RecordType *BaseType = B->getType()->getAs()) - ExceptSpec.CalledDecl( + ExceptSpec.CalledDecl(B->getLocStart(), LookupDestructor(cast(BaseType->getDecl()))); } @@ -7210,7 +7218,7 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) { BEnd = ClassDecl->vbases_end(); B != BEnd; ++B) { if (const RecordType *BaseType = B->getType()->getAs()) - ExceptSpec.CalledDecl( + ExceptSpec.CalledDecl(B->getLocStart(), LookupDestructor(cast(BaseType->getDecl()))); } @@ -7220,7 +7228,7 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) { F != FEnd; ++F) { if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs()) - ExceptSpec.CalledDecl( + ExceptSpec.CalledDecl(F->getLocation(), LookupDestructor(cast(RecordTy->getDecl()))); } @@ -7545,7 +7553,7 @@ std::pair Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( CXXRecordDecl *ClassDecl) { if (ClassDecl->isInvalidDecl()) - return std::make_pair(ImplicitExceptionSpecification(Context), false); + return std::make_pair(ImplicitExceptionSpecification(*this), false); // C++ [class.copy]p10: // If the class definition does not explicitly declare a copy @@ -7618,7 +7626,7 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( // Based on a similar decision made for constness in C++0x, we're erring on // the side of assuming such calls to be made regardless of whether they // actually happen. - ImplicitExceptionSpecification ExceptSpec(Context); + ImplicitExceptionSpecification ExceptSpec(*this); unsigned ArgQuals = HasConstCopyAssignment ? Qualifiers::Const : 0; for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); @@ -7630,7 +7638,7 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( = cast(Base->getType()->getAs()->getDecl()); if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl, ArgQuals, false, 0)) - ExceptSpec.CalledDecl(CopyAssign); + ExceptSpec.CalledDecl(Base->getLocStart(), CopyAssign); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), @@ -7640,7 +7648,7 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( = cast(Base->getType()->getAs()->getDecl()); if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl, ArgQuals, false, 0)) - ExceptSpec.CalledDecl(CopyAssign); + ExceptSpec.CalledDecl(Base->getLocStart(), CopyAssign); } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), @@ -7651,7 +7659,7 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(FieldClassDecl, ArgQuals, false, 0)) - ExceptSpec.CalledDecl(CopyAssign); + ExceptSpec.CalledDecl(Field->getLocation(), CopyAssign); } } @@ -7664,7 +7672,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { // for determining the argument type of the operator. Note also that // operators taking an object instead of a reference are allowed. - ImplicitExceptionSpecification Spec(Context); + ImplicitExceptionSpecification Spec(*this); bool Const; llvm::tie(Spec, Const) = ComputeDefaultedCopyAssignmentExceptionSpecAndConst(ClassDecl); @@ -8031,7 +8039,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, Sema::ImplicitExceptionSpecification Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { - ImplicitExceptionSpecification ExceptSpec(Context); + ImplicitExceptionSpecification ExceptSpec(*this); if (ClassDecl->isInvalidDecl()) return ExceptSpec; @@ -8058,7 +8066,7 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { = cast(Base->getType()->getAs()->getDecl()); if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl, false, 0)) - ExceptSpec.CalledDecl(MoveAssign); + ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), @@ -8068,7 +8076,7 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { = cast(Base->getType()->getAs()->getDecl()); if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl, false, 0)) - ExceptSpec.CalledDecl(MoveAssign); + ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign); } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), @@ -8079,7 +8087,7 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(FieldClassDecl, false, 0)) - ExceptSpec.CalledDecl(MoveAssign); + ExceptSpec.CalledDecl(Field->getLocation(), MoveAssign); } } @@ -8577,7 +8585,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, std::pair Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { if (ClassDecl->isInvalidDecl()) - return std::make_pair(ImplicitExceptionSpecification(Context), false); + return std::make_pair(ImplicitExceptionSpecification(*this), false); // C++ [class.copy]p5: // The implicitly-declared copy constructor for a class X will @@ -8638,7 +8646,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] - ImplicitExceptionSpecification ExceptSpec(Context); + ImplicitExceptionSpecification ExceptSpec(*this); unsigned Quals = HasConstCopyConstructor? Qualifiers::Const : 0; for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); @@ -8652,7 +8660,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { = cast(Base->getType()->getAs()->getDecl()); if (CXXConstructorDecl *CopyConstructor = LookupCopyingConstructor(BaseClassDecl, Quals)) - ExceptSpec.CalledDecl(CopyConstructor); + ExceptSpec.CalledDecl(Base->getLocStart(), CopyConstructor); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), BaseEnd = ClassDecl->vbases_end(); @@ -8662,7 +8670,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { = cast(Base->getType()->getAs()->getDecl()); if (CXXConstructorDecl *CopyConstructor = LookupCopyingConstructor(BaseClassDecl, Quals)) - ExceptSpec.CalledDecl(CopyConstructor); + ExceptSpec.CalledDecl(Base->getLocStart(), CopyConstructor); } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); @@ -8672,7 +8680,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { if (CXXConstructorDecl *CopyConstructor = LookupCopyingConstructor(FieldClassDecl, Quals)) - ExceptSpec.CalledDecl(CopyConstructor); + ExceptSpec.CalledDecl(Field->getLocation(), CopyConstructor); } } @@ -8685,7 +8693,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( // If the class definition does not explicitly declare a copy // constructor, one is declared implicitly. - ImplicitExceptionSpecification Spec(Context); + ImplicitExceptionSpecification Spec(*this); bool Const; llvm::tie(Spec, Const) = ComputeDefaultedCopyCtorExceptionSpecAndConst(ClassDecl); @@ -8783,7 +8791,7 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] - ImplicitExceptionSpecification ExceptSpec(Context); + ImplicitExceptionSpecification ExceptSpec(*this); if (ClassDecl->isInvalidDecl()) return ExceptSpec; @@ -8800,7 +8808,7 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. if (Constructor) - ExceptSpec.CalledDecl(Constructor); + ExceptSpec.CalledDecl(B->getLocStart(), Constructor); } } @@ -8814,7 +8822,7 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. if (Constructor) - ExceptSpec.CalledDecl(Constructor); + ExceptSpec.CalledDecl(B->getLocStart(), Constructor); } } @@ -8832,7 +8840,7 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // might just be ill-formed because this function attempts to refer to // a deleted function here. if (Constructor) - ExceptSpec.CalledDecl(Constructor); + ExceptSpec.CalledDecl(F->getLocation(), Constructor); } } @@ -11053,6 +11061,265 @@ void Sema::CheckDelegatingCtorCycles() { (*CI)->setInvalidDecl(); } +namespace { + /// \brief AST visitor that finds references to the 'this' expression. + class FindCXXThisExpr : public RecursiveASTVisitor { + Sema &S; + + public: + explicit FindCXXThisExpr(Sema &S) : S(S) { } + + bool VisitCXXThisExpr(CXXThisExpr *E) { + S.Diag(E->getLocation(), diag::err_this_static_member_func) + << E->isImplicit(); + return false; + } + }; +} + +bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) { + TypeSourceInfo *TSInfo = Method->getTypeSourceInfo(); + if (!TSInfo) + return false; + + TypeLoc TL = TSInfo->getTypeLoc(); + FunctionProtoTypeLoc *ProtoTL = dyn_cast(&TL); + if (!ProtoTL) + return false; + + // C++11 [expr.prim.general]p3: + // [The expression this] shall not appear before the optional + // cv-qualifier-seq and it shall not appear within the declaration of a + // static member function (although its type and value category are defined + // within a static member function as they are within a non-static member + // function). [ Note: this is because declaration matching does not occur + // until the complete declarator is known. - end note ] + const FunctionProtoType *Proto = ProtoTL->getTypePtr(); + FindCXXThisExpr Finder(*this); + + // If the return type came after the cv-qualifier-seq, check it now. + if (Proto->hasTrailingReturn() && + !Finder.TraverseTypeLoc(ProtoTL->getResultLoc())) + return true; + + // Check the exception specification. + if (checkThisInStaticMemberFunctionExceptionSpec(Method)) + return true; + + return checkThisInStaticMemberFunctionAttributes(Method); +} + +bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) { + TypeSourceInfo *TSInfo = Method->getTypeSourceInfo(); + if (!TSInfo) + return false; + + TypeLoc TL = TSInfo->getTypeLoc(); + FunctionProtoTypeLoc *ProtoTL = dyn_cast(&TL); + if (!ProtoTL) + return false; + + const FunctionProtoType *Proto = ProtoTL->getTypePtr(); + FindCXXThisExpr Finder(*this); + + switch (Proto->getExceptionSpecType()) { + case EST_Uninstantiated: + case EST_BasicNoexcept: + case EST_Delayed: + case EST_DynamicNone: + case EST_MSAny: + case EST_None: + break; + + case EST_ComputedNoexcept: + if (!Finder.TraverseStmt(Proto->getNoexceptExpr())) + return true; + + case EST_Dynamic: + for (FunctionProtoType::exception_iterator E = Proto->exception_begin(), + EEnd = Proto->exception_end(); + E != EEnd; ++E) { + if (!Finder.TraverseType(*E)) + return true; + } + break; + } + + return false; +} + +bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) { + FindCXXThisExpr Finder(*this); + + // Check attributes. + for (Decl::attr_iterator A = Method->attr_begin(), AEnd = Method->attr_end(); + A != AEnd; ++A) { + // FIXME: This should be emitted by tblgen. + Expr *Arg = 0; + ArrayRef Args; + if (GuardedByAttr *G = dyn_cast(*A)) + Arg = G->getArg(); + else if (PtGuardedByAttr *G = dyn_cast(*A)) + Arg = G->getArg(); + else if (AcquiredAfterAttr *AA = dyn_cast(*A)) + Args = ArrayRef(AA->args_begin(), AA->args_size()); + else if (AcquiredBeforeAttr *AB = dyn_cast(*A)) + Args = ArrayRef(AB->args_begin(), AB->args_size()); + else if (ExclusiveLockFunctionAttr *ELF + = dyn_cast(*A)) + Args = ArrayRef(ELF->args_begin(), ELF->args_size()); + else if (SharedLockFunctionAttr *SLF + = dyn_cast(*A)) + Args = ArrayRef(SLF->args_begin(), SLF->args_size()); + else if (ExclusiveTrylockFunctionAttr *ETLF + = dyn_cast(*A)) { + Arg = ETLF->getSuccessValue(); + Args = ArrayRef(ETLF->args_begin(), ETLF->args_size()); + } else if (SharedTrylockFunctionAttr *STLF + = dyn_cast(*A)) { + Arg = STLF->getSuccessValue(); + Args = ArrayRef(STLF->args_begin(), STLF->args_size()); + } else if (UnlockFunctionAttr *UF = dyn_cast(*A)) + Args = ArrayRef(UF->args_begin(), UF->args_size()); + else if (LockReturnedAttr *LR = dyn_cast(*A)) + Arg = LR->getArg(); + else if (LocksExcludedAttr *LE = dyn_cast(*A)) + Args = ArrayRef(LE->args_begin(), LE->args_size()); + else if (ExclusiveLocksRequiredAttr *ELR + = dyn_cast(*A)) + Args = ArrayRef(ELR->args_begin(), ELR->args_size()); + else if (SharedLocksRequiredAttr *SLR + = dyn_cast(*A)) + Args = ArrayRef(SLR->args_begin(), SLR->args_size()); + + if (Arg && !Finder.TraverseStmt(Arg)) + return true; + + for (unsigned I = 0, N = Args.size(); I != N; ++I) { + if (!Finder.TraverseStmt(Args[I])) + return true; + } + } + + return false; +} + +void +Sema::checkExceptionSpecification(ExceptionSpecificationType EST, + ArrayRef DynamicExceptions, + ArrayRef DynamicExceptionRanges, + Expr *NoexceptExpr, + llvm::SmallVectorImpl &Exceptions, + FunctionProtoType::ExtProtoInfo &EPI) { + Exceptions.clear(); + EPI.ExceptionSpecType = EST; + if (EST == EST_Dynamic) { + Exceptions.reserve(DynamicExceptions.size()); + for (unsigned ei = 0, ee = DynamicExceptions.size(); ei != ee; ++ei) { + // FIXME: Preserve type source info. + QualType ET = GetTypeFromParser(DynamicExceptions[ei]); + + SmallVector Unexpanded; + collectUnexpandedParameterPacks(ET, Unexpanded); + if (!Unexpanded.empty()) { + DiagnoseUnexpandedParameterPacks(DynamicExceptionRanges[ei].getBegin(), + UPPC_ExceptionType, + Unexpanded); + continue; + } + + // Check that the type is valid for an exception spec, and + // drop it if not. + if (!CheckSpecifiedExceptionType(ET, DynamicExceptionRanges[ei])) + Exceptions.push_back(ET); + } + EPI.NumExceptions = Exceptions.size(); + EPI.Exceptions = Exceptions.data(); + return; + } + + if (EST == EST_ComputedNoexcept) { + // If an error occurred, there's no expression here. + if (NoexceptExpr) { + assert((NoexceptExpr->isTypeDependent() || + NoexceptExpr->getType()->getCanonicalTypeUnqualified() == + Context.BoolTy) && + "Parser should have made sure that the expression is boolean"); + if (NoexceptExpr && DiagnoseUnexpandedParameterPack(NoexceptExpr)) { + EPI.ExceptionSpecType = EST_BasicNoexcept; + return; + } + + if (!NoexceptExpr->isValueDependent()) + NoexceptExpr = VerifyIntegerConstantExpression(NoexceptExpr, 0, + PDiag(diag::err_noexcept_needs_constant_expression), + /*AllowFold*/ false).take(); + EPI.NoexceptExpr = NoexceptExpr; + } + return; + } +} + +void Sema::actOnDelayedExceptionSpecification(Decl *MethodD, + ExceptionSpecificationType EST, + SourceRange SpecificationRange, + ArrayRef DynamicExceptions, + ArrayRef DynamicExceptionRanges, + Expr *NoexceptExpr) { + if (!MethodD) + return; + + // Dig out the method we're referring to. + CXXMethodDecl *Method = 0; + if (FunctionTemplateDecl *FunTmpl = dyn_cast(MethodD)) + Method = dyn_cast(FunTmpl->getTemplatedDecl()); + else + Method = dyn_cast(MethodD); + + if (!Method) + return; + + // Dig out the prototype. This should never fail. + const FunctionProtoType *Proto + = dyn_cast(Method->getType()); + if (!Proto) + return; + + // Check the exception specification. + llvm::SmallVector Exceptions; + FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo(); + checkExceptionSpecification(EST, DynamicExceptions, DynamicExceptionRanges, + NoexceptExpr, Exceptions, EPI); + + // Rebuild the function type. + QualType T = Context.getFunctionType(Proto->getResultType(), + Proto->arg_type_begin(), + Proto->getNumArgs(), + EPI); + if (TypeSourceInfo *TSInfo = Method->getTypeSourceInfo()) { + // FIXME: When we get proper type location information for exceptions, + // we'll also have to rebuild the TypeSourceInfo. For now, we just patch + // up the TypeSourceInfo; + assert(TypeLoc::getFullDataSizeForType(T) + == TypeLoc::getFullDataSizeForType(Method->getType()) && + "TypeLoc size mismatch with delayed exception specification"); + TSInfo->overrideType(T); + } + + Method->setType(T); + + if (Method->isStatic()) + checkThisInStaticMemberFunctionExceptionSpec(Method); + + if (Method->isVirtual()) { + // Check overrides, which we previously had to delay. + for (CXXMethodDecl::method_iterator O = Method->begin_overridden_methods(), + OEnd = Method->end_overridden_methods(); + O != OEnd; ++O) + CheckOverridingFunctionExceptionSpec(Method, *O); + } +} + /// IdentifyCUDATarget - Determine the CUDA compilation target for this function Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) { // Implicitly declared functions (e.g. copy constructors) are diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 42221f8df48a..14b24341d094 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -96,6 +96,26 @@ bool Sema::CheckDistantExceptionSpec(QualType T) { return FnT->hasExceptionSpec(); } +const FunctionProtoType * +Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { + // FIXME: If FD is a special member, we should delay computing its exception + // specification until this point. + if (FPT->getExceptionSpecType() != EST_Uninstantiated) + return FPT; + + FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl(); + const FunctionProtoType *SourceFPT = + SourceDecl->getType()->castAs(); + + if (SourceFPT->getExceptionSpecType() != EST_Uninstantiated) + return SourceFPT; + + // Instantiate the exception specification now. + InstantiateExceptionSpec(Loc, SourceDecl); + + return SourceDecl->getType()->castAs(); +} + bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator(); bool IsOperatorNew = OO == OO_New || OO == OO_Array_New; @@ -104,7 +124,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { unsigned DiagID = diag::err_mismatched_exception_spec; if (getLangOpts().MicrosoftExt) DiagID = diag::warn_mismatched_exception_spec; - + if (!CheckEquivalentExceptionSpec(PDiag(DiagID), PDiag(diag::note_previous_declaration), Old->getType()->getAs(), @@ -295,6 +315,13 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, if (MissingEmptyExceptionSpecification) *MissingEmptyExceptionSpecification = false; + Old = ResolveExceptionSpec(NewLoc, Old); + if (!Old) + return false; + New = ResolveExceptionSpec(NewLoc, New); + if (!New) + return false; + // C++0x [except.spec]p3: Two exception-specifications are compatible if: // - both are non-throwing, regardless of their form, // - both have the form noexcept(constant-expression) and the constant- @@ -318,6 +345,7 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, ExceptionSpecificationType NewEST = New->getExceptionSpecType(); assert(OldEST != EST_Delayed && NewEST != EST_Delayed && + OldEST != EST_Uninstantiated && NewEST != EST_Uninstantiated && "Shouldn't see unknown exception specifications here"); // Shortcut the case where both have no spec. @@ -483,6 +511,14 @@ bool Sema::CheckExceptionSpecSubset( if (!SubLoc.isValid()) SubLoc = SuperLoc; + // Resolve the exception specifications, if needed. + Superset = ResolveExceptionSpec(SuperLoc, Superset); + if (!Superset) + return false; + Subset = ResolveExceptionSpec(SubLoc, Subset); + if (!Subset) + return false; + ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType(); // If superset contains everything, we're done. @@ -507,6 +543,7 @@ bool Sema::CheckExceptionSpecSubset( ExceptionSpecificationType SubEST = Subset->getExceptionSpecType(); assert(SuperEST != EST_Delayed && SubEST != EST_Delayed && + SuperEST != EST_Uninstantiated && SubEST != EST_Uninstantiated && "Shouldn't see unknown exception specifications here"); // It does not. If the subset contains everything, we've failed. @@ -726,4 +763,324 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, New->getLocation()); } +static CanThrowResult canSubExprsThrow(Sema &S, const Expr *CE) { + Expr *E = const_cast(CE); + CanThrowResult R = CT_Cannot; + for (Expr::child_range I = E->children(); I && R != CT_Can; ++I) + R = mergeCanThrow(R, S.canThrow(cast(*I))); + return R; +} + +static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, + const Decl *D, + bool NullThrows = true) { + if (!D) + return NullThrows ? CT_Can : CT_Cannot; + + // See if we can get a function type from the decl somehow. + const ValueDecl *VD = dyn_cast(D); + if (!VD) // If we have no clue what we're calling, assume the worst. + return CT_Can; + + // As an extension, we assume that __attribute__((nothrow)) functions don't + // throw. + if (isa(D) && D->hasAttr()) + return CT_Cannot; + + QualType T = VD->getType(); + const FunctionProtoType *FT; + if ((FT = T->getAs())) { + } else if (const PointerType *PT = T->getAs()) + FT = PT->getPointeeType()->getAs(); + else if (const ReferenceType *RT = T->getAs()) + FT = RT->getPointeeType()->getAs(); + else if (const MemberPointerType *MT = T->getAs()) + FT = MT->getPointeeType()->getAs(); + else if (const BlockPointerType *BT = T->getAs()) + FT = BT->getPointeeType()->getAs(); + + if (!FT) + return CT_Can; + + FT = S.ResolveExceptionSpec(E->getLocStart(), FT); + if (!FT) + return CT_Can; + + if (FT->getExceptionSpecType() == EST_Delayed) { + // FIXME: Try to resolve a delayed exception spec in ResolveExceptionSpec. + assert(isa(D) && + "only constructor exception specs can be unknown"); + S.Diag(E->getLocStart(), diag::err_exception_spec_unknown) + << E->getSourceRange(); + return CT_Can; + } + + return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can; +} + +static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) { + if (DC->isTypeDependent()) + return CT_Dependent; + + if (!DC->getTypeAsWritten()->isReferenceType()) + return CT_Cannot; + + if (DC->getSubExpr()->isTypeDependent()) + return CT_Dependent; + + return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot; +} + +static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) { + if (DC->isTypeOperand()) + return CT_Cannot; + + Expr *Op = DC->getExprOperand(); + if (Op->isTypeDependent()) + return CT_Dependent; + + const RecordType *RT = Op->getType()->getAs(); + if (!RT) + return CT_Cannot; + + if (!cast(RT->getDecl())->isPolymorphic()) + return CT_Cannot; + + if (Op->Classify(S.Context).isPRValue()) + return CT_Cannot; + + return CT_Can; +} + +CanThrowResult Sema::canThrow(const Expr *E) { + // C++ [expr.unary.noexcept]p3: + // [Can throw] if in a potentially-evaluated context the expression would + // contain: + switch (E->getStmtClass()) { + case Expr::CXXThrowExprClass: + // - a potentially evaluated throw-expression + return CT_Can; + + case Expr::CXXDynamicCastExprClass: { + // - a potentially evaluated dynamic_cast expression dynamic_cast(v), + // where T is a reference type, that requires a run-time check + CanThrowResult CT = canDynamicCastThrow(cast(E)); + if (CT == CT_Can) + return CT; + return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + } + + case Expr::CXXTypeidExprClass: + // - a potentially evaluated typeid expression applied to a glvalue + // expression whose type is a polymorphic class type + return canTypeidThrow(*this, cast(E)); + + // - a potentially evaluated call to a function, member function, function + // pointer, or member function pointer that does not have a non-throwing + // exception-specification + case Expr::CallExprClass: + case Expr::CXXMemberCallExprClass: + case Expr::CXXOperatorCallExprClass: + case Expr::UserDefinedLiteralClass: { + const CallExpr *CE = cast(E); + CanThrowResult CT; + if (E->isTypeDependent()) + CT = CT_Dependent; + else if (isa(CE->getCallee()->IgnoreParens())) + CT = CT_Cannot; + else + CT = canCalleeThrow(*this, E, CE->getCalleeDecl()); + if (CT == CT_Can) + return CT; + return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + } + + case Expr::CXXConstructExprClass: + case Expr::CXXTemporaryObjectExprClass: { + CanThrowResult CT = canCalleeThrow(*this, E, + cast(E)->getConstructor()); + if (CT == CT_Can) + return CT; + return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + } + + case Expr::LambdaExprClass: { + const LambdaExpr *Lambda = cast(E); + CanThrowResult CT = CT_Cannot; + for (LambdaExpr::capture_init_iterator Cap = Lambda->capture_init_begin(), + CapEnd = Lambda->capture_init_end(); + Cap != CapEnd; ++Cap) + CT = mergeCanThrow(CT, canThrow(*Cap)); + return CT; + } + + case Expr::CXXNewExprClass: { + CanThrowResult CT; + if (E->isTypeDependent()) + CT = CT_Dependent; + else + CT = canCalleeThrow(*this, E, cast(E)->getOperatorNew()); + if (CT == CT_Can) + return CT; + return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + } + + case Expr::CXXDeleteExprClass: { + CanThrowResult CT; + QualType DTy = cast(E)->getDestroyedType(); + if (DTy.isNull() || DTy->isDependentType()) { + CT = CT_Dependent; + } else { + CT = canCalleeThrow(*this, E, + cast(E)->getOperatorDelete()); + if (const RecordType *RT = DTy->getAs()) { + const CXXRecordDecl *RD = cast(RT->getDecl()); + CT = mergeCanThrow(CT, canCalleeThrow(*this, E, RD->getDestructor())); + } + if (CT == CT_Can) + return CT; + } + return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + } + + case Expr::CXXBindTemporaryExprClass: { + // The bound temporary has to be destroyed again, which might throw. + CanThrowResult CT = canCalleeThrow(*this, E, + cast(E)->getTemporary()->getDestructor()); + if (CT == CT_Can) + return CT; + return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + } + + // ObjC message sends are like function calls, but never have exception + // specs. + case Expr::ObjCMessageExprClass: + case Expr::ObjCPropertyRefExprClass: + case Expr::ObjCSubscriptRefExprClass: + return CT_Can; + + // All the ObjC literals that are implemented as calls are + // potentially throwing unless we decide to close off that + // possibility. + case Expr::ObjCArrayLiteralClass: + case Expr::ObjCDictionaryLiteralClass: + case Expr::ObjCNumericLiteralClass: + return CT_Can; + + // Many other things have subexpressions, so we have to test those. + // Some are simple: + case Expr::ConditionalOperatorClass: + case Expr::CompoundLiteralExprClass: + case Expr::CXXConstCastExprClass: + case Expr::CXXDefaultArgExprClass: + case Expr::CXXReinterpretCastExprClass: + case Expr::DesignatedInitExprClass: + case Expr::ExprWithCleanupsClass: + case Expr::ExtVectorElementExprClass: + case Expr::InitListExprClass: + case Expr::MemberExprClass: + case Expr::ObjCIsaExprClass: + case Expr::ObjCIvarRefExprClass: + case Expr::ParenExprClass: + case Expr::ParenListExprClass: + case Expr::ShuffleVectorExprClass: + case Expr::VAArgExprClass: + return canSubExprsThrow(*this, E); + + // Some might be dependent for other reasons. + case Expr::ArraySubscriptExprClass: + case Expr::BinaryOperatorClass: + case Expr::CompoundAssignOperatorClass: + case Expr::CStyleCastExprClass: + case Expr::CXXStaticCastExprClass: + case Expr::CXXFunctionalCastExprClass: + case Expr::ImplicitCastExprClass: + case Expr::MaterializeTemporaryExprClass: + case Expr::UnaryOperatorClass: { + CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot; + return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + } + + // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms. + case Expr::StmtExprClass: + return CT_Can; + + case Expr::ChooseExprClass: + if (E->isTypeDependent() || E->isValueDependent()) + return CT_Dependent; + return canThrow(cast(E)->getChosenSubExpr(Context)); + + case Expr::GenericSelectionExprClass: + if (cast(E)->isResultDependent()) + return CT_Dependent; + return canThrow(cast(E)->getResultExpr()); + + // Some expressions are always dependent. + case Expr::CXXDependentScopeMemberExprClass: + case Expr::CXXUnresolvedConstructExprClass: + case Expr::DependentScopeDeclRefExprClass: + return CT_Dependent; + + case Expr::AsTypeExprClass: + case Expr::BinaryConditionalOperatorClass: + case Expr::BlockExprClass: + case Expr::CUDAKernelCallExprClass: + case Expr::DeclRefExprClass: + case Expr::ObjCBridgedCastExprClass: + case Expr::ObjCIndirectCopyRestoreExprClass: + case Expr::ObjCProtocolExprClass: + case Expr::ObjCSelectorExprClass: + case Expr::OffsetOfExprClass: + case Expr::PackExpansionExprClass: + case Expr::PseudoObjectExprClass: + case Expr::SubstNonTypeTemplateParmExprClass: + case Expr::SubstNonTypeTemplateParmPackExprClass: + case Expr::UnaryExprOrTypeTraitExprClass: + case Expr::UnresolvedLookupExprClass: + case Expr::UnresolvedMemberExprClass: + // FIXME: Can any of the above throw? If so, when? + return CT_Cannot; + + case Expr::AddrLabelExprClass: + case Expr::ArrayTypeTraitExprClass: + case Expr::AtomicExprClass: + case Expr::BinaryTypeTraitExprClass: + case Expr::TypeTraitExprClass: + case Expr::CXXBoolLiteralExprClass: + case Expr::CXXNoexceptExprClass: + case Expr::CXXNullPtrLiteralExprClass: + case Expr::CXXPseudoDestructorExprClass: + case Expr::CXXScalarValueInitExprClass: + case Expr::CXXThisExprClass: + case Expr::CXXUuidofExprClass: + case Expr::CharacterLiteralClass: + case Expr::ExpressionTraitExprClass: + case Expr::FloatingLiteralClass: + case Expr::GNUNullExprClass: + case Expr::ImaginaryLiteralClass: + case Expr::ImplicitValueInitExprClass: + case Expr::IntegerLiteralClass: + case Expr::ObjCEncodeExprClass: + case Expr::ObjCStringLiteralClass: + case Expr::ObjCBoolLiteralExprClass: + case Expr::OpaqueValueExprClass: + case Expr::PredefinedExprClass: + case Expr::SizeOfPackExprClass: + case Expr::StringLiteralClass: + case Expr::UnaryTypeTraitExprClass: + // These expressions can never throw. + return CT_Cannot; + +#define STMT(CLASS, PARENT) case Expr::CLASS##Class: +#define STMT_RANGE(Base, First, Last) +#define LAST_STMT_RANGE(BASE, FIRST, LAST) +#define EXPR(CLASS, PARENT) +#define ABSTRACT_STMT(STMT) +#include "clang/AST/StmtNodes.inc" + case Expr::NoStmtClass: + llvm_unreachable("Invalid class for expression"); + } + llvm_unreachable("Bogus StmtClass"); +} + } // end namespace clang diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 0d0f2f5b99a4..d2e0e6b63b4d 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9438,10 +9438,11 @@ ExprResult Sema::VerifyIntegerConstantExpression(Expr *E, PDiag(diag::err_expr_not_ice) << LangOpts.CPlusPlus); } -ExprResult Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, - PartialDiagnostic NotIceDiag, - bool AllowFold, - PartialDiagnostic FoldDiag) { +ExprResult +Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, + const PartialDiagnostic &NotIceDiag, + bool AllowFold, + const PartialDiagnostic &FoldDiag) { SourceLocation DiagLoc = E->getLocStart(); if (getLangOpts().CPlusPlus0x) { @@ -9773,6 +9774,12 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) { // FIXME: Is this really right? if (CurContext == Func) return; + // Instantiate the exception specification for any function which is + // used: CodeGen will need it. + const FunctionProtoType *FPT = Func->getType()->getAs(); + if (FPT && FPT->getExceptionSpecType() == EST_Uninstantiated) + InstantiateExceptionSpec(Loc, Func); + // Implicit instantiation of function templates and member functions of // class templates. if (Func->isImplicitlyInstantiable()) { @@ -11268,22 +11275,6 @@ ExprResult Sema::ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { assert((Kind == tok::kw___objc_yes || Kind == tok::kw___objc_no) && "Unknown Objective-C Boolean value!"); - QualType ObjCBoolLiteralQT = Context.ObjCBuiltinBoolTy; - // signed char is the default type for boolean literals. Use 'BOOL' - // instead, if BOOL typedef is visible in its scope instead. - Decl *TD = - LookupSingleName(TUScope, &Context.Idents.get("BOOL"), - SourceLocation(), LookupOrdinaryName); - if (TypedefDecl *BoolTD = dyn_cast_or_null(TD)) { - QualType QT = BoolTD->getUnderlyingType(); - if (!QT->isIntegralOrUnscopedEnumerationType()) { - Diag(OpLoc, diag::warn_bool_for_boolean_literal) << QT; - Diag(BoolTD->getLocation(), diag::note_previous_declaration); - } - else - ObjCBoolLiteralQT = QT; - } - return Owned(new (Context) ObjCBoolLiteralExpr(Kind == tok::kw___objc_yes, - ObjCBoolLiteralQT, OpLoc)); + Context.ObjCBuiltinBoolTy, OpLoc)); } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 31a8115f0b48..af86cb2c43e1 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -654,23 +654,44 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, QualType Sema::getCurrentThisType() { DeclContext *DC = getFunctionLevelDeclContext(); - QualType ThisTy; + QualType ThisTy = CXXThisTypeOverride; if (CXXMethodDecl *method = dyn_cast(DC)) { if (method && method->isInstance()) ThisTy = method->getThisType(Context); - } else if (CXXRecordDecl *RD = dyn_cast(DC)) { - // C++0x [expr.prim]p4: - // Otherwise, if a member-declarator declares a non-static data member - // of a class X, the expression this is a prvalue of type "pointer to X" - // within the optional brace-or-equal-initializer. - Scope *S = getScopeForContext(DC); - if (!S || S->getFlags() & Scope::ThisScope) - ThisTy = Context.getPointerType(Context.getRecordType(RD)); } - + return ThisTy; } +Sema::CXXThisScopeRAII::CXXThisScopeRAII(Sema &S, + Decl *ContextDecl, + unsigned CXXThisTypeQuals, + bool Enabled) + : S(S), OldCXXThisTypeOverride(S.CXXThisTypeOverride), Enabled(false) +{ + if (!Enabled || !ContextDecl) + return; + + CXXRecordDecl *Record = 0; + if (ClassTemplateDecl *Template = dyn_cast(ContextDecl)) + Record = Template->getTemplatedDecl(); + else + Record = cast(ContextDecl); + + S.CXXThisTypeOverride + = S.Context.getPointerType( + S.Context.getRecordType(Record).withCVRQualifiers(CXXThisTypeQuals)); + + this->Enabled = true; +} + + +Sema::CXXThisScopeRAII::~CXXThisScopeRAII() { + if (Enabled) { + S.CXXThisTypeOverride = OldCXXThisTypeOverride; + } +} + void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) { // We don't need to capture this in an unevaluated context. if (ExprEvalContexts.back().Context == Unevaluated && !Explicit) @@ -739,6 +760,18 @@ ExprResult Sema::ActOnCXXThis(SourceLocation Loc) { return Owned(new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false)); } +bool Sema::isThisOutsideMemberFunctionBody(QualType BaseType) { + // If we're outside the body of a member function, then we'll have a specified + // type for 'this'. + if (CXXThisTypeOverride.isNull()) + return false; + + // Determine whether we're looking into a class that's currently being + // defined. + CXXRecordDecl *Class = BaseType->getAsCXXRecordDecl(); + return Class && Class->isBeingDefined(); +} + ExprResult Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, SourceLocation LParenLoc, @@ -3102,6 +3135,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, FoundAssign = true; const FunctionProtoType *CPT = Operator->getType()->getAs(); + CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); + if (!CPT) + return false; if (CPT->getExceptionSpecType() == EST_Delayed) return false; if (!CPT->isNothrow(Self.Context)) @@ -3141,6 +3177,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, FoundConstructor = true; const FunctionProtoType *CPT = Constructor->getType()->getAs(); + CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); + if (!CPT) + return false; if (CPT->getExceptionSpecType() == EST_Delayed) return false; // FIXME: check whether evaluating default arguments can throw. @@ -3176,6 +3215,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, if (Constructor->isDefaultConstructor()) { const FunctionProtoType *CPT = Constructor->getType()->getAs(); + CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); + if (!CPT) + return false; if (CPT->getExceptionSpecType() == EST_Delayed) return false; // TODO: check whether evaluating default arguments can throw. @@ -4784,8 +4826,13 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, return Owned(Base); } - // The object type must be complete (or dependent). + // The object type must be complete (or dependent), or + // C++11 [expr.prim.general]p3: + // Unlike the object expression in other contexts, *this is not required to + // be of complete type for purposes of class member access (5.2.5) outside + // the member function body. if (!BaseType->isDependentType() && + !isThisOutsideMemberFunctionBody(BaseType) && RequireCompleteType(OpLoc, BaseType, PDiag(diag::err_incomplete_member_access))) return ExprError(); @@ -5165,9 +5212,9 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, SourceLocation RParen) { + CanThrowResult CanThrow = canThrow(Operand); return Owned(new (Context) CXXNoexceptExpr(Context.BoolTy, Operand, - Operand->CanThrow(Context), - KeyLoc, RParen)); + CanThrow, KeyLoc, RParen)); } ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation, diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index 26b88a2a7ee1..6c84caa3f371 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -101,16 +101,8 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, DeclContext *DC = SemaRef.getFunctionLevelDeclContext(); - bool isStaticContext = - (!isa(DC) || - cast(DC)->isStatic()); - - // C++0x [expr.prim]p4: - // Otherwise, if a member-declarator declares a non-static data member - // of a class X, the expression this is a prvalue of type "pointer to X" - // within the optional brace-or-equal-initializer. - if (CurScope->getFlags() & Scope::ThisScope) - isStaticContext = false; + bool isStaticContext = SemaRef.CXXThisTypeOverride.isNull() && + (!isa(DC) || cast(DC)->isStatic()); if (R.isUnresolvableResult()) return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved; @@ -549,12 +541,13 @@ class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback { } static bool -LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, +LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, SourceRange BaseRange, const RecordType *RTy, SourceLocation OpLoc, CXXScopeSpec &SS, bool HasTemplateArgs) { RecordDecl *RDecl = RTy->getDecl(); - if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), + if (!SemaRef.isThisOutsideMemberFunctionBody(QualType(RTy, 0)) && + SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), SemaRef.PDiag(diag::err_typecheck_incomplete_tag) << BaseRange)) return true; diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 966eb90306a9..f003bddc05bb 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -3165,7 +3165,7 @@ LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc, namespace { typedef llvm::StringMap TypoResultsMap; -typedef std::map TypoEditDistanceMap; +typedef std::map TypoEditDistanceMap; static const unsigned MaxTypoDistanceResultSets = 5; @@ -3187,14 +3187,6 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer { : Typo(Typo->getName()), SemaRef(SemaRef) { } - ~TypoCorrectionConsumer() { - for (TypoEditDistanceMap::iterator I = BestResults.begin(), - IEnd = BestResults.end(); - I != IEnd; - ++I) - delete I->second; - } - virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, bool InBaseClass); void FoundName(StringRef Name); @@ -3212,7 +3204,7 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer { bool empty() const { return BestResults.empty(); } TypoCorrection &operator[](StringRef Name) { - return (*BestResults.begin()->second)[Name]; + return BestResults.begin()->second[Name]; } unsigned getBestEditDistance(bool Normalized) { @@ -3276,11 +3268,9 @@ void TypoCorrectionConsumer::addName(StringRef Name, void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) { StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName(); - TypoResultsMap *& Map = BestResults[Correction.getEditDistance(false)]; - if (!Map) - Map = new TypoResultsMap; + TypoResultsMap &Map = BestResults[Correction.getEditDistance(false)]; - TypoCorrection &CurrentCorrection = (*Map)[Name]; + TypoCorrection &CurrentCorrection = Map[Name]; if (!CurrentCorrection || // FIXME: The following should be rolled up into an operator< on // TypoCorrection with a more principled definition. @@ -3289,12 +3279,8 @@ void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) { CurrentCorrection.getAsString(SemaRef.getLangOpts())) CurrentCorrection = Correction; - while (BestResults.size() > MaxTypoDistanceResultSets) { - TypoEditDistanceMap::iterator Last = BestResults.end(); - --Last; - delete Last->second; - BestResults.erase(Last); - } + while (BestResults.size() > MaxTypoDistanceResultSets) + erase(llvm::prior(BestResults.end())); } // Fill the supplied vector with the IdentifierInfo pointers for each piece of @@ -3882,8 +3868,8 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, while (!Consumer.empty()) { TypoCorrectionConsumer::distance_iterator DI = Consumer.begin(); unsigned ED = DI->first; - for (TypoCorrectionConsumer::result_iterator I = DI->second->begin(), - IEnd = DI->second->end(); + for (TypoCorrectionConsumer::result_iterator I = DI->second.begin(), + IEnd = DI->second.end(); I != IEnd; /* Increment in loop. */) { // If the item already has been looked up or is a keyword, keep it. // If a validator callback object was given, drop the correction @@ -3892,7 +3878,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, TypoCorrectionConsumer::result_iterator Prev = I; ++I; if (!isCandidateViable(CCC, Prev->second)) - DI->second->erase(Prev); + DI->second.erase(Prev); continue; } @@ -3911,7 +3897,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, { TypoCorrectionConsumer::result_iterator Next = I; ++Next; - DI->second->erase(I); + DI->second.erase(I); I = Next; } break; @@ -3929,7 +3915,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, I->second.addCorrectionDecl(*TRD); ++I; if (!isCandidateViable(CCC, Prev->second)) - DI->second->erase(Prev); + DI->second.erase(Prev); break; } @@ -3938,14 +3924,14 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, I->second.setCorrectionDecl(TmpRes.getAsSingle()); ++I; if (!isCandidateViable(CCC, Prev->second)) - DI->second->erase(Prev); + DI->second.erase(Prev); break; } } } - if (DI->second->empty()) + if (DI->second.empty()) Consumer.erase(DI); else if (!getLangOpts().CPlusPlus || QualifiedResults.empty() || !ED) // If there are results in the closest possible bucket, stop @@ -4009,7 +3995,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, // No corrections remain... if (Consumer.empty()) return TypoCorrection(); - TypoResultsMap &BestResults = *Consumer.begin()->second; + TypoResultsMap &BestResults = Consumer.begin()->second; ED = TypoCorrection::NormalizeEditDistance(Consumer.begin()->first); if (ED > 0 && Typo->getName().size() / ED < 3) { @@ -4083,7 +4069,8 @@ std::string TypoCorrection::getAsString(const LangOptions &LO) const { std::string tmpBuffer; llvm::raw_string_ostream PrefixOStream(tmpBuffer); CorrectionNameSpec->print(PrefixOStream, PrintingPolicy(LO)); - return PrefixOStream.str() + CorrectionName.getAsString(); + CorrectionName.printName(PrefixOStream); + return PrefixOStream.str(); } return CorrectionName.getAsString(); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 284c8dec1c62..50230f068dd5 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -11150,6 +11150,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, VK_LValue, Found.getDecl(), TemplateArgs); + MarkDeclRefReferenced(DRE); DRE->setHadMultipleCandidates(ULE->getNumDecls() > 1); return DRE; } @@ -11178,6 +11179,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, VK_LValue, Found.getDecl(), TemplateArgs); + MarkDeclRefReferenced(DRE); DRE->setHadMultipleCandidates(MemExpr->getNumDecls() > 1); return DRE; } else { diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index d52c912457a1..0e6632964a95 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/lib/Sema/SemaPseudoObject.cpp @@ -214,6 +214,7 @@ namespace { ObjCMethodDecl *Setter; Selector SetterSelector; + Selector GetterSelector; public: ObjCPropertyOpBuilder(Sema &S, ObjCPropertyRefExpr *refExpr) : @@ -475,8 +476,24 @@ bool ObjCPropertyOpBuilder::findGetter() { // For implicit properties, just trust the lookup we already did. if (RefExpr->isImplicitProperty()) { - Getter = RefExpr->getImplicitPropertyGetter(); - return (Getter != 0); + if ((Getter = RefExpr->getImplicitPropertyGetter())) { + GetterSelector = Getter->getSelector(); + return true; + } + else { + // Must build the getter selector the hard way. + ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter(); + assert(setter && "both setter and getter are null - cannot happen"); + IdentifierInfo *setterName = + setter->getSelector().getIdentifierInfoForSlot(0); + const char *compStr = setterName->getNameStart(); + compStr += 3; + IdentifierInfo *getterName = &S.Context.Idents.get(compStr); + GetterSelector = + S.PP.getSelectorTable().getNullarySelector(getterName); + return false; + + } } ObjCPropertyDecl *prop = RefExpr->getExplicitProperty(); @@ -776,7 +793,7 @@ ObjCPropertyOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, assert(RefExpr->isImplicitProperty()); S.Diag(opcLoc, diag::err_nogetter_property_incdec) << unsigned(UnaryOperator::isDecrementOp(opcode)) - << RefExpr->getImplicitPropertyGetter()->getSelector() // FIXME! + << GetterSelector << op->getSourceRange(); return ExprError(); } @@ -1300,6 +1317,11 @@ static Expr *stripOpaqueValuesFromPseudoObjectRef(Sema &S, Expr *E) { Expr *opaqueRef = E->IgnoreParens(); if (ObjCPropertyRefExpr *refExpr = dyn_cast(opaqueRef)) { + // Class and super property references don't have opaque values in them. + if (refExpr->isClassReceiver() || refExpr->isSuperReceiver()) + return E; + + assert(refExpr->isObjectReceiver() && "Unknown receiver kind?"); OpaqueValueExpr *baseOVE = cast(refExpr->getBase()); return ObjCPropertyRefRebuilder(S, baseOVE->getSourceExpr()).rebuild(E); } else if (ObjCSubscriptRefExpr *refExpr diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 97c8eb04e9e1..9052278d7337 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -345,7 +345,6 @@ Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, StmtResult Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, SourceLocation ColonLoc, Stmt *SubStmt) { - // If the label was multiply defined, reject it now. if (TheDecl->getStmt()) { Diag(IdentLoc, diag::err_redefinition_of_label) << TheDecl->getDeclName(); @@ -361,6 +360,16 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, return Owned(LS); } +StmtResult Sema::ActOnAttributedStmt(SourceLocation AttrLoc, + const AttrVec &Attrs, + Stmt *SubStmt) { + // Fill in the declaration and return it. Variable length will require to + // change this to AttributedStmt::Create(Context, ....); + // and probably using ArrayRef + AttributedStmt *LS = new (Context) AttributedStmt(AttrLoc, Attrs, SubStmt); + return Owned(LS); +} + StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar, Stmt *thenStmt, SourceLocation ElseLoc, diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp new file mode 100644 index 000000000000..21c329758ebc --- /dev/null +++ b/lib/Sema/SemaStmtAttr.cpp @@ -0,0 +1,48 @@ +//===--- SemaStmtAttr.cpp - Statement Attribute Handling ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements stmt-related attribute processing. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaInternal.h" +#include "TargetAttributesSema.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Sema/DelayedDiagnostic.h" +#include "clang/Sema/Lookup.h" +#include "llvm/ADT/StringExtras.h" +using namespace clang; +using namespace sema; + + +static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A) { + switch (A.getKind()) { + default: + // if we're here, then we parsed an attribute, but didn't recognize it as a + // statement attribute => it is declaration attribute + S.Diag(A.getRange().getBegin(), diag::warn_attribute_invalid_on_stmt) << + A.getName()->getName(); + return 0; + } +} + +StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList, + SourceRange Range) { + AttrVec Attrs; + for (const AttributeList* l = AttrList; l; l = l->getNext()) { + if (Attr *a = ProcessStmtAttribute(*this, S, *l)) + Attrs.push_back(a); + } + + if (Attrs.empty()) + return S; + + return ActOnAttributedStmt(Range.getBegin(), Attrs, S); +} diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index ff8c4dacc246..51ce2a1345a5 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2496,6 +2496,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); + Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); ArgType = SemaRef.SubstType(ArgType, AllTemplateArgs, Param->getDefaultArgumentLoc(), Param->getDeclName()); @@ -2544,6 +2545,8 @@ SubstDefaultTemplateArgument(Sema &SemaRef, Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); + Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); + EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); return SemaRef.SubstExpr(Param->getDefaultArgument(), AllTemplateArgs); } @@ -2591,6 +2594,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); + Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); // Substitute into the nested-name-specifier first, QualifierLoc = Param->getDefaultArgument().getTemplateQualifierLoc(); if (QualifierLoc) { diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 2ea1e6ff9341..d68e4642fc43 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -2310,23 +2310,42 @@ Sema::SubstituteExplicitTemplateArguments( // explicitly-specified template arguments. If the function has a trailing // return type, substitute it after the arguments to ensure we substitute // in lexical order. - if (Proto->hasTrailingReturn() && - SubstParmTypes(Function->getLocation(), - Function->param_begin(), Function->getNumParams(), - MultiLevelTemplateArgumentList(*ExplicitArgumentList), - ParamTypes)) - return TDK_SubstitutionFailure; - + if (Proto->hasTrailingReturn()) { + if (SubstParmTypes(Function->getLocation(), + Function->param_begin(), Function->getNumParams(), + MultiLevelTemplateArgumentList(*ExplicitArgumentList), + ParamTypes)) + return TDK_SubstitutionFailure; + } + // Instantiate the return type. // FIXME: exception-specifications? - QualType ResultType - = SubstType(Proto->getResultType(), - MultiLevelTemplateArgumentList(*ExplicitArgumentList), - Function->getTypeSpecStartLoc(), - Function->getDeclName()); - if (ResultType.isNull() || Trap.hasErrorOccurred()) - return TDK_SubstitutionFailure; - + QualType ResultType; + { + // C++11 [expr.prim.general]p3: + // If a declaration declares a member function or member function + // template of a class X, the expression this is a prvalue of type + // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq + // and the end of the function-definition, member-declarator, or + // declarator. + unsigned ThisTypeQuals = 0; + CXXRecordDecl *ThisContext = 0; + if (CXXMethodDecl *Method = dyn_cast(Function)) { + ThisContext = Method->getParent(); + ThisTypeQuals = Method->getTypeQualifiers(); + } + + CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals, + getLangOpts().CPlusPlus0x); + + ResultType = SubstType(Proto->getResultType(), + MultiLevelTemplateArgumentList(*ExplicitArgumentList), + Function->getTypeSpecStartLoc(), + Function->getDeclName()); + if (ResultType.isNull() || Trap.hasErrorOccurred()) + return TDK_SubstitutionFailure; + } + // Instantiate the types of each of the function parameters given the // explicitly-specified template arguments if we didn't do so earlier. if (!Proto->hasTrailingReturn() && diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 4740145fd5ac..128dc2f7ff40 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -153,6 +153,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const { switch (Kind) { case TemplateInstantiation: + case ExceptionSpecInstantiation: case DefaultTemplateArgumentInstantiation: case DefaultFunctionArgumentInstantiation: return true; @@ -190,6 +191,29 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, } } +Sema::InstantiatingTemplate:: +InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + FunctionDecl *Entity, ExceptionSpecification, + SourceRange InstantiationRange) + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ + Invalid = CheckInstantiationDepth(PointOfInstantiation, + InstantiationRange); + if (!Invalid) { + ActiveTemplateInstantiation Inst; + Inst.Kind = ActiveTemplateInstantiation::ExceptionSpecInstantiation; + Inst.PointOfInstantiation = PointOfInstantiation; + Inst.Entity = reinterpret_cast(Entity); + Inst.TemplateArgs = 0; + Inst.NumTemplateArgs = 0; + Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; + SemaRef.ActiveTemplateInstantiations.push_back(Inst); + } +} + Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template, @@ -592,6 +616,13 @@ void Sema::PrintInstantiationStack() { << Active->InstantiationRange; break; } + + case ActiveTemplateInstantiation::ExceptionSpecInstantiation: + Diags.Report(Active->PointOfInstantiation, + diag::note_template_exception_spec_instantiation_here) + << cast((Decl *)Active->Entity) + << Active->InstantiationRange; + break; } } } @@ -609,6 +640,7 @@ llvm::Optional Sema::isSFINAEContext() const { switch(Active->Kind) { case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: case ActiveTemplateInstantiation::TemplateInstantiation: + case ActiveTemplateInstantiation::ExceptionSpecInstantiation: // This is a template instantiation, so there is no SFINAE. return llvm::Optional(); @@ -789,6 +821,11 @@ namespace { QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL); + QualType TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL, + CXXRecordDecl *ThisContext, + unsigned ThisTypeQuals); + ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm, int indexAdjustment, llvm::Optional NumExpansions, @@ -1211,6 +1248,16 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, return inherited::TransformFunctionProtoType(TLB, TL); } +QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL, + CXXRecordDecl *ThisContext, + unsigned ThisTypeQuals) { + // We need a local instantiation scope for this function prototype. + LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); + return inherited::TransformFunctionProtoType(TLB, TL, ThisContext, + ThisTypeQuals); +} + ParmVarDecl * TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm, int indexAdjustment, @@ -1446,7 +1493,9 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &Args, SourceLocation Loc, - DeclarationName Entity) { + DeclarationName Entity, + CXXRecordDecl *ThisContext, + unsigned ThisTypeQuals) { assert(!ActiveTemplateInstantiations.empty() && "Cannot perform an instantiation without some context on the " "instantiation stack"); @@ -1461,7 +1510,14 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, TypeLoc TL = T->getTypeLoc(); TLB.reserve(TL.getFullDataSize()); - QualType Result = Instantiator.TransformType(TLB, TL); + QualType Result; + + if (FunctionProtoTypeLoc *Proto = dyn_cast(&TL)) { + Result = Instantiator.TransformFunctionProtoType(TLB, *Proto, ThisContext, + ThisTypeQuals); + } else { + Result = Instantiator.TransformType(TLB, TL); + } if (Result.isNull()) return 0; @@ -1878,24 +1934,33 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, CheckCompletedCXXClass(Instantiation); // Attach any in-class member initializers now the class is complete. - for (unsigned I = 0, N = FieldsWithMemberInitializers.size(); I != N; ++I) { - FieldDecl *OldField = FieldsWithMemberInitializers[I].first; - FieldDecl *NewField = FieldsWithMemberInitializers[I].second; - Expr *OldInit = OldField->getInClassInitializer(); + { + // C++11 [expr.prim.general]p4: + // Otherwise, if a member-declarator declares a non-static data member + // (9.2) of a class X, the expression this is a prvalue of type "pointer + // to X" within the optional brace-or-equal-initializer. It shall not + // appear elsewhere in the member-declarator. + CXXThisScopeRAII ThisScope(*this, Instantiation, (unsigned)0); + + for (unsigned I = 0, N = FieldsWithMemberInitializers.size(); I != N; ++I) { + FieldDecl *OldField = FieldsWithMemberInitializers[I].first; + FieldDecl *NewField = FieldsWithMemberInitializers[I].second; + Expr *OldInit = OldField->getInClassInitializer(); - ExprResult NewInit = SubstInitializer(OldInit, TemplateArgs, - /*CXXDirectInit=*/false); - if (NewInit.isInvalid()) - NewField->setInvalidDecl(); - else { - Expr *Init = NewInit.take(); - assert(Init && "no-argument initializer in class"); - assert(!isa(Init) && "call-style init in class"); - ActOnCXXInClassMemberInitializer(NewField, - Init->getSourceRange().getBegin(), Init); + ExprResult NewInit = SubstInitializer(OldInit, TemplateArgs, + /*CXXDirectInit=*/false); + if (NewInit.isInvalid()) + NewField->setInvalidDecl(); + else { + Expr *Init = NewInit.take(); + assert(Init && "no-argument initializer in class"); + assert(!isa(Init) && "call-style init in class"); + ActOnCXXInClassMemberInitializer(NewField, + Init->getSourceRange().getBegin(), + Init); + } } } - // Instantiate late parsed attributes, and attach them to their decls. // See Sema::InstantiateAttrs for (LateInstantiatedAttrVec::iterator I = LateAttrs.begin(), diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 8afe7aca9750..c7bd99c1ca6a 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2141,10 +2141,19 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, TypeSourceInfo *OldTInfo = D->getTypeSourceInfo(); assert(OldTInfo && "substituting function without type source info"); assert(Params.empty() && "parameter vector is non-empty at start"); + + CXXRecordDecl *ThisContext = 0; + unsigned ThisTypeQuals = 0; + if (CXXMethodDecl *Method = dyn_cast(D)) { + ThisContext = Method->getParent(); + ThisTypeQuals = Method->getTypeQualifiers(); + } + TypeSourceInfo *NewTInfo = SemaRef.SubstFunctionDeclType(OldTInfo, TemplateArgs, D->getTypeSpecStartLoc(), - D->getDeclName()); + D->getDeclName(), + ThisContext, ThisTypeQuals); if (!NewTInfo) return 0; @@ -2206,6 +2215,195 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, return NewTInfo; } +/// Introduce the instantiated function parameters into the local +/// instantiation scope, and set the parameter names to those used +/// in the template. +static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, + const FunctionDecl *PatternDecl, + LocalInstantiationScope &Scope, + const MultiLevelTemplateArgumentList &TemplateArgs) { + unsigned FParamIdx = 0; + for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) { + const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I); + if (!PatternParam->isParameterPack()) { + // Simple case: not a parameter pack. + assert(FParamIdx < Function->getNumParams()); + ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); + FunctionParam->setDeclName(PatternParam->getDeclName()); + Scope.InstantiatedLocal(PatternParam, FunctionParam); + ++FParamIdx; + continue; + } + + // Expand the parameter pack. + Scope.MakeInstantiatedLocalArgPack(PatternParam); + unsigned NumArgumentsInExpansion + = S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs); + for (unsigned Arg = 0; Arg < NumArgumentsInExpansion; ++Arg) { + ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); + FunctionParam->setDeclName(PatternParam->getDeclName()); + Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam); + ++FParamIdx; + } + } +} + +static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New, + const FunctionProtoType *Proto, + const MultiLevelTemplateArgumentList &TemplateArgs) { + assert(Proto->getExceptionSpecType() != EST_Uninstantiated); + + // C++11 [expr.prim.general]p3: + // If a declaration declares a member function or member function + // template of a class X, the expression this is a prvalue of type + // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq + // and the end of the function-definition, member-declarator, or + // declarator. + CXXRecordDecl *ThisContext = 0; + unsigned ThisTypeQuals = 0; + if (CXXMethodDecl *Method = dyn_cast(New)) { + ThisContext = Method->getParent(); + ThisTypeQuals = Method->getTypeQualifiers(); + } + Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals, + SemaRef.getLangOpts().CPlusPlus0x); + + // The function has an exception specification or a "noreturn" + // attribute. Substitute into each of the exception types. + SmallVector Exceptions; + for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) { + // FIXME: Poor location information! + if (const PackExpansionType *PackExpansion + = Proto->getExceptionType(I)->getAs()) { + // We have a pack expansion. Instantiate it. + SmallVector Unexpanded; + SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), + Unexpanded); + assert(!Unexpanded.empty() && + "Pack expansion without parameter packs?"); + + bool Expand = false; + bool RetainExpansion = false; + llvm::Optional NumExpansions + = PackExpansion->getNumExpansions(); + if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(), + SourceRange(), + Unexpanded, + TemplateArgs, + Expand, + RetainExpansion, + NumExpansions)) + break; + + if (!Expand) { + // We can't expand this pack expansion into separate arguments yet; + // just substitute into the pattern and create a new pack expansion + // type. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); + QualType T = SemaRef.SubstType(PackExpansion->getPattern(), + TemplateArgs, + New->getLocation(), New->getDeclName()); + if (T.isNull()) + break; + + T = SemaRef.Context.getPackExpansionType(T, NumExpansions); + Exceptions.push_back(T); + continue; + } + + // Substitute into the pack expansion pattern for each template + bool Invalid = false; + for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, ArgIdx); + + QualType T = SemaRef.SubstType(PackExpansion->getPattern(), + TemplateArgs, + New->getLocation(), New->getDeclName()); + if (T.isNull()) { + Invalid = true; + break; + } + + Exceptions.push_back(T); + } + + if (Invalid) + break; + + continue; + } + + QualType T + = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs, + New->getLocation(), New->getDeclName()); + if (T.isNull() || + SemaRef.CheckSpecifiedExceptionType(T, New->getLocation())) + continue; + + Exceptions.push_back(T); + } + Expr *NoexceptExpr = 0; + if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) { + EnterExpressionEvaluationContext Unevaluated(SemaRef, + Sema::ConstantEvaluated); + ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs); + if (E.isUsable()) + E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart()); + + if (E.isUsable()) { + NoexceptExpr = E.take(); + if (!NoexceptExpr->isTypeDependent() && + !NoexceptExpr->isValueDependent()) + NoexceptExpr = SemaRef.VerifyIntegerConstantExpression(NoexceptExpr, + 0, SemaRef.PDiag(diag::err_noexcept_needs_constant_expression), + /*AllowFold*/ false).take(); + } + } + + // Rebuild the function type + const FunctionProtoType *NewProto + = New->getType()->getAs(); + assert(NewProto && "Template instantiation without function prototype?"); + + FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo(); + EPI.ExceptionSpecType = Proto->getExceptionSpecType(); + EPI.NumExceptions = Exceptions.size(); + EPI.Exceptions = Exceptions.data(); + EPI.NoexceptExpr = NoexceptExpr; + + New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(), + NewProto->arg_type_begin(), + NewProto->getNumArgs(), + EPI)); +} + +void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, + FunctionDecl *Decl) { + const FunctionProtoType *Proto = Decl->getType()->castAs(); + if (Proto->getExceptionSpecType() != EST_Uninstantiated) + return; + + InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl, + InstantiatingTemplate::ExceptionSpecification()); + if (Inst) + return; + + // Enter the scope of this instantiation. We don't use + // PushDeclContext because we don't have a scope. + Sema::ContextRAII savedContext(*this, Decl); + LocalInstantiationScope Scope(*this); + + MultiLevelTemplateArgumentList TemplateArgs = + getTemplateInstantiationArgs(Decl, 0, /*RelativeToPrimary*/true); + + FunctionDecl *Template = Proto->getExceptionSpecTemplate(); + addInstantiatedParametersToScope(*this, Decl, Template, Scope, TemplateArgs); + + ::InstantiateExceptionSpec(*this, Decl, + Template->getType()->castAs(), + TemplateArgs); +} + /// \brief Initializes the common fields of an instantiation function /// declaration (New) from the corresponding fields of its template (Tmpl). /// @@ -2243,119 +2441,37 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, assert(Proto && "Function template without prototype?"); if (Proto->hasExceptionSpec() || Proto->getNoReturnAttr()) { - // The function has an exception specification or a "noreturn" - // attribute. Substitute into each of the exception types. - SmallVector Exceptions; - for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) { - // FIXME: Poor location information! - if (const PackExpansionType *PackExpansion - = Proto->getExceptionType(I)->getAs()) { - // We have a pack expansion. Instantiate it. - SmallVector Unexpanded; - SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), - Unexpanded); - assert(!Unexpanded.empty() && - "Pack expansion without parameter packs?"); - - bool Expand = false; - bool RetainExpansion = false; - llvm::Optional NumExpansions - = PackExpansion->getNumExpansions(); - if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(), - SourceRange(), - Unexpanded, - TemplateArgs, - Expand, - RetainExpansion, - NumExpansions)) - break; - - if (!Expand) { - // We can't expand this pack expansion into separate arguments yet; - // just substitute into the pattern and create a new pack expansion - // type. - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); - QualType T = SemaRef.SubstType(PackExpansion->getPattern(), - TemplateArgs, - New->getLocation(), New->getDeclName()); - if (T.isNull()) - break; - - T = SemaRef.Context.getPackExpansionType(T, NumExpansions); - Exceptions.push_back(T); - continue; - } - - // Substitute into the pack expansion pattern for each template - bool Invalid = false; - for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, ArgIdx); - - QualType T = SemaRef.SubstType(PackExpansion->getPattern(), - TemplateArgs, - New->getLocation(), New->getDeclName()); - if (T.isNull()) { - Invalid = true; - break; - } - - Exceptions.push_back(T); - } - - if (Invalid) - break; - - continue; - } - - QualType T - = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs, - New->getLocation(), New->getDeclName()); - if (T.isNull() || - SemaRef.CheckSpecifiedExceptionType(T, New->getLocation())) - continue; - - Exceptions.push_back(T); - } - Expr *NoexceptExpr = 0; - if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) { - EnterExpressionEvaluationContext Unevaluated(SemaRef, - Sema::ConstantEvaluated); - ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs); - if (E.isUsable()) - E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart()); - - if (E.isUsable()) { - NoexceptExpr = E.take(); - if (!NoexceptExpr->isTypeDependent() && - !NoexceptExpr->isValueDependent()) - NoexceptExpr = SemaRef.VerifyIntegerConstantExpression(NoexceptExpr, - 0, SemaRef.PDiag(diag::err_noexcept_needs_constant_expression), - /*AllowFold*/ false).take(); - } - } - - // Rebuild the function type - FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo(); - EPI.ExceptionSpecType = Proto->getExceptionSpecType(); - EPI.NumExceptions = Exceptions.size(); - EPI.Exceptions = Exceptions.data(); - EPI.NoexceptExpr = NoexceptExpr; - EPI.ExtInfo = Proto->getExtInfo(); - const FunctionProtoType *NewProto - = New->getType()->getAs(); - assert(NewProto && "Template instantiation without function prototype?"); - New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(), - NewProto->arg_type_begin(), - NewProto->getNumArgs(), - EPI)); + // DR1330: In C++11, defer instantiation of a non-trivial + // exception specification. + if (SemaRef.getLangOpts().CPlusPlus0x && + EPI.ExceptionSpecType != EST_None && + EPI.ExceptionSpecType != EST_DynamicNone && + EPI.ExceptionSpecType != EST_BasicNoexcept) { + FunctionDecl *ExceptionSpecTemplate = Tmpl; + if (EPI.ExceptionSpecType == EST_Uninstantiated) + ExceptionSpecTemplate = EPI.ExceptionSpecTemplate; + + // Mark the function has having an uninstantiated exception specification. + const FunctionProtoType *NewProto + = New->getType()->getAs(); + assert(NewProto && "Template instantiation without function prototype?"); + EPI = NewProto->getExtProtoInfo(); + EPI.ExceptionSpecType = EST_Uninstantiated; + EPI.ExceptionSpecDecl = New; + EPI.ExceptionSpecTemplate = ExceptionSpecTemplate; + New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(), + NewProto->arg_type_begin(), + NewProto->getNumArgs(), + EPI)); + } else { + ::InstantiateExceptionSpec(SemaRef, New, Proto, TemplateArgs); + } } - const FunctionDecl* Definition = Tmpl; - // Get the definition. Leaves the variable unchanged if undefined. + const FunctionDecl *Definition = Tmpl; Tmpl->isDefined(Definition); SemaRef.InstantiateAttrs(TemplateArgs, Definition, New, @@ -2513,33 +2629,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(Function, 0, false, PatternDecl); - // Introduce the instantiated function parameters into the local - // instantiation scope, and set the parameter names to those used - // in the template. - unsigned FParamIdx = 0; - for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) { - const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I); - if (!PatternParam->isParameterPack()) { - // Simple case: not a parameter pack. - assert(FParamIdx < Function->getNumParams()); - ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); - FunctionParam->setDeclName(PatternParam->getDeclName()); - Scope.InstantiatedLocal(PatternParam, FunctionParam); - ++FParamIdx; - continue; - } - - // Expand the parameter pack. - Scope.MakeInstantiatedLocalArgPack(PatternParam); - unsigned NumArgumentsInExpansion - = getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs); - for (unsigned Arg = 0; Arg < NumArgumentsInExpansion; ++Arg) { - ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); - FunctionParam->setDeclName(PatternParam->getDeclName()); - Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam); - ++FParamIdx; - } - } + addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope, + TemplateArgs); if (PatternDecl->isDefaulted()) { ActOnFinishFunctionBody(Function, 0, /*IsInstantiation=*/true); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index c41df82a48b5..d0906ded0cbb 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -561,7 +561,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state, /*const qualifier*/SourceLocation(), /*volatile qualifier*/SourceLocation(), /*mutable qualifier*/SourceLocation(), - /*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0, + /*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0, 0, /*parens*/ loc, loc, declarator)); @@ -2371,34 +2371,33 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, EPI.ConsumedArguments = ConsumedArguments.data(); SmallVector Exceptions; - EPI.ExceptionSpecType = FTI.getExceptionSpecType(); + SmallVector DynamicExceptions; + SmallVector DynamicExceptionRanges; + Expr *NoexceptExpr = 0; + if (FTI.getExceptionSpecType() == EST_Dynamic) { - Exceptions.reserve(FTI.NumExceptions); - for (unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) { - // FIXME: Preserve type source info. - QualType ET = S.GetTypeFromParser(FTI.Exceptions[ei].Ty); - // Check that the type is valid for an exception spec, and - // drop it if not. - if (!S.CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range)) - Exceptions.push_back(ET); + // FIXME: It's rather inefficient to have to split into two vectors + // here. + unsigned N = FTI.NumExceptions; + DynamicExceptions.reserve(N); + DynamicExceptionRanges.reserve(N); + for (unsigned I = 0; I != N; ++I) { + DynamicExceptions.push_back(FTI.Exceptions[I].Ty); + DynamicExceptionRanges.push_back(FTI.Exceptions[I].Range); } - EPI.NumExceptions = Exceptions.size(); - EPI.Exceptions = Exceptions.data(); } else if (FTI.getExceptionSpecType() == EST_ComputedNoexcept) { - // If an error occurred, there's no expression here. - if (Expr *NoexceptExpr = FTI.NoexceptExpr) { - assert((NoexceptExpr->isTypeDependent() || - NoexceptExpr->getType()->getCanonicalTypeUnqualified() == - Context.BoolTy) && - "Parser should have made sure that the expression is boolean"); - if (!NoexceptExpr->isValueDependent()) - NoexceptExpr = S.VerifyIntegerConstantExpression(NoexceptExpr, 0, - S.PDiag(diag::err_noexcept_needs_constant_expression), - /*AllowFold*/ false).take(); - EPI.NoexceptExpr = NoexceptExpr; - } - } else if (FTI.getExceptionSpecType() == EST_None && - ImplicitlyNoexcept && chunkIndex == 0) { + NoexceptExpr = FTI.NoexceptExpr; + } + + S.checkExceptionSpecification(FTI.getExceptionSpecType(), + DynamicExceptions, + DynamicExceptionRanges, + NoexceptExpr, + Exceptions, + EPI); + + if (FTI.getExceptionSpecType() == EST_None && + ImplicitlyNoexcept && chunkIndex == 0) { // Only the outermost chunk is marked noexcept, of course. EPI.ExceptionSpecType = EST_BasicNoexcept; } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index fdb861eea51b..a66378e51783 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -522,6 +522,11 @@ class TreeTransform { QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T); #include "clang/AST/TypeLocNodes.def" + QualType TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL, + CXXRecordDecl *ThisContext, + unsigned ThisTypeQuals); + StmtResult TransformSEHHandler(Stmt *Handler); @@ -1044,6 +1049,15 @@ class TreeTransform { return SemaRef.ActOnLabelStmt(IdentLoc, L, ColonLoc, SubStmt); } + /// \brief Build a new label statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + StmtResult RebuildAttributedStmt(SourceLocation AttrLoc, const AttrVec &Attrs, + Stmt *SubStmt) { + return SemaRef.ActOnAttributedStmt(AttrLoc, Attrs, SubStmt); + } + /// \brief Build a new "if" statement. /// /// By default, performs semantic analysis to build the new statement. @@ -4156,12 +4170,18 @@ template QualType TreeTransform::TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL) { + return getDerived().TransformFunctionProtoType(TLB, TL, 0, 0); +} + +template +QualType +TreeTransform::TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL, + CXXRecordDecl *ThisContext, + unsigned ThisTypeQuals) { // Transform the parameters and return type. // - // We instantiate in source order, with the return type first followed by - // the parameters, because users tend to expect this (even if they shouldn't - // rely on it!). - // + // We are required to instantiate the params and return type in source order. // When the function has a trailing return type, we instantiate the // parameters before the return type, since the return type can then refer // to the parameters themselves (via decltype, sizeof, etc.). @@ -4180,9 +4200,19 @@ TreeTransform::TransformFunctionProtoType(TypeLocBuilder &TLB, ParamTypes, &ParamDecls)) return QualType(); - ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); - if (ResultType.isNull()) - return QualType(); + { + // C++11 [expr.prim.general]p3: + // If a declaration declares a member function or member function + // template of a class X, the expression this is a prvalue of type + // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq + // and the end of the function-definition, member-declarator, or + // declarator. + Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals); + + ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); + if (ResultType.isNull()) + return QualType(); + } } else { ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); @@ -4197,6 +4227,8 @@ TreeTransform::TransformFunctionProtoType(TypeLocBuilder &TLB, return QualType(); } + // FIXME: Need to transform the exception-specification too. + QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ResultType != T->getResultType() || @@ -5154,14 +5186,30 @@ TreeTransform::TransformLabelStmt(LabelStmt *S) { S->getDecl()); if (!LD) return StmtError(); - - + + // FIXME: Pass the real colon location in. return getDerived().RebuildLabelStmt(S->getIdentLoc(), cast(LD), SourceLocation(), SubStmt.get()); } +template +StmtResult +TreeTransform::TransformAttributedStmt(AttributedStmt *S) { + StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt()); + if (SubStmt.isInvalid()) + return StmtError(); + + // TODO: transform attributes + if (SubStmt.get() == S->getSubStmt() /* && attrs are the same */) + return S; + + return getDerived().RebuildAttributedStmt(S->getAttrLoc(), + S->getAttrs(), + SubStmt.get()); +} + template StmtResult TreeTransform::TransformIfStmt(IfStmt *S) { diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index f91b66cf5476..06b42f3ab130 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -27,7 +27,6 @@ #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLocVisitor.h" -#include "llvm/Support/SaveAndRestore.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" @@ -46,6 +45,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/system_error.h" #include #include @@ -664,46 +664,6 @@ ASTDeclContextNameLookupTrait::GetInternalKey( return Key; } -ASTDeclContextNameLookupTrait::external_key_type -ASTDeclContextNameLookupTrait::GetExternalKey( - const internal_key_type& Key) const { - ASTContext &Context = Reader.getContext(); - switch (Key.Kind) { - case DeclarationName::Identifier: - return DeclarationName((IdentifierInfo*)Key.Data); - - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - return DeclarationName(Selector(Key.Data)); - - case DeclarationName::CXXConstructorName: - return Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(Reader.getLocalType(F, Key.Data))); - - case DeclarationName::CXXDestructorName: - return Context.DeclarationNames.getCXXDestructorName( - Context.getCanonicalType(Reader.getLocalType(F, Key.Data))); - - case DeclarationName::CXXConversionFunctionName: - return Context.DeclarationNames.getCXXConversionFunctionName( - Context.getCanonicalType(Reader.getLocalType(F, Key.Data))); - - case DeclarationName::CXXOperatorName: - return Context.DeclarationNames.getCXXOperatorName( - (OverloadedOperatorKind)Key.Data); - - case DeclarationName::CXXLiteralOperatorName: - return Context.DeclarationNames.getCXXLiteralOperatorName( - (IdentifierInfo*)Key.Data); - - case DeclarationName::CXXUsingDirective: - return DeclarationName::getUsingDirectiveName(); - } - - llvm_unreachable("Invalid Name Kind ?"); -} - std::pair ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char*& d) { using namespace clang::io; @@ -749,7 +709,7 @@ ASTDeclContextNameLookupTrait::ReadKey(const unsigned char* d, unsigned) { ASTDeclContextNameLookupTrait::data_type ASTDeclContextNameLookupTrait::ReadData(internal_key_type, const unsigned char* d, - unsigned DataLen) { + unsigned DataLen) { using namespace clang::io; unsigned NumDecls = ReadUnalignedLE16(d); LE32DeclID *Start = (LE32DeclID *)d; @@ -1911,7 +1871,8 @@ ASTReader::ReadASTBlock(ModuleFile &F) { case UPDATE_VISIBLE: { unsigned Idx = 0; serialization::DeclID ID = ReadDeclID(F, Record, Idx); - void *Table = ASTDeclContextNameLookupTable::Create( + ASTDeclContextNameLookupTable *Table = + ASTDeclContextNameLookupTable::Create( (const unsigned char *)BlobStart + Record[Idx++], (const unsigned char *)BlobStart, ASTDeclContextNameLookupTrait(*this, F)); @@ -4908,7 +4869,7 @@ namespace { // Look for this name within this module. ASTDeclContextNameLookupTable *LookupTable = - (ASTDeclContextNameLookupTable*)Info->second.NameLookupTableData; + Info->second.NameLookupTableData; ASTDeclContextNameLookupTable::iterator Pos = LookupTable->find(This->Name); if (Pos == LookupTable->end()) @@ -4972,48 +4933,95 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, } namespace { - /// \brief ModuleFile visitor used to complete the visible decls map of a + /// \brief ModuleFile visitor used to retrieve all visible names in a /// declaration context. - class DeclContextVisibleDeclMapVisitor { + class DeclContextAllNamesVisitor { ASTReader &Reader; - DeclContext *DC; + llvm::SmallVectorImpl &Contexts; + const DeclContext *DC; + llvm::DenseMap > &Decls; public: - DeclContextVisibleDeclMapVisitor(ASTReader &Reader, DeclContext *DC) - : Reader(Reader), DC(DC) { } + DeclContextAllNamesVisitor(ASTReader &Reader, + SmallVectorImpl &Contexts, + llvm::DenseMap > &Decls) + : Reader(Reader), Contexts(Contexts), Decls(Decls) { } static bool visit(ModuleFile &M, void *UserData) { - return static_cast(UserData)->visit(M); - } + DeclContextAllNamesVisitor *This + = static_cast(UserData); - bool visit(ModuleFile &M) { // Check whether we have any visible declaration information for // this context in this module. - ModuleFile::DeclContextInfosMap::iterator - Info = M.DeclContextInfos.find(DC); - if (Info == M.DeclContextInfos.end() || - !Info->second.NameLookupTableData) - return false; - - // Look for this name within this module. - ASTDeclContextNameLookupTable *LookupTable = - (ASTDeclContextNameLookupTable*)Info->second.NameLookupTableData; - for (ASTDeclContextNameLookupTable::key_iterator - I = LookupTable->key_begin(), - E = LookupTable->key_end(); I != E; ++I) { - DC->lookup(*I); // Force loading of the visible decls for the decl name. + ModuleFile::DeclContextInfosMap::iterator Info; + bool FoundInfo = false; + for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) { + Info = M.DeclContextInfos.find(This->Contexts[I]); + if (Info != M.DeclContextInfos.end() && + Info->second.NameLookupTableData) { + FoundInfo = true; + break; + } } - return false; + if (!FoundInfo) + return false; + + ASTDeclContextNameLookupTable *LookupTable = + Info->second.NameLookupTableData; + bool FoundAnything = false; + for (ASTDeclContextNameLookupTable::data_iterator + I = LookupTable->data_begin(), E = LookupTable->data_end(); + I != E; ++I) { + ASTDeclContextNameLookupTrait::data_type Data = *I; + for (; Data.first != Data.second; ++Data.first) { + NamedDecl *ND = This->Reader.GetLocalDeclAs(M, + *Data.first); + if (!ND) + continue; + + // Record this declaration. + FoundAnything = true; + This->Decls[ND->getDeclName()].push_back(ND); + } + } + + return FoundAnything; } }; } -void ASTReader::completeVisibleDeclsMap(DeclContext *DC) { +void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) { if (!DC->hasExternalVisibleStorage()) return; - DeclContextVisibleDeclMapVisitor Visitor(*this, DC); - ModuleMgr.visit(&DeclContextVisibleDeclMapVisitor::visit, &Visitor); + llvm::DenseMap > Decls; + + // Compute the declaration contexts we need to look into. Multiple such + // declaration contexts occur when two declaration contexts from disjoint + // modules get merged, e.g., when two namespaces with the same name are + // independently defined in separate modules. + SmallVector Contexts; + Contexts.push_back(DC); + + if (DC->isNamespace()) { + MergedDeclsMap::iterator Merged + = MergedDecls.find(const_cast(cast(DC))); + if (Merged != MergedDecls.end()) { + for (unsigned I = 0, N = Merged->second.size(); I != N; ++I) + Contexts.push_back(cast(GetDecl(Merged->second[I]))); + } + } + + DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls); + ModuleMgr.visit(&DeclContextAllNamesVisitor::visit, &Visitor); + ++NumVisibleDeclContextsRead; + + for (llvm::DenseMap >::iterator + I = Decls.begin(), E = Decls.end(); I != E; ++I) { + SetExternalVisibleDeclsForName(DC, I->first, I->second); + } } /// \brief Under non-PCH compilation the consumer receives the objc methods @@ -6364,6 +6372,6 @@ ASTReader::~ASTReader() { for (DeclContextVisibleUpdates::iterator J = I->second.begin(), F = I->second.end(); J != F; ++J) - delete static_cast(J->first); + delete J->first; } } diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 5db5f9252b7f..8dd53ee7d206 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "ASTCommon.h" +#include "ASTReaderInternals.h" #include "clang/Serialization/ASTReader.h" #include "clang/Sema/IdentifierResolver.h" #include "clang/Sema/Sema.h" @@ -955,6 +956,10 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) { Params.push_back(ReadDeclAs(Record, Idx)); BD->setParams(Params); + BD->setIsVariadic(Record[Idx++]); + BD->setBlockMissingReturnType(Record[Idx++]); + BD->setIsConversionFromLambda(Record[Idx++]); + bool capturesCXXThis = Record[Idx++]; unsigned numCaptures = Record[Idx++]; SmallVector captures; @@ -2100,7 +2105,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { DeclContextVisibleUpdates &U = I->second; for (DeclContextVisibleUpdates::iterator UI = U.begin(), UE = U.end(); UI != UE; ++UI) { - UI->second->DeclContextInfos[DC].NameLookupTableData = UI->first; + DeclContextInfo &Info = UI->second->DeclContextInfos[DC]; + delete Info.NameLookupTableData; + Info.NameLookupTableData = UI->first; } PendingVisibleUpdates.erase(I); } diff --git a/lib/Serialization/ASTReaderInternals.h b/lib/Serialization/ASTReaderInternals.h index 3a1dfcf4b74a..e5159e952635 100644 --- a/lib/Serialization/ASTReaderInternals.h +++ b/lib/Serialization/ASTReaderInternals.h @@ -57,8 +57,7 @@ class ASTDeclContextNameLookupTrait { typedef DeclarationName external_key_type; typedef DeclNameKey internal_key_type; - explicit ASTDeclContextNameLookupTrait(ASTReader &Reader, - ModuleFile &F) + explicit ASTDeclContextNameLookupTrait(ASTReader &Reader, ModuleFile &F) : Reader(Reader), F(F) { } static bool EqualKey(const internal_key_type& a, @@ -68,9 +67,8 @@ class ASTDeclContextNameLookupTrait { unsigned ComputeHash(const DeclNameKey &Key) const; internal_key_type GetInternalKey(const external_key_type& Name) const; - external_key_type GetExternalKey(const internal_key_type& Key) const; - static std::pair + static std::pair ReadKeyDataLength(const unsigned char*& d); internal_key_type ReadKey(const unsigned char* d, unsigned); @@ -79,10 +77,6 @@ class ASTDeclContextNameLookupTrait { unsigned DataLen); }; -/// \brief The on-disk hash table used for the DeclContext's Name lookup table. -typedef OnDiskChainedHashTable - ASTDeclContextNameLookupTable; - /// \brief Class that performs lookup for an identifier stored in an AST file. class ASTIdentifierLookupTrait { ASTReader &Reader; diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 2eeb090af0d6..007ecee9f53f 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -159,9 +159,18 @@ void ASTStmtReader::VisitLabelStmt(LabelStmt *S) { S->setIdentLoc(ReadSourceLocation(Record, Idx)); } +void ASTStmtReader::VisitAttributedStmt(AttributedStmt *S) { + VisitStmt(S); + AttrVec Attrs; + Reader.ReadAttributes(F, Attrs, Record, Idx); + S->Attrs = Attrs; + S->SubStmt = Reader.ReadSubStmt(); + S->AttrLoc = ReadSourceLocation(Record, Idx); +} + void ASTStmtReader::VisitIfStmt(IfStmt *S) { VisitStmt(S); - S->setConditionVariable(Reader.getContext(), + S->setConditionVariable(Reader.getContext(), ReadDeclAs(Record, Idx)); S->setCond(Reader.ReadSubExpr()); S->setThen(Reader.ReadSubStmt()); @@ -1630,6 +1639,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = new (Context) LabelStmt(Empty); break; + case STMT_ATTRIBUTED: + S = new (Context) AttributedStmt(Empty); + break; + case STMT_IF: S = new (Context) IfStmt(Empty); break; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index a4301b53e872..81c0a9dd48ac 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -651,6 +651,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream, RECORD(STMT_CASE); RECORD(STMT_DEFAULT); RECORD(STMT_LABEL); + RECORD(STMT_ATTRIBUTED); RECORD(STMT_IF); RECORD(STMT_SWITCH); RECORD(STMT_WHILE); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 7a4ef63bb3f6..1ee3ac480b6f 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -775,6 +775,9 @@ void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) { for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); P != PEnd; ++P) Writer.AddDeclRef(*P, Record); + Record.push_back(D->isVariadic()); + Record.push_back(D->blockMissingReturnType()); + Record.push_back(D->isConversionFromLambda()); Record.push_back(D->capturesCXXThis()); Record.push_back(D->getNumCaptures()); for (BlockDecl::capture_iterator diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 827caa026a4a..1e3121146319 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -106,6 +106,14 @@ void ASTStmtWriter::VisitLabelStmt(LabelStmt *S) { Code = serialization::STMT_LABEL; } +void ASTStmtWriter::VisitAttributedStmt(AttributedStmt *S) { + VisitStmt(S); + Writer.WriteAttributes(S->getAttrs(), Record); + Writer.AddStmt(S->getSubStmt()); + Writer.AddSourceLocation(S->getAttrLoc(), Record); + Code = serialization::STMT_ATTRIBUTED; +} + void ASTStmtWriter::VisitIfStmt(IfStmt *S) { VisitStmt(S); Writer.AddDeclRef(S->getConditionVariable(), Record); diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp index 16b95e2a6834..ff241d3d4105 100644 --- a/lib/Serialization/Module.cpp +++ b/lib/Serialization/Module.cpp @@ -45,8 +45,7 @@ ModuleFile::~ModuleFile() { E = DeclContextInfos.end(); I != E; ++I) { if (I->second.NameLookupTableData) - delete static_cast( - I->second.NameLookupTableData); + delete I->second.NameLookupTableData; } delete static_cast(IdentifierLookupTable); diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp index d15c8ba408a4..97b58cf79b0e 100644 --- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp @@ -183,9 +183,6 @@ static void checkForInvalidSelf(const Expr *E, CheckerContext &C, void ObjCSelfInitChecker::checkPostObjCMessage(ObjCMessage msg, CheckerContext &C) const { - CallOrObjCMessage MsgWrapper(msg, C.getState(), C.getLocationContext()); - checkPostStmt(MsgWrapper, C); - // When encountering a message that does initialization (init rule), // tag the return value so that we know later on that if self has this value // then it is properly initialized. @@ -209,6 +206,9 @@ void ObjCSelfInitChecker::checkPostObjCMessage(ObjCMessage msg, return; } + CallOrObjCMessage MsgWrapper(msg, C.getState(), C.getLocationContext()); + checkPostStmt(MsgWrapper, C); + // We don't check for an invalid 'self' in an obj-c message expression to cut // down false positives where logging functions get information from self // (like its class) or doing "invalidation" on self when the initialization @@ -277,6 +277,11 @@ void ObjCSelfInitChecker::checkPreStmt(const CallOrObjCMessage &CE, CheckerContext &C) const { ProgramStateRef state = C.getState(); unsigned NumArgs = CE.getNumArgs(); + // If we passed 'self' as and argument to the call, record it in the state + // to be propagated after the call. + // Note, we could have just given up, but try to be more optimistic here and + // assume that the functions are going to continue initialization or will not + // modify self. for (unsigned i = 0; i < NumArgs; ++i) { SVal argV = CE.getArgSVal(i); if (isSelfVar(argV, C)) { @@ -298,14 +303,24 @@ void ObjCSelfInitChecker::checkPostStmt(const CallOrObjCMessage &CE, for (unsigned i = 0; i < NumArgs; ++i) { SVal argV = CE.getArgSVal(i); if (isSelfVar(argV, C)) { + // If the address of 'self' is being passed to the call, assume that the + // 'self' after the call will have the same flags. + // EX: log(&self) SelfFlagEnum prevFlags = (SelfFlagEnum)state->get(); state = state->remove(); addSelfFlag(state, state->getSVal(cast(argV)), prevFlags, C); return; } else if (hasSelfFlag(argV, SelfFlag_Self, C)) { + // If 'self' is passed to the call by value, assume that the function + // returns 'self'. So assign the flags, which were set on 'self' to the + // return value. + // EX: self = performMoreInitialization(self) SelfFlagEnum prevFlags = (SelfFlagEnum)state->get(); state = state->remove(); - addSelfFlag(state, state->getSVal(cast(argV)), prevFlags, C); + const Expr *CallExpr = CE.getOriginExpr(); + if (CallExpr) + addSelfFlag(state, state->getSVal(CallExpr, C.getLocationContext()), + prevFlags, C); return; } } @@ -358,7 +373,7 @@ static bool isSelfVar(SVal location, CheckerContext &C) { return false; loc::MemRegionVal MRV = cast(location); - if (const DeclRegion *DR = dyn_cast(MRV.getRegion())) + if (const DeclRegion *DR = dyn_cast(MRV.stripCasts())) return (DR->getDecl() == analCtx->getSelfDecl()); return false; diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp index 82ac8bda0210..eeaed2de8367 100644 --- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -8,8 +8,6 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" -#include "clang/Index/Entity.h" -#include "clang/Index/Indexer.h" using namespace clang; using namespace ento; @@ -22,7 +20,6 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, StoreManagerCreator storemgr, ConstraintManagerCreator constraintmgr, CheckerManager *checkerMgr, - idx::Indexer *idxer, unsigned maxnodes, unsigned maxvisit, bool vizdot, bool vizubi, AnalysisPurgeMode purge, @@ -38,7 +35,7 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, : AnaCtxMgr(useUnoptimizedCFG, addImplicitDtors, addInitializers), Ctx(ctx), Diags(diags), LangOpts(lang), PD(pd), CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), - CheckerMgr(checkerMgr), Idxer(idxer), + CheckerMgr(checkerMgr), AScope(ScopeDecl), MaxNodes(maxnodes), MaxVisit(maxvisit), VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge), EagerlyAssume(eager), TrimGraph(trim), @@ -62,7 +59,6 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, CreateStoreMgr(ParentAM.CreateStoreMgr), CreateConstraintMgr(ParentAM.CreateConstraintMgr), CheckerMgr(ParentAM.CheckerMgr), - Idxer(ParentAM.Idxer), AScope(ScopeDecl), MaxNodes(ParentAM.MaxNodes), MaxVisit(ParentAM.MaxVisit), @@ -80,21 +76,3 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, { AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd(); } - - -AnalysisDeclContext * -AnalysisManager::getAnalysisDeclContextInAnotherTU(const Decl *D) { - idx::Entity Ent = idx::Entity::get(const_cast(D), - Idxer->getProgram()); - FunctionDecl *FuncDef; - idx::TranslationUnit *TU; - llvm::tie(FuncDef, TU) = Idxer->getDefinitionFor(Ent); - - if (FuncDef == 0) - return 0; - - // This AnalysisDeclContext wraps function definition in another translation unit. - // But it is still owned by the AnalysisManager associated with the current - // translation unit. - return AnaCtxMgr.getContext(FuncDef, TU); -} diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp index eb986afa3dbc..ca662c799211 100644 --- a/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -17,7 +17,6 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" -#include "clang/Index/TranslationUnit.h" #include "clang/AST/Expr.h" #include "clang/AST/StmtCXX.h" #include "llvm/Support/Casting.h" diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index d2da9aaccb7c..1fd90685186e 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -536,6 +536,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::IfStmtClass: case Stmt::IndirectGotoStmtClass: case Stmt::LabelStmtClass: + case Stmt::AttributedStmtClass: case Stmt::NoStmtClass: case Stmt::NullStmtClass: case Stmt::SwitchStmtClass: diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index b99bd5441e41..b9f4e153d7e1 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -134,6 +134,11 @@ bool ExprEngine::shouldInlineDecl(const FunctionDecl *FD, ExplodedNode *Pred) { AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(FD); const CFG *CalleeCFG = CalleeADC->getCFG(); + // It is possible that the CFG cannot be constructed. + // Be safe, and check if the CalleeCFG is valid. + if (!CalleeCFG) + return false; + if (getNumberStackFrames(Pred->getLocationContext()) == AMgr.InlineMaxStackDepth) return false; diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index c19ebcbcc4b8..008f744957ef 100644 --- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -207,7 +207,6 @@ class AnalysisConsumer : public ASTConsumer, PP.getLangOpts(), PD, CreateStoreMgr, CreateConstraintMgr, checkerMgr.get(), - /* Indexer */ 0, Opts.MaxNodes, Opts.MaxLoop, Opts.VisualizeEGDot, Opts.VisualizeEGUbi, Opts.AnalysisPurgeOpt, Opts.EagerlyAssume, diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp index eea1055f491c..dd9ccc07b60b 100644 --- a/lib/Tooling/CompilationDatabase.cpp +++ b/lib/Tooling/CompilationDatabase.cpp @@ -13,7 +13,7 @@ #include "clang/Tooling/CompilationDatabase.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Support/JSONParser.h" +#include "llvm/Support/YAMLParser.h" #include "llvm/Support/Path.h" #include "llvm/Support/system_error.h" @@ -22,10 +22,10 @@ namespace tooling { namespace { -/// \brief A parser for JSON escaped strings of command line arguments. +/// \brief A parser for escaped strings of command line arguments. /// /// Assumes \-escaping for quoted arguments (see the documentation of -/// unescapeJSONCommandLine(...)). +/// unescapeCommandLine(...)). class CommandLineArgumentParser { public: CommandLineArgumentParser(StringRef CommandLine) @@ -90,9 +90,6 @@ class CommandLineArgumentParser { bool next() { ++Position; - if (Position == Input.end()) return false; - // Remove the JSON escaping first. This is done unconditionally. - if (*Position == '\\') ++Position; return Position != Input.end(); } @@ -101,9 +98,9 @@ class CommandLineArgumentParser { std::vector CommandLine; }; -std::vector unescapeJSONCommandLine( - StringRef JSONEscapedCommandLine) { - CommandLineArgumentParser parser(JSONEscapedCommandLine); +std::vector unescapeCommandLine( + StringRef EscapedCommandLine) { + CommandLineArgumentParser parser(EscapedCommandLine); return parser.parse(); } @@ -124,6 +121,33 @@ CompilationDatabase::loadFromDirectory(StringRef BuildDirectory, return Database.take(); } +FixedCompilationDatabase * +FixedCompilationDatabase::loadFromCommandLine(int &Argc, + const char **Argv, + Twine Directory) { + const char **DoubleDash = std::find(Argv, Argv + Argc, StringRef("--")); + if (DoubleDash == Argv + Argc) + return NULL; + std::vector CommandLine(DoubleDash + 1, Argv + Argc); + Argc = DoubleDash - Argv; + return new FixedCompilationDatabase(Directory, CommandLine); +} + +FixedCompilationDatabase:: +FixedCompilationDatabase(Twine Directory, ArrayRef CommandLine) { + std::vector ToolCommandLine(1, "clang-tool"); + ToolCommandLine.insert(ToolCommandLine.end(), + CommandLine.begin(), CommandLine.end()); + CompileCommands.push_back(CompileCommand(Directory, ToolCommandLine)); +} + +std::vector +FixedCompilationDatabase::getCompileCommands(StringRef FilePath) const { + std::vector Result(CompileCommands); + Result[0].CommandLine.push_back(FilePath); + return Result; +} + JSONCompilationDatabase * JSONCompilationDatabase::loadFromFile(StringRef FilePath, std::string &ErrorMessage) { @@ -162,65 +186,77 @@ JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const { const std::vector &CommandsRef = CommandsRefI->getValue(); std::vector Commands; for (int I = 0, E = CommandsRef.size(); I != E; ++I) { + llvm::SmallString<8> DirectoryStorage; + llvm::SmallString<1024> CommandStorage; Commands.push_back(CompileCommand( // FIXME: Escape correctly: - CommandsRef[I].first, - unescapeJSONCommandLine(CommandsRef[I].second))); + CommandsRef[I].first->getValue(DirectoryStorage), + unescapeCommandLine(CommandsRef[I].second->getValue(CommandStorage)))); } return Commands; } bool JSONCompilationDatabase::parse(std::string &ErrorMessage) { - llvm::SourceMgr SM; - llvm::JSONParser Parser(Database->getBuffer(), &SM); - llvm::JSONValue *Root = Parser.parseRoot(); - if (Root == NULL) { - ErrorMessage = "Error while parsing JSON."; + llvm::yaml::document_iterator I = YAMLStream.begin(); + if (I == YAMLStream.end()) { + ErrorMessage = "Error while parsing YAML."; return false; } - llvm::JSONArray *Array = dyn_cast(Root); + llvm::yaml::Node *Root = I->getRoot(); + if (Root == NULL) { + ErrorMessage = "Error while parsing YAML."; + return false; + } + llvm::yaml::SequenceNode *Array = + llvm::dyn_cast(Root); if (Array == NULL) { ErrorMessage = "Expected array."; return false; } - for (llvm::JSONArray::const_iterator AI = Array->begin(), AE = Array->end(); + for (llvm::yaml::SequenceNode::iterator AI = Array->begin(), + AE = Array->end(); AI != AE; ++AI) { - const llvm::JSONObject *Object = dyn_cast(*AI); + llvm::yaml::MappingNode *Object = + llvm::dyn_cast(&*AI); if (Object == NULL) { ErrorMessage = "Expected object."; return false; } - StringRef EntryDirectory; - StringRef EntryFile; - StringRef EntryCommand; - for (llvm::JSONObject::const_iterator KVI = Object->begin(), - KVE = Object->end(); + llvm::yaml::ScalarNode *Directory; + llvm::yaml::ScalarNode *Command; + llvm::SmallString<8> FileStorage; + llvm::StringRef File; + for (llvm::yaml::MappingNode::iterator KVI = Object->begin(), + KVE = Object->end(); KVI != KVE; ++KVI) { - const llvm::JSONValue *Value = (*KVI)->Value; + llvm::yaml::Node *Value = (*KVI).getValue(); if (Value == NULL) { ErrorMessage = "Expected value."; return false; } - const llvm::JSONString *ValueString = - dyn_cast(Value); + llvm::yaml::ScalarNode *ValueString = + llvm::dyn_cast(Value); if (ValueString == NULL) { ErrorMessage = "Expected string as value."; return false; } - if ((*KVI)->Key->getRawText() == "directory") { - EntryDirectory = ValueString->getRawText(); - } else if ((*KVI)->Key->getRawText() == "file") { - EntryFile = ValueString->getRawText(); - } else if ((*KVI)->Key->getRawText() == "command") { - EntryCommand = ValueString->getRawText(); + llvm::yaml::ScalarNode *KeyString = + llvm::dyn_cast((*KVI).getKey()); + llvm::SmallString<8> KeyStorage; + if (KeyString->getValue(KeyStorage) == "directory") { + Directory = ValueString; + } else if (KeyString->getValue(KeyStorage) == "command") { + Command = ValueString; + } else if (KeyString->getValue(KeyStorage) == "file") { + File = ValueString->getValue(FileStorage); } else { - ErrorMessage = (Twine("Unknown key: \"") + - (*KVI)->Key->getRawText() + "\"").str(); + ErrorMessage = ("Unknown key: \"" + + KeyString->getRawValue() + "\"").str(); return false; } } - IndexByFile[EntryFile].push_back( - CompileCommandRef(EntryDirectory, EntryCommand)); + IndexByFile[File].push_back( + CompileCommandRef(Directory, Command)); } return true; } diff --git a/test/Analysis/objc-bool.m b/test/Analysis/objc-bool.m index 631cd2d1fb21..f95736a6df51 100644 --- a/test/Analysis/objc-bool.m +++ b/test/Analysis/objc-bool.m @@ -1,4 +1,4 @@ -// RUN: %clang --analyze %s -o %t -verify +// RUN: %clang --analyze %s -o %t -Xclang -verify // Test handling of ObjC bool literals. diff --git a/test/Analysis/redefined_system.c b/test/Analysis/redefined_system.c index 3f585c4ef689..3c08b5e89642 100644 --- a/test/Analysis/redefined_system.c +++ b/test/Analysis/redefined_system.c @@ -12,6 +12,6 @@ char strdup(); char atoi(); int foo () { - return memmove() + malloc() + system + stdin() + memccpy() + free() + strdup() + atoi(); + return memmove() + malloc() + system() + stdin() + memccpy() + free() + strdup() + atoi(); } diff --git a/test/Analysis/self-init.m b/test/Analysis/self-init.m index 3db42e9cf5ac..d5151733430d 100644 --- a/test/Analysis/self-init.m +++ b/test/Analysis/self-init.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.SelfInit %s -verify +// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.SelfInit -fobjc-default-synthesize-properties %s -verify @class NSZone, NSCoder; @protocol NSObject- (id)self; @@ -48,9 +48,7 @@ void log(void *obj); extern void *somePtr; @class MyObj; -static id _commonInit(MyObj *self) { - return self; -} +extern id _commonInit(MyObj *self); @interface MyObj : NSObject { id myivar; @@ -59,6 +57,7 @@ static id _commonInit(MyObj *self) { -(id)_init; -(id)initWithSomething:(int)x; -(void)doSomething; ++(id)commonInitMember:(id)s; @end @interface MyProxyObj : NSProxy {} @@ -90,6 +89,14 @@ static id _commonInit(MyObj *self) { return self; } +-(id)init4_w { + [super init]; + if (self) { + log(&self); + } + return self; // expected-warning {{Returning 'self' while it is not set to the result of '[(super or self) init...]'}} +} + - (id)initWithSomething:(int)x { if ((self = [super init])) myint = x; @@ -157,6 +164,12 @@ static id _commonInit(MyObj *self) { return self; } +-(id)init14_w { + [super init]; + self = _commonInit(self); + return self; // expected-warning {{Returning 'self' while it is not set to the result of '[(super or self) init...]'}} +} + -(id)init15 { if (!(self = [super init])) return 0; @@ -176,6 +189,28 @@ static id _commonInit(MyObj *self) { return 0; } +-(id)init18 { + self = [super init]; + self = _commonInit(self); + return self; +} + ++(id)commonInitMember:(id)s { + return s; +} + +-(id)init19 { + self = [super init]; + self = [MyObj commonInitMember:self]; + return self; +} + +-(id)init19_w { + [super init]; + self = [MyObj commonInitMember:self]; + return self; // expected-warning {{Returning 'self'}} +} + -(void)doSomething {} @end @@ -201,3 +236,21 @@ static id _commonInit(MyObj *self) { } @end +// Test radar:11235991 - passing self to a call to super. +@protocol MyDelegate +@end +@interface Object : NSObject +- (id) initWithObject: (id)i; +@end +@interface Derived: Object +- (id) initWithInt: (int)t; +@property (nonatomic, retain, readwrite) Object *size; +@end +@implementation Derived +- (id) initWithInt: (int)t { + if ((self = [super initWithObject:self])) { + _size = [[Object alloc] init]; + } + return self; +} +@end diff --git a/test/CXX/class/class.mem/p2.cpp b/test/CXX/class/class.mem/p2.cpp index 09040d859c80..0a823f4c1f00 100644 --- a/test/CXX/class/class.mem/p2.cpp +++ b/test/CXX/class/class.mem/p2.cpp @@ -29,3 +29,30 @@ namespace test2 { A x; }; } + +namespace test3 { + struct A { + struct B { + void f() throw(A); + void g() throw(B); + }; + + void f() throw(A); + void g() throw(B); + }; + + template + struct A2 { + struct B { + void f1() throw(A2); + void f2() throw(A2); + void g() throw(B); + }; + + void f1() throw(A2); + void f2() throw(A2); + void g() throw(B); + }; + + template struct A2; +} diff --git a/test/CXX/except/except.spec/p1.cpp b/test/CXX/except/except.spec/p1.cpp index c68ec56a2491..e184ec4ffa21 100644 --- a/test/CXX/except/except.spec/p1.cpp +++ b/test/CXX/except/except.spec/p1.cpp @@ -65,7 +65,7 @@ namespace noexcept_unevaluated { } template - void g(T x) noexcept((sizeof(T) == sizeof(int)) || f(x)) { } + void g(T x) noexcept((sizeof(T) == sizeof(int)) || noexcept(f(x))) { } void h() { g(1); @@ -77,5 +77,5 @@ namespace PR11084 { static int f() noexcept(1/X) { return 10; } // expected-error{{argument to noexcept specifier must be a constant expression}} expected-note{{division by zero}} }; - void g() { A<0>::f(); } // expected-note{{in instantiation of template class 'PR11084::A<0>' requested here}} + void g() { A<0>::f(); } // expected-note{{in instantiation of exception specification for 'f' requested here}} } diff --git a/test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp b/test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp new file mode 100644 index 000000000000..ad4f4064c255 --- /dev/null +++ b/test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp @@ -0,0 +1,100 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify + +struct A { + int &f(int*); + float &f(int*) const noexcept; + + int *ptr; + auto g1() noexcept(noexcept(f(ptr))) -> decltype(f(this->ptr)); + auto g2() const noexcept(noexcept(f((*this).ptr))) -> decltype(f(ptr)); +}; + +void testA(A &a) { + int &ir = a.g1(); + float &fr = a.g2(); + static_assert(!noexcept(a.g1()), "exception-specification failure"); + static_assert(noexcept(a.g2()), "exception-specification failure"); +} + +struct B { + char g(); + template auto f(T t) -> decltype(t + g()) + { return t + g(); } +}; + +template auto B::f(int t) -> decltype(t + g()); + +template +struct C { + int &f(T*); + float &f(T*) const noexcept; + + T* ptr; + auto g1() noexcept(noexcept(f(ptr))) -> decltype(f((*this).ptr)); + auto g2() const noexcept(noexcept(f(((this))->ptr))) -> decltype(f(ptr)); +}; + +void test_C(C ci) { + int *p = 0; + int &ir = ci.g1(); + float &fr = ci.g2(); + static_assert(!noexcept(ci.g1()), "exception-specification failure"); + static_assert(noexcept(ci.g2()), "exception-specification failure"); +} + +namespace PR10036 { + template + void + iter_swap(I x, I y) noexcept; + + template + class A + { + T t_; + public: + void swap(A& a) noexcept(noexcept(iter_swap(&t_, &a.t_))); + }; + + void test() { + A i, j; + i.swap(j); + } +} + +namespace Static { + struct X1 { + int m; + static auto f() -> decltype(m); // expected-error{{'this' cannot be implicitly used in a static member function declaration}} + static auto g() -> decltype(this->m); // expected-error{{'this' cannot be used in a static member function declaration}} + + static int h(); + + static int i() noexcept(noexcept(m + 2)); // expected-error{{'this' cannot be implicitly used in a static member function declaration}} + }; + + auto X1::h() -> decltype(m) { return 0; } // expected-error{{'this' cannot be implicitly used in a static member function declaration}} + + template + struct X2 { + int m; + + T f(T*); + static T f(int); + + auto g(T x) -> decltype(f(x)) { return 0; } + }; + + void test_X2() { + X2().g(0); + } +} + +namespace PR12564 { + struct Base { + void bar(Base&) {} + }; + + struct Derived : Base { + void foo(Derived& d) noexcept(noexcept(d.bar(d))) {} + }; +} diff --git a/test/CXX/special/class.inhctor/elsewhere.cpp b/test/CXX/special/class.inhctor/elsewhere.cpp index 66afa17309fa..09fd3d50dc4d 100644 --- a/test/CXX/special/class.inhctor/elsewhere.cpp +++ b/test/CXX/special/class.inhctor/elsewhere.cpp @@ -9,15 +9,15 @@ struct B1 { B1(int); }; -using B1::B1; // expected-error {{using declaration can not refer to class member}} +using B1::B1; // expected-error {{using declaration can not refer to class member}} expected-error {{not supported}} // C++0x [namespace.udecl]p10: // A using-declaration is a declaration and can therefore be used repeatedly // where (and only where) multiple declarations are allowed. struct I1 : B1 { - using B1::B1; // expected-note {{previous using declaration}} - using B1::B1; // expected-error {{redeclaration of using decl}} + using B1::B1; // expected-note {{previous using declaration}} expected-error {{not supported}} + using B1::B1; // expected-error {{redeclaration of using decl}} expected-error {{not supported}} }; // C++0x [namespace.udecl]p3: @@ -27,31 +27,31 @@ struct I1 : B1 { // shall name a direct base class of the class being defined. struct D1 : I1 { - using B1::B1; // expected-error {{'B1' is not a direct base of 'D1', can not inherit constructors}} + using B1::B1; // expected-error {{'B1' is not a direct base of 'D1', can not inherit constructors}} expected-error {{not supported}} }; template struct A {}; template struct B : A, A { - using A::A; // expected-error {{'A::', which is not a base class of 'B'}} + using A::A; // expected-error {{'A::', which is not a base class of 'B'}} expected-error {{not supported}} }; B bb; B bc; B bd; // expected-note {{here}} template struct C : A { - using A::A; // expected-error {{'A::', which is not a base class of 'C'}} + using A::A; // expected-error {{'A::', which is not a base class of 'C'}} expected-error {{not supported}} }; C cb; C cc; // expected-note {{here}} template struct D : A {}; template struct E : D { - using A::A; // expected-error {{'A' is not a direct base of 'E', can not inherit}} + using A::A; // expected-error {{'A' is not a direct base of 'E', can not inherit}} expected-error {{not supported}} }; E eb; // expected-note {{here}} template struct F : D { - using A::A; // expected-error {{'A' is not a direct base of 'F'}} + using A::A; // expected-error {{'A' is not a direct base of 'F'}} expected-error {{not supported}} }; F fb; // expected-note {{here}} diff --git a/test/CXX/special/class.inhctor/p3.cpp b/test/CXX/special/class.inhctor/p3.cpp index f71ab16c0f17..d7093fb36943 100644 --- a/test/CXX/special/class.inhctor/p3.cpp +++ b/test/CXX/special/class.inhctor/p3.cpp @@ -5,7 +5,7 @@ struct B1 { B1(int, int); }; struct D1 : B1 { - using B1::B1; + using B1::B1; // expected-error {{not supported}} }; D1 d1a(1), d1b(1, 1); @@ -15,7 +15,7 @@ struct B2 { explicit B2(int, int = 0, int = 0); }; struct D2 : B2 { // expected-note 2 {{candidate constructor}} - using B2::B2; + using B2::B2; // expected-error {{not supported}} }; D2 d2a(1), d2b(1, 1), d2c(1, 1, 1); @@ -25,18 +25,18 @@ struct B3 { B3(void*); // expected-note {{inherited from here}} }; struct D3 : B3 { // expected-note 2 {{candidate constructor}} - using B3::B3; // expected-note {{candidate constructor (inherited)}} + using B3::B3; // expected-note {{candidate constructor (inherited)}} expected-error {{not supported}} }; D3 fd3() { return 1; } // expected-error {{no viable conversion}} template struct T1 : B1 { - using B1::B1; + using B1::B1; // expected-error {{not supported}} }; template struct T2 : T1 { - using T1::T1; + using T1::T1; // expected-error {{not supported}} }; template struct T3 : T1 { - using T1::T1; + using T1::T1; // expected-error {{not supported}} }; struct U { friend T1::T1(int); diff --git a/test/CXX/special/class.inhctor/p7.cpp b/test/CXX/special/class.inhctor/p7.cpp index 9ae160f0547a..bfaa3ac35987 100644 --- a/test/CXX/special/class.inhctor/p7.cpp +++ b/test/CXX/special/class.inhctor/p7.cpp @@ -8,12 +8,12 @@ struct B2 { B2(int); // expected-note {{conflicting constructor}} }; struct D1 : B1, B2 { - using B1::B1; // expected-note {{inherited here}} - using B2::B2; // expected-error {{already inherited constructor with the same signature}} + using B1::B1; // expected-note {{inherited here}} expected-error {{not supported}} + using B2::B2; // expected-error {{already inherited constructor with the same signature}} expected-error {{not supported}} }; struct D2 : B1, B2 { - using B1::B1; - using B2::B2; + using B1::B1; // expected-error {{not supported}} + using B2::B2; // expected-error {{not supported}} D2(int); }; @@ -22,8 +22,8 @@ template struct B3 { }; template struct B4 : B3, B1 { B4(); - using B3::B3; // expected-note {{inherited here}} - using B1::B1; // expected-error {{already inherited}} + using B3::B3; // expected-note {{inherited here}} expected-error {{not supported}} + using B1::B1; // expected-error {{already inherited}} expected-error {{not supported}} }; B4 b4c; B4 b4i; // expected-note {{here}} diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp index 6955219e7ae3..726e22227ed6 100644 --- a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp +++ b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp @@ -164,7 +164,7 @@ template // FIXME: this should test that the diagnostic reads "type contains..." struct alignas(Types) TestUnexpandedDecls : T{ // expected-error{{expression contains unexpanded parameter pack 'Types'}} void member_function(Types); // expected-error{{declaration type contains unexpanded parameter pack 'Types'}} - void member_function () throw(Types); // expected-error{{declaration type contains unexpanded parameter pack 'Types'}} + void member_function () throw(Types); // expected-error{{exception type contains unexpanded parameter pack 'Types'}} operator Types() const; // expected-error{{declaration type contains unexpanded parameter pack 'Types'}} Types data_member; // expected-error{{data member type contains unexpanded parameter pack 'Types'}} static Types static_data_member; // expected-error{{declaration type contains unexpanded parameter pack 'Types'}} diff --git a/test/CodeCompletion/preamble.c b/test/CodeCompletion/preamble.c new file mode 100644 index 000000000000..f322e09f12e0 --- /dev/null +++ b/test/CodeCompletion/preamble.c @@ -0,0 +1,7 @@ +#include "some_struct.h" +void foo() { + struct X x; + x. + +// RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:4:5 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s +// CHECK-CC1: FieldDecl:{ResultType int}{TypedText m} (35) (parent: StructDecl 'X') diff --git a/test/CodeCompletion/some_struct.h b/test/CodeCompletion/some_struct.h new file mode 100644 index 000000000000..63aa2a39d3f4 --- /dev/null +++ b/test/CodeCompletion/some_struct.h @@ -0,0 +1 @@ +struct X { int m; }; diff --git a/test/CodeGen/arm-homogenous.c b/test/CodeGen/arm-homogenous.c new file mode 100644 index 000000000000..eb3d5a6bd631 --- /dev/null +++ b/test/CodeGen/arm-homogenous.c @@ -0,0 +1,160 @@ +// RUN: %clang_cc1 -triple armv7---eabi -target-abi aapcs -mfloat-abi hard -emit-llvm %s -o - | FileCheck %s + +typedef long long int64_t; +typedef unsigned int uint32_t; + +/* This is not a homogenous aggregate - fundamental types are different */ +typedef union { + float f[4]; + uint32_t i[4]; +} union_with_first_floats; +union_with_first_floats g_u_f; + +extern void takes_union_with_first_floats(union_with_first_floats a); +extern union_with_first_floats returns_union_with_first_floats(void); + +void test_union_with_first_floats(void) { + takes_union_with_first_floats(g_u_f); +} +// CHECK: declare arm_aapcs_vfpcc void @takes_union_with_first_floats([4 x i32]) + +void test_return_union_with_first_floats(void) { + g_u_f = returns_union_with_first_floats(); +} +// CHECK: declare arm_aapcs_vfpcc void @returns_union_with_first_floats(%union.union_with_first_floats* sret) + +/* This is not a homogenous aggregate - fundamental types are different */ +typedef union { + uint32_t i[4]; + float f[4]; +} union_with_non_first_floats; +union_with_non_first_floats g_u_nf_f; + +extern void takes_union_with_non_first_floats(union_with_non_first_floats a); +extern union_with_non_first_floats returns_union_with_non_first_floats(void); + +void test_union_with_non_first_floats(void) { + takes_union_with_non_first_floats(g_u_nf_f); +} +// CHECK: declare arm_aapcs_vfpcc void @takes_union_with_non_first_floats([4 x i32]) + +void test_return_union_with_non_first_floats(void) { + g_u_nf_f = returns_union_with_non_first_floats(); +} +// CHECK: declare arm_aapcs_vfpcc void @returns_union_with_non_first_floats(%union.union_with_non_first_floats* sret) + +/* This is not a homogenous aggregate - fundamental types are different */ +typedef struct { + float a; + union_with_first_floats b; +} struct_with_union_with_first_floats; +struct_with_union_with_first_floats g_s_f; + +extern void takes_struct_with_union_with_first_floats(struct_with_union_with_first_floats a); +extern struct_with_union_with_first_floats returns_struct_with_union_with_first_floats(void); + +void test_struct_with_union_with_first_floats(void) { + takes_struct_with_union_with_first_floats(g_s_f); +} +// CHECK: declare arm_aapcs_vfpcc void @takes_struct_with_union_with_first_floats([5 x i32]) + +void test_return_struct_with_union_with_first_floats(void) { + g_s_f = returns_struct_with_union_with_first_floats(); +} +// CHECK: declare arm_aapcs_vfpcc void @returns_struct_with_union_with_first_floats(%struct.struct_with_union_with_first_floats* sret) + +/* This is not a homogenous aggregate - fundamental types are different */ +typedef struct { + float a; + union_with_non_first_floats b; +} struct_with_union_with_non_first_floats; +struct_with_union_with_non_first_floats g_s_nf_f; + +extern void takes_struct_with_union_with_non_first_floats(struct_with_union_with_non_first_floats a); +extern struct_with_union_with_non_first_floats returns_struct_with_union_with_non_first_floats(void); + +void test_struct_with_union_with_non_first_floats(void) { + takes_struct_with_union_with_non_first_floats(g_s_nf_f); +} +// CHECK: declare arm_aapcs_vfpcc void @takes_struct_with_union_with_non_first_floats([5 x i32]) + +void test_return_struct_with_union_with_non_first_floats(void) { + g_s_nf_f = returns_struct_with_union_with_non_first_floats(); +} +// CHECK: declare arm_aapcs_vfpcc void @returns_struct_with_union_with_non_first_floats(%struct.struct_with_union_with_non_first_floats* sret) + +/* Plain array is not a homogenous aggregate */ +extern void takes_array_of_floats(float a[4]); +void test_array_of_floats(void) { + float a[4] = {1.0, 2.0, 3.0, 4.0}; + takes_array_of_floats(a); +} +// CHECK: declare arm_aapcs_vfpcc void @takes_array_of_floats(float*) + +/* Struct-type homogenous aggregate */ +typedef struct { + float x, y, z, w; +} struct_with_fundamental_elems; +struct_with_fundamental_elems g_s; + +extern void takes_struct_with_fundamental_elems(struct_with_fundamental_elems a); +extern struct_with_fundamental_elems returns_struct_with_fundamental_elems(void); + +void test_struct_with_fundamental_elems(void) { + takes_struct_with_fundamental_elems(g_s); +// CHECK: call arm_aapcs_vfpcc void @takes_struct_with_fundamental_elems(float {{.*}}, float {{.*}}, float{{.*}}, float {{.*}}) +} +// CHECK: declare arm_aapcs_vfpcc void @takes_struct_with_fundamental_elems(float, float, float, float) + +void test_return_struct_with_fundamental_elems(void) { + g_s = returns_struct_with_fundamental_elems(); +// CHECK: call arm_aapcs_vfpcc %struct.struct_with_fundamental_elems @returns_struct_with_fundamental_elems() +} +// CHECK: declare arm_aapcs_vfpcc %struct.struct_with_fundamental_elems @returns_struct_with_fundamental_elems() + +/* Array-type homogenous aggregate */ +typedef struct { + float xyzw[4]; +} struct_with_array; +struct_with_array g_s_a; + +extern void takes_struct_with_array(struct_with_array a); +extern struct_with_array returns_struct_with_array(void); + +void test_struct_with_array(void) { + takes_struct_with_array(g_s_a); +// CHECK: call arm_aapcs_vfpcc void @takes_struct_with_array(float {{.*}}, float {{.*}}, float {{.*}}, float {{.*}}) +} +// CHECK: declare arm_aapcs_vfpcc void @takes_struct_with_array(float, float, float, float) + +void test_return_struct_with_array(void) { + g_s_a = returns_struct_with_array(); +// CHECK: call arm_aapcs_vfpcc %struct.struct_with_array @returns_struct_with_array() +} +// CHECK: declare arm_aapcs_vfpcc %struct.struct_with_array @returns_struct_with_array() + +/* This union is a homogenous aggregate. Check that it's passed properly */ +typedef union { + struct_with_fundamental_elems xyzw; + float a[3]; +} union_with_struct_with_fundamental_elems; +union_with_struct_with_fundamental_elems g_u_s_fe; + +extern void takes_union_with_struct_with_fundamental_elems(union_with_struct_with_fundamental_elems a); +extern union_with_struct_with_fundamental_elems returns_union_with_struct_with_fundamental_elems(void); + +void test_union_with_struct_with_fundamental_elems(void) { + takes_union_with_struct_with_fundamental_elems(g_u_s_fe); +// CHECK: call arm_aapcs_vfpcc void @takes_union_with_struct_with_fundamental_elems(float {{.*}}, float {{.*}}, float {{.*}}, float {{.*}}) +} +// CHECK: declare arm_aapcs_vfpcc void @takes_union_with_struct_with_fundamental_elems(float, float, float, float) + +void test_return_union_with_struct_with_fundamental_elems(void) { + g_u_s_fe = returns_union_with_struct_with_fundamental_elems(); +// CHECK: call arm_aapcs_vfpcc %union.union_with_struct_with_fundamental_elems @returns_union_with_struct_with_fundamental_elems() +} +// CHECK: declare arm_aapcs_vfpcc %union.union_with_struct_with_fundamental_elems @returns_union_with_struct_with_fundamental_elems() + +// FIXME: Tests necessary: +// - Vectors +// - C++ stuff \ No newline at end of file diff --git a/test/CodeGen/avx-shuffle-builtins.c b/test/CodeGen/avx-shuffle-builtins.c index 538ae50c938d..d071f825aa9e 100644 --- a/test/CodeGen/avx-shuffle-builtins.c +++ b/test/CodeGen/avx-shuffle-builtins.c @@ -48,18 +48,18 @@ __m256 test_mm256_permute_ps(__m256 a) { __m256d test_mm256_permute2f128_pd(__m256d a, __m256d b) { // Check if the mask is correct - // CHECK: shufflevector{{.*}} + // CHECK: @llvm.x86.avx.vperm2f128.pd.256 return _mm256_permute2f128_pd(a, b, 0x31); } __m256 test_mm256_permute2f128_ps(__m256 a, __m256 b) { // Check if the mask is correct - // CHECK: shufflevector{{.*}} + // CHECK: @llvm.x86.avx.vperm2f128.ps.256 return _mm256_permute2f128_ps(a, b, 0x13); } __m256i test_mm256_permute2f128_si256(__m256i a, __m256i b) { // Check if the mask is correct - // CHECK: shufflevector{{.*}} + // CHECK: @llvm.x86.avx.vperm2f128.si.256 return _mm256_permute2f128_si256(a, b, 0x20); } diff --git a/test/CodeGen/avx2-builtins.c b/test/CodeGen/avx2-builtins.c index a5ddc8eb2ed8..7d166b562638 100644 --- a/test/CodeGen/avx2-builtins.c +++ b/test/CodeGen/avx2-builtins.c @@ -662,7 +662,7 @@ __m256i test_mm256_permutevar8x32_epi32(__m256i a, __m256i b) { } __m256d test_mm256_permute4x64_pd(__m256d a) { - // CHECK: @llvm.x86.avx2.permpd + // CHECK: shufflevector{{.*}} return _mm256_permute4x64_pd(a, 25); } @@ -672,12 +672,12 @@ __m256 test_mm256_permutevar8x32_ps(__m256 a, __m256 b) { } __m256i test_mm256_permute4x64_epi64(__m256i a) { - // CHECK: @llvm.x86.avx2.permq + // CHECK: shufflevector{{.*}} return _mm256_permute4x64_epi64(a, 35); } __m256i test_mm256_permute2x128_si256(__m256i a, __m256i b) { - // CHECK: shufflevector{{.*}} + // CHECK: @llvm.x86.avx2.vperm2i128 return _mm256_permute2x128_si256(a, b, 0x31); } diff --git a/test/CodeGen/builtins-x86.c b/test/CodeGen/builtins-x86.c index 30138d6374fd..acb5554db4d3 100644 --- a/test/CodeGen/builtins-x86.c +++ b/test/CodeGen/builtins-x86.c @@ -414,6 +414,9 @@ void f0() { tmp_V4i = __builtin_ia32_cvttpd2dq256(tmp_V4d); tmp_V4i = __builtin_ia32_cvtpd2dq256(tmp_V4d); tmp_V8i = __builtin_ia32_cvttps2dq256(tmp_V8f); + tmp_V4d = __builtin_ia32_vperm2f128_pd256(tmp_V4d, tmp_V4d, 0x7); + tmp_V8f = __builtin_ia32_vperm2f128_ps256(tmp_V8f, tmp_V8f, 0x7); + tmp_V8i = __builtin_ia32_vperm2f128_si256(tmp_V8i, tmp_V8i, 0x7); tmp_V4d = __builtin_ia32_vinsertf128_pd256(tmp_V4d, tmp_V2d, 0x7); tmp_V8f = __builtin_ia32_vinsertf128_ps256(tmp_V8f, tmp_V4f, 0x7); tmp_V8i = __builtin_ia32_vinsertf128_si256(tmp_V8i, tmp_V4i, 0x7); diff --git a/test/CodeGen/may-alias.c b/test/CodeGen/may-alias.c index 6171be763dc7..b73ee15f8745 100644 --- a/test/CodeGen/may-alias.c +++ b/test/CodeGen/may-alias.c @@ -26,5 +26,5 @@ void test1(struct Test1MA *p1, struct Test1 *p2) { // CHECK: !0 = metadata !{metadata !"any pointer", metadata !1} // CHECK: !1 = metadata !{metadata !"omnipotent char", metadata !2} -// CHECK: !2 = metadata !{metadata !"Simple C/C++ TBAA", null} +// CHECK: !2 = metadata !{metadata !"Simple C/C++ TBAA"} // CHECK: !3 = metadata !{metadata !"int", metadata !1} diff --git a/test/CodeGen/packed-nest-unpacked.c b/test/CodeGen/packed-nest-unpacked.c index af1508ae81de..0ccc0c41b7e6 100644 --- a/test/CodeGen/packed-nest-unpacked.c +++ b/test/CodeGen/packed-nest-unpacked.c @@ -1,11 +1,12 @@ // RUN: %clang_cc1 %s -triple x86_64-apple-macosx10.7.2 -emit-llvm -o - | FileCheck %s -// struct X { int x[6]; }; struct Y { char x[13]; struct X y; } __attribute((packed)); struct Y g; void f(struct X); +struct X foo(void); +// struct X test1() { // CHECK: @test1 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* bitcast (%struct.X* getelementptr inbounds (%struct.Y* @g, i32 0, i32 1) to i8*), i64 24, i32 1, i1 false) @@ -24,8 +25,23 @@ void test3(struct X a) { g.y = a; } +// void test4() { // CHECK: @test4 // FIXME: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* bitcast (%struct.X* getelementptr inbounds (%struct.Y* @g, i32 0, i32 1) to i8*), i64 24, i32 1, i1 false) f(g.y); } + +// PR12395 +int test5() { + // CHECK: @test5 + // CHECK: load i32* getelementptr inbounds (%struct.Y* @g, i32 0, i32 1, i32 0, i64 0), align 1 + return g.y.x[0]; +} + +// +void test6() { + // CHECK: @test6 + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* bitcast (%struct.X* getelementptr inbounds (%struct.Y* @g, i32 0, i32 1) to i8*), i8* %{{.*}}, i64 24, i32 1, i1 false) + g.y = foo(); +} diff --git a/test/CodeGen/tbaa-for-vptr.cpp b/test/CodeGen/tbaa-for-vptr.cpp index f4885f805d27..5ce6bf32edf3 100644 --- a/test/CodeGen/tbaa-for-vptr.cpp +++ b/test/CodeGen/tbaa-for-vptr.cpp @@ -16,4 +16,4 @@ void CallFoo(A *a) { // CHECK: %{{.*}} = load {{.*}} !tbaa !0 // CHECK: store {{.*}} !tbaa !0 // CHECK: !0 = metadata !{metadata !"vtable pointer", metadata !1} -// CHECK: !1 = metadata !{metadata !"Simple C/C++ TBAA", null} +// CHECK: !1 = metadata !{metadata !"Simple C/C++ TBAA"} diff --git a/test/CodeGenCXX/block-byref-cxx-objc.cpp b/test/CodeGenCXX/block-byref-cxx-objc.cpp index 135e0c755194..30f1f074b9b3 100644 --- a/test/CodeGenCXX/block-byref-cxx-objc.cpp +++ b/test/CodeGenCXX/block-byref-cxx-objc.cpp @@ -23,3 +23,13 @@ int main() // CHECK: call void @_Block_object_assign // CHECK: define internal void @__destroy_helper_block_ // CHECK: call void @_Block_object_dispose + +// rdar://problem/11135650 +namespace test1 { + struct A { int x; A(); ~A(); }; + + void test() { + return; + __block A a; + } +} diff --git a/test/CodeGenCXX/const-init-cxx11.cpp b/test/CodeGenCXX/const-init-cxx11.cpp index c745deebf04b..62a345a49564 100644 --- a/test/CodeGenCXX/const-init-cxx11.cpp +++ b/test/CodeGenCXX/const-init-cxx11.cpp @@ -92,6 +92,9 @@ namespace Array { // CHECK: @_ZN5Array1cE = constant [6 x [4 x i8]] [{{.*}} c"foo\00", [4 x i8] c"a\00\00\00", [4 x i8] c"bar\00", [4 x i8] c"xyz\00", [4 x i8] c"b\00\00\00", [4 x i8] c"123\00"] extern constexpr char c[6][4] = { "foo", "a", { "bar" }, { 'x', 'y', 'z' }, { "b" }, '1', '2', '3' }; + // CHECK: @_ZN5Array2ucE = constant [4 x i8] c"foo\00" + extern constexpr unsigned char uc[] = { "foo" }; + struct C { constexpr C() : n(5) {} int n, m = 3 * n + 1; }; // CHECK: @_ZN5Array5ctorsE = constant [3 x {{.*}}] [{{.*}} { i32 5, i32 16 }, {{.*}} { i32 5, i32 16 }, {{.*}} { i32 5, i32 16 }] extern const C ctors[3]; diff --git a/test/CodeGenCXX/cxx11-exception-spec.cpp b/test/CodeGenCXX/cxx11-exception-spec.cpp new file mode 100644 index 000000000000..194b80cdd47e --- /dev/null +++ b/test/CodeGenCXX/cxx11-exception-spec.cpp @@ -0,0 +1,120 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -verify -fexceptions -fcxx-exceptions -triple x86_64-linux-gnu | FileCheck %s + +void h(); + +template void f() noexcept(sizeof(T) == 4) { h(); } +template void g() noexcept(sizeof(T) == 4); + +template struct S { + static void f() noexcept(sizeof(T) == 4) { h(); } + static void g() noexcept(sizeof(T) == 4); +}; + +// CHECK: define {{.*}} @_Z1fIsEvv() { +template<> void f() { h(); } +// CHECK: define {{.*}} @_Z1fIA2_sEvv() nounwind { +template<> void f() noexcept { h(); } + +// CHECK: define {{.*}} @_ZN1SIsE1fEv() +// CHECK-NOT: nounwind +template<> void S::f() { h(); } +// CHECK: define {{.*}} @_ZN1SIA2_sE1fEv() nounwind +template<> void S::f() noexcept { h(); } + +// CHECK: define {{.*}} @_Z1fIDsEvv() { +template void f(); +// CHECK: define {{.*}} @_Z1fIA2_DsEvv() nounwind { +template void f(); + +// CHECK: define {{.*}} @_ZN1SIDsE1fEv() +// CHECK-NOT: nounwind +template void S::f(); +// CHECK: define {{.*}} @_ZN1SIA2_DsE1fEv() nounwind +template void S::f(); + +void h() { + // CHECK: define {{.*}} @_Z1fIiEvv() nounwind { + f(); + // CHECK: define {{.*}} @_Z1fIA2_iEvv() { + f(); + + // CHECK: define {{.*}} @_ZN1SIiE1fEv() nounwind + S::f(); + // CHECK: define {{.*}} @_ZN1SIA2_iE1fEv() + // CHECK-NOT: nounwind + S::f(); + + // CHECK: define {{.*}} @_Z1fIfEvv() nounwind { + void (*f1)() = &f; + // CHECK: define {{.*}} @_Z1fIdEvv() { + void (*f2)() = &f; + + // CHECK: define {{.*}} @_ZN1SIfE1fEv() nounwind + void (*f3)() = &S::f; + // CHECK: define {{.*}} @_ZN1SIdE1fEv() + // CHECK-NOT: nounwind + void (*f4)() = &S::f; + + // CHECK: define {{.*}} @_Z1fIA4_cEvv() nounwind { + (void)&f; + // CHECK: define {{.*}} @_Z1fIcEvv() { + (void)&f; + + // CHECK: define {{.*}} @_ZN1SIA4_cE1fEv() nounwind + (void)&S::f; + // CHECK: define {{.*}} @_ZN1SIcE1fEv() + // CHECK-NOT: nounwind + (void)&S::f; +} + +// CHECK: define {{.*}} @_Z1iv +void i() { + // CHECK: declare {{.*}} @_Z1gIiEvv() nounwind + g(); + // CHECK: declare {{.*}} @_Z1gIA2_iEvv() + // CHECK-NOT: nounwind + g(); + + // CHECK: declare {{.*}} @_ZN1SIiE1gEv() nounwind + S::g(); + // CHECK: declare {{.*}} @_ZN1SIA2_iE1gEv() + // CHECK-NOT: nounwind + S::g(); + + // CHECK: declare {{.*}} @_Z1gIfEvv() nounwind + void (*g1)() = &g; + // CHECK: declare {{.*}} @_Z1gIdEvv() + // CHECK-NOT: nounwind + void (*g2)() = &g; + + // CHECK: declare {{.*}} @_ZN1SIfE1gEv() nounwind + void (*g3)() = &S::g; + // CHECK: declare {{.*}} @_ZN1SIdE1gEv() + // CHECK-NOT: nounwind + void (*g4)() = &S::g; + + // CHECK: declare {{.*}} @_Z1gIA4_cEvv() nounwind + (void)&g; + // CHECK: declare {{.*}} @_Z1gIcEvv() + // CHECK-NOT: nounwind + (void)&g; + + // CHECK: declare {{.*}} @_ZN1SIA4_cE1gEv() nounwind + (void)&S::g; + // CHECK: declare {{.*}} @_ZN1SIcE1gEv() + // CHECK-NOT: nounwind + (void)&S::g; +} + +template struct Nested { + template void f() noexcept(sizeof(T) == sizeof(U)); +}; + +// CHECK: define {{.*}} @_Z1jv +void j() { + // CHECK: declare {{.*}} @_ZN6NestedIiE1fILb1EcEEvv( + // CHECK-NOT: nounwind + Nested().f(); + // CHECK: declare {{.*}} @_ZN6NestedIlE1fILb0ElEEvv({{.*}}) nounwind + Nested().f(); +} diff --git a/test/CodeGenCXX/inheriting-constructor.cpp b/test/CodeGenCXX/inheriting-constructor.cpp index b921a6d2bb93..a99840290a55 100644 --- a/test/CodeGenCXX/inheriting-constructor.cpp +++ b/test/CodeGenCXX/inheriting-constructor.cpp @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s +// XFAIL: * + // PR12219 struct A { A(int); virtual ~A(); }; struct B : A { using A::A; ~B(); }; diff --git a/test/CodeGenCXX/mangle-this-cxx11.cpp b/test/CodeGenCXX/mangle-this-cxx11.cpp new file mode 100644 index 000000000000..f9e94797b159 --- /dev/null +++ b/test/CodeGenCXX/mangle-this-cxx11.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s + +struct B { + template U f(); +}; + +struct A { + B b; + // implicitly rewritten to (*this).b.f() + template auto f() -> decltype (b.f()); + template auto g() -> decltype (this->b.f()); +}; + +int main() { + A a; + // CHECK: call i32 @_ZN1A1fIiEEDTcldtdtdefpT1b1fIT_EEEv + a.f(); + // CHECK: call i32 @_ZN1A1gIiEEDTcldtptfpT1b1fIT_EEEv + a.g(); +} diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp index ed659de5e062..74278f7128c8 100644 --- a/test/CodeGenCXX/static-init.cpp +++ b/test/CodeGenCXX/static-init.cpp @@ -2,6 +2,7 @@ // CHECK: @_ZZ1hvE1i = internal global i32 0, align 4 // CHECK: @base_req = global [4 x i8] c"foo\00", align 1 +// CHECK: @base_req_uchar = global [4 x i8] c"bar\00", align 1 // CHECK: @_ZZN5test31BC1EvE1u = internal global { i8, [3 x i8] } { i8 97, [3 x i8] undef }, align 4 // CHECK: @_ZZN5test1L6getvarEiE3var = internal constant [4 x i32] [i32 1, i32 0, i32 2, i32 4], align 16 @@ -64,6 +65,7 @@ namespace test1 { // Make sure we emit the initializer correctly for the following: char base_req[] = { "foo" }; +unsigned char base_req_uchar[] = { "bar" }; namespace union_static_local { // CHECK: define internal void @_ZZN18union_static_local4testEvEN1c4mainEv diff --git a/test/CodeGenOpenCL/fpaccuracy.cl b/test/CodeGenOpenCL/fpmath.cl similarity index 79% rename from test/CodeGenOpenCL/fpaccuracy.cl rename to test/CodeGenOpenCL/fpmath.cl index d27316a799f3..704fcd739ac4 100644 --- a/test/CodeGenOpenCL/fpaccuracy.cl +++ b/test/CodeGenOpenCL/fpmath.cl @@ -4,13 +4,13 @@ typedef __attribute__(( ext_vector_type(4) )) float float4; float spscalardiv(float a, float b) { // CHECK: @spscalardiv - // CHECK: fdiv{{.*}}, !fpaccuracy ![[MD:[0-9]+]] + // CHECK: fdiv{{.*}}, !fpmath ![[MD:[0-9]+]] return a / b; } float4 spvectordiv(float4 a, float4 b) { // CHECK: @spvectordiv - // CHECK: fdiv{{.*}}, !fpaccuracy ![[MD]] + // CHECK: fdiv{{.*}}, !fpmath ![[MD]] return a / b; } @@ -18,7 +18,7 @@ float4 spvectordiv(float4 a, float4 b) { double dpscalardiv(double a, double b) { // CHECK: @dpscalardiv - // CHECK-NOT: !fpaccuracy + // CHECK-NOT: !fpmath return a / b; } diff --git a/test/Headers/typedef_guards.c b/test/Headers/typedef_guards.c index 1aa667bb7e04..646b2ca0efe8 100644 --- a/test/Headers/typedef_guards.c +++ b/test/Headers/typedef_guards.c @@ -1,4 +1,4 @@ -// RUN: %clang -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify %s // NULL is rdefined in stddef.h #define NULL ((void*) 0) diff --git a/test/Index/get-cursor.m b/test/Index/get-cursor.m index 60e35eedd427..5ac337598816 100644 --- a/test/Index/get-cursor.m +++ b/test/Index/get-cursor.m @@ -60,6 +60,15 @@ void foo3(Test3 *test3) { [test3 setFoo:2 withBar:4]; } +@interface Test4 +@end +@interface Test4(Dido) +@end +@implementation Test4(Dido) +@end + +@class Forw1, Forw2, Forw3; + // RUN: c-index-test -cursor-at=%s:4:28 -cursor-at=%s:5:28 %s | FileCheck -check-prefix=CHECK-PROP %s // CHECK-PROP: ObjCPropertyDecl=foo1:4:26 // CHECK-PROP: ObjCPropertyDecl=foo2:5:27 @@ -82,6 +91,14 @@ void foo3(Test3 *test3) { // CHECK-MEMBERREF: 52:11 MemberRefExpr=setImplicitProp::46:8 Extent=[52:5 - 52:23] Spelling=setImplicitProp: ([52:11 - 52:23]) // RUN: c-index-test -cursor-at=%s:56:24 -cursor-at=%s:60:14 \ +// RUN: -cursor-at=%s:65:20 -cursor-at=%s:67:25 \ +// RUN: -cursor-at=%s:70:10 -cursor-at=%s:70:16 -cursor-at=%s:70:25 \ // RUN: %s | FileCheck -check-prefix=CHECK-SPELLRANGE %s // CHECK-SPELLRANGE: 56:8 ObjCInstanceMethodDecl=setFoo:withBar::56:8 Extent=[56:1 - 56:37] Spelling=setFoo:withBar: ([56:8 - 56:14][56:22 - 56:29]) Selector index=1 // CHECK-SPELLRANGE: 60:3 ObjCMessageExpr=setFoo:withBar::56:8 Extent=[60:3 - 60:29] Spelling=setFoo:withBar: ([60:10 - 60:16][60:19 - 60:26]) Selector index=0 +// CHECK-SPELLRANGE: 65:12 ObjCCategoryDecl=Dido:65:12 Extent=[65:1 - 66:5] Spelling=Dido ([65:18 - 65:22]) +// CHECK-SPELLRANGE: 67:17 ObjCCategoryImplDecl=Dido:67:17 (Definition) Extent=[67:1 - 68:2] Spelling=Dido ([67:23 - 67:27]) + +// CHECK-SPELLRANGE: 70:8 ObjCClassRef=Forw1:70:8 Extent=[70:8 - 70:13] Spelling=Forw1 ([70:8 - 70:13]) +// CHECK-SPELLRANGE: 70:15 ObjCClassRef=Forw2:70:15 Extent=[70:15 - 70:20] Spelling=Forw2 ([70:15 - 70:20]) +// CHECK-SPELLRANGE: 70:22 ObjCClassRef=Forw3:70:22 Extent=[70:22 - 70:27] Spelling=Forw3 ([70:22 - 70:27]) diff --git a/test/Lexer/newline-eof-c++98-compat.cpp b/test/Lexer/newline-eof-c++98-compat.cpp index 7f7eebbad7d3..3e5c8e226235 100644 --- a/test/Lexer/newline-eof-c++98-compat.cpp +++ b/test/Lexer/newline-eof-c++98-compat.cpp @@ -1,4 +1,4 @@ -// RUN: %clang -cc1 -fsyntax-only -Wc++98-compat-pedantic -std=c++11 -verify %s +// RUN: %clang_cc1 -fsyntax-only -Wc++98-compat-pedantic -std=c++11 -verify %s // The following line isn't terminated, don't fix it. void foo() {} // expected-warning{{C++98 requires newline at end of file}} \ No newline at end of file diff --git a/test/Lexer/newline-eof.c b/test/Lexer/newline-eof.c index 12087b237080..825a266a0a36 100644 --- a/test/Lexer/newline-eof.c +++ b/test/Lexer/newline-eof.c @@ -1,4 +1,4 @@ -// RUN: %clang -cc1 -fsyntax-only -Wnewline-eof -verify %s +// RUN: %clang_cc1 -fsyntax-only -Wnewline-eof -verify %s // rdar://9133072 // The following line isn't terminated, don't fix it. diff --git a/test/Lexer/utf-16.c b/test/Lexer/utf-16.c index 2b313e49fd2d..169ee43ebe04 100644 --- a/test/Lexer/utf-16.c +++ b/test/Lexer/utf-16.c @@ -1,4 +1,4 @@ -// RUN: not %clang %s -fsyntax-only -verify +// RUN: %clang_cc1 %s -fsyntax-only -verify // rdar://7876588 // This test verifies that clang gives a decent error for UTF-16 source files. diff --git a/test/Misc/message-length.c b/test/Misc/message-length.c index 3e69b6a206ee..a6f4f44e6b9c 100644 --- a/test/Misc/message-length.c +++ b/test/Misc/message-length.c @@ -27,9 +27,8 @@ void a_very_long_line(int *ip, float *FloatPointer) { #pragma STDC CX_LIMITED_RANGE // some long comment text and a brace, eh {} - // CHECK: FILE:23:78 -// CHECK: {{^ ...// some long comment text and a brace, eh {} }} +// CHECK: {{^ ...// some long comment text and a brace, eh {}}} struct A { int x; }; void h(struct A *a) { diff --git a/test/Misc/pubnames.c b/test/Misc/pubnames.c deleted file mode 100644 index 03048972c002..000000000000 --- a/test/Misc/pubnames.c +++ /dev/null @@ -1,19 +0,0 @@ -// RUN: %clang_cc1 -pubnames-dump %s | FileCheck %s -#define FOO -#define BAR -#undef FOO -#define WIBBLE - -int foo(); -int bar(float); -int wibble; - -// CHECK: BAR -// CHECK-NOT: FOO -// CHECK: WIBBLE -// CHECK-NOT: __clang_major__ -// CHECK: bar -// CHECK: foo -// CHECK: wibble - - diff --git a/test/Misc/unprintable.c b/test/Misc/unprintable.c new file mode 100644 index 000000000000..860503e63c39 --- /dev/null +++ b/test/Misc/unprintable.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 %s 2>&1 | FileCheck -strict-whitespace %s + +int main() { + int i; + if((i==/*👿*/1)); + +// CHECK: {{^ if\(\(i==/\*\*/1\)\);}} + +// CHECK: {{^ ~\^~~~~~~~~~~~~~~~}} +// CHECK: {{^ ~ \^ ~}} + + /* 👿 */ "👿berhund"; + +// CHECK: {{^ /\* \*/ "berhund";}} +// CHECK: {{^ \^~~~~~~~~~~~~~~~~~}} +} \ No newline at end of file diff --git a/test/Misc/wnull-character.cpp b/test/Misc/wnull-character.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a618da272a13f98e9ebb3100bed68e19daab51cb GIT binary patch literal 143 zcmWm6K?{N~7>DuB`xJi!I}~Ht(aeh!LD3e4b4HNqC>2v<^D1}>n&5@GR z{@D;^kdHWe)?e9sH$vY1$2m!z4w~2mq!HV4nc;_{b*AbJy&xk8ODu=ZvWag^W@17q jRHs9A&T&a}QLi^sWt)g$o;3{WePpZ#>}RlOlb!ej-GwXN literal 0 HcmV?d00001 diff --git a/test/Misc/wrong-encoding.c b/test/Misc/wrong-encoding.c new file mode 100644 index 000000000000..bd1cf3dc02ae --- /dev/null +++ b/test/Misc/wrong-encoding.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck -strict-whitespace %s + +void foo() { + + "§Ã"; // ø +// CHECK: {{^ ""; // }} +// CHECK: {{^ \^}} + + /* þ« */ const char *d = "¥"; + +// CHECK: {{^ /\* \*/ const char \*d = "";}} +// CHECK: {{^ \^}} + +// CHECK: {{^ ""; // }} +// CHECK: {{^ \^~~~~~~~~~}} +} diff --git a/test/PCH/typo2.cpp b/test/PCH/typo2.cpp new file mode 100644 index 000000000000..f9b4c833e040 --- /dev/null +++ b/test/PCH/typo2.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -emit-pch %s -o %t.pch +// RUN: %clang_cc1 -include-pch %t.pch %s -verify + +#ifndef HEADER_INCLUDED +#define HEADER_INCLUDED + +void func(struct Test); // expected-note{{'Test' declared here}} + +#else + +::Yest *T; // expected-error{{did you mean 'Test'}} + +#endif diff --git a/test/Parser/MicrosoftExtensions.cpp b/test/Parser/MicrosoftExtensions.cpp index 89394c303ca8..3a1ffea453ca 100644 --- a/test/Parser/MicrosoftExtensions.cpp +++ b/test/Parser/MicrosoftExtensions.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wmicrosoft -verify -fms-extensions -fdelayed-template-parsing +// RUN: %clang_cc1 %s -std=c++11 -fsyntax-only -Wno-unused-value -Wmicrosoft -verify -fms-extensions -fms-compatibility -fdelayed-template-parsing /* Microsoft attribute tests */ [repeatable][source_annotation_attribute( Parameter|ReturnValue )] @@ -103,7 +103,7 @@ typedef COM_CLASS_TEMPLATE COM_TYPE_2; template class COM_CLASS_TEMPLATE_REF { }; -typedef COM_CLASS_TEMPLATE COM_TYPE_REF; +typedef COM_CLASS_TEMPLATE_REF COM_TYPE_REF; struct late_defined_uuid; template @@ -284,3 +284,28 @@ int main () { missing_template_keyword(); } + + + +namespace access_protected_PTM { + +class A { +protected: + void f(); // expected-note {{must name member using the type of the current context 'access_protected_PTM::B'}} +}; + +class B : public A{ +public: + void test_access(); + static void test_access_static(); +}; + +void B::test_access() { + &A::f; // expected-error {{'f' is a protected member of 'access_protected_PTM::A'}} +} + +void B::test_access_static() { + &A::f; +} + +} \ No newline at end of file diff --git a/test/Parser/cxx11-stmt-attributes.cpp b/test/Parser/cxx11-stmt-attributes.cpp new file mode 100644 index 000000000000..fab56218eb84 --- /dev/null +++ b/test/Parser/cxx11-stmt-attributes.cpp @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 %s + +void foo(int i) { + + [[unknown_attribute]] ; + [[unknown_attribute]] { } + [[unknown_attribute]] if (0) { } + [[unknown_attribute]] for (;;); + [[unknown_attribute]] do { + [[unknown_attribute]] continue; + } while (0); + [[unknown_attribute]] while (0); + + [[unknown_attribute]] switch (i) { + [[unknown_attribute]] case 0: + [[unknown_attribute]] default: + [[unknown_attribute]] break; + } + + [[unknown_attribute]] goto here; + [[unknown_attribute]] here: + + [[unknown_attribute]] try { + } catch (...) { + } + + [[unknown_attribute]] return; + + + alignas(8) ; // expected-warning {{attribute aligned cannot be specified on a statement}} + [[noreturn]] { } // expected-warning {{attribute noreturn cannot be specified on a statement}} + [[noreturn]] if (0) { } // expected-warning {{attribute noreturn cannot be specified on a statement}} + [[noreturn]] for (;;); // expected-warning {{attribute noreturn cannot be specified on a statement}} + [[noreturn]] do { // expected-warning {{attribute noreturn cannot be specified on a statement}} + [[unavailable]] continue; // TODO: only noreturn, alignas and carries_dependency are parsed in C++ 11 syntax at the moment, hence no warning here + } while (0); + [[unknown_attributqqq]] while (0); // TODO: remove 'qqq' part and enjoy 'empty loop body' warning here (DiagnoseEmptyLoopBody) + [[unknown_attribute]] while (0); // no warning here yet, just an unknown attribute + + [[unused]] switch (i) { // TODO: only noreturn, alignas and carries_dependency are parsed in C++ 11 syntax at the moment, hence no warning here + [[uuid]] case 0: // TODO: only noreturn, alignas and carries_dependency are parsed in C++ 11 syntax at the moment, hence no warning here + [[visibility]] default: // TODO: only noreturn, alignas and carries_dependency are parsed in C++ 11 syntax at the moment, hence no warning here + [[carries_dependency]] break; // expected-warning {{attribute carries_dependency cannot be specified on a statement}} + } + + [[fastcall]] goto there; // TODO: only noreturn, alignas and carries_dependency are parsed in C++ 11 syntax at the moment, hence no warning here + [[noinline]] there: // TODO: only noreturn, alignas and carries_dependency are parsed in C++ 11 syntax at the moment, hence no warning here + + [[lock_returned]] try { // TODO: only noreturn, alignas and carries_dependency are parsed in C++ 11 syntax at the moment, hence no warning here + } catch (...) { + } + + [[weakref]] return; // TODO: only noreturn, alignas and carries_dependency are parsed in C++ 11 syntax at the moment, hence no warning here +} diff --git a/test/Parser/objcxx11-attributes.mm b/test/Parser/objcxx11-attributes.mm index 0875b66e2132..0c91392978af 100644 --- a/test/Parser/objcxx11-attributes.mm +++ b/test/Parser/objcxx11-attributes.mm @@ -31,15 +31,17 @@ void f(X *noreturn) { // An attribute is OK. [[]]; - [[int(), noreturn]]; + [[int(), noreturn]]; // expected-warning {{attribute noreturn cannot be specified on a statement}} [[class, test(foo 'x' bar),,,]]; - [[bitand, noreturn]]; + [[bitand, noreturn]]; // expected-warning {{attribute noreturn cannot be specified on a statement}} [[noreturn]]int(e)(); + int e2(); // expected-warning {{interpreted as a function declaration}} expected-note{{}} // A function taking a noreturn function. - int(f)([[noreturn]] int()); + int(f)([[noreturn]] int()); // expected-note {{here}} f(e); + f(e2); // expected-error {{cannot initialize a parameter of type 'int (*)() __attribute__((noreturn))' with an lvalue of type 'int ()'}} // Variables initialized by a message send. int(g)([[noreturn getSelf] getSize]); diff --git a/test/Preprocessor/pragma_sysheader.c b/test/Preprocessor/pragma_sysheader.c index 26416827c01b..17080fec53db 100644 --- a/test/Preprocessor/pragma_sysheader.c +++ b/test/Preprocessor/pragma_sysheader.c @@ -1,4 +1,4 @@ -// RUN: %clang -verify -pedantic %s -fsyntax-only +// RUN: %clang_cc1 -verify -pedantic %s -fsyntax-only // RUN: %clang_cc1 -E %s | FileCheck %s // rdar://6899937 #include "pragma_sysheader.h" diff --git a/test/Rewriter/blockcast3.mm b/test/Rewriter/blockcast3.mm index 8b35528cfbeb..ceafcff3b091 100644 --- a/test/Rewriter/blockcast3.mm +++ b/test/Rewriter/blockcast3.mm @@ -1,5 +1,8 @@ -// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp +// RUN: %clang_cc1 -E %s -o %t.mm +// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %t.mm -o %t-rw.cpp // RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s +// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %t.mm -o %t-modern-rw.cpp +// RUN: FileCheck -check-prefix LP --input-file=%t-modern-rw.cpp %s // radar 7607781 typedef struct { @@ -20,4 +23,4 @@ void f(const void **arg) { }); } -// CHECK-LP: (struct __Block_byref_q_0 *)&q +// CHECK-LP: (__Block_byref_q_0 *)&q diff --git a/test/Rewriter/instancetype-test.mm b/test/Rewriter/instancetype-test.mm index a92a3f7f7b00..788505562c39 100644 --- a/test/Rewriter/instancetype-test.mm +++ b/test/Rewriter/instancetype-test.mm @@ -1,5 +1,7 @@ -// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp -// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fms-extensions -rewrite-objc %s -o %t-modern-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp void *sel_registerName(const char *); diff --git a/test/Rewriter/objc-bool-literal-check-modern.mm b/test/Rewriter/objc-bool-literal-check-modern.mm index b28e594d72a6..338619715e12 100644 --- a/test/Rewriter/objc-bool-literal-check-modern.mm +++ b/test/Rewriter/objc-bool-literal-check-modern.mm @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %t.mm -o - | FileCheck %s // rdar://11124775 -typedef signed char BOOL; +typedef bool BOOL; BOOL yes() { return __objc_yes; @@ -22,8 +22,8 @@ int main() { return __objc_yes; } -// CHECK: return ((signed char)1); -// CHECK: return ((signed char)0); -// CHECK: which (((signed char)1)); -// CHECK: which (((signed char)0)); -// CHECK: return ((signed char)1); +// CHECK: return ((bool)1); +// CHECK: return ((bool)0); +// CHECK: which (((bool)1)); +// CHECK: which (((bool)0)); +// CHECK: return ((bool)1); diff --git a/test/Rewriter/objc-bool-literal-modern.mm b/test/Rewriter/objc-bool-literal-modern.mm index 6bbbb449c907..328ee6bf46f0 100644 --- a/test/Rewriter/objc-bool-literal-modern.mm +++ b/test/Rewriter/objc-bool-literal-modern.mm @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fsyntax-only -D"__declspec(X)=" %t-rw.cpp // rdar://11124775 -typedef signed char BOOL; +typedef bool BOOL; BOOL yes() { return __objc_yes; diff --git a/test/Rewriter/objc-modern-numeric-literal.mm b/test/Rewriter/objc-modern-numeric-literal.mm index d27d03d54e23..5f0b1fc3b1ee 100644 --- a/test/Rewriter/objc-modern-numeric-literal.mm +++ b/test/Rewriter/objc-modern-numeric-literal.mm @@ -4,7 +4,7 @@ extern "C" void *sel_registerName(const char *); -typedef signed char BOOL; +typedef bool BOOL; typedef long NSInteger; typedef unsigned long NSUInteger; @@ -63,7 +63,7 @@ int main(int argc, const char *argv[]) { // CHECK: NSNumber *fortyTwoLongLong = ((NSNumber *(*)(id, SEL, long long))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithLongLong:"), 42LL); // CHECK: NSNumber *piFloat = ((NSNumber *(*)(id, SEL, float))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithFloat:"), 3.1415927); // CHECK: NSNumber *piDouble = ((NSNumber *(*)(id, SEL, double))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithDouble:"), 3.1415926535); -// CHECK: NSNumber *yesNumber = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), (BOOL)true); -// CHECK: NSNumber *noNumber = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), (BOOL)false); -// CHECK: NSNumber *trueNumber = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), (BOOL)true); -// CHECK: NSNumber *falseNumber = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), (BOOL)false); +// CHECK: NSNumber *yesNumber = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), true); +// CHECK: NSNumber *noNumber = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), false); +// CHECK: NSNumber *trueNumber = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), true); +// CHECK: NSNumber *falseNumber = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), false); diff --git a/test/Rewriter/rewrite-block-consts.mm b/test/Rewriter/rewrite-block-consts.mm index fca10edd4f61..1d6de8cd6abc 100644 --- a/test/Rewriter/rewrite-block-consts.mm +++ b/test/Rewriter/rewrite-block-consts.mm @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp -// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D__block="" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp // rdar:// 8243071 void x(int y) {} diff --git a/test/Rewriter/rewrite-block-literal-1.mm b/test/Rewriter/rewrite-block-literal-1.mm index 5213f500b986..f152117443a7 100644 --- a/test/Rewriter/rewrite-block-literal-1.mm +++ b/test/Rewriter/rewrite-block-literal-1.mm @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp // RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -Did="void *" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp // radar 9254348 +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-modern-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -Did="void *" -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp +// rdar://11259664 void *sel_registerName(const char *); typedef void (^BLOCK_TYPE)(void); diff --git a/test/Rewriter/rewrite-block-literal.mm b/test/Rewriter/rewrite-block-literal.mm index 732d0b9f8db9..083312e79dd7 100644 --- a/test/Rewriter/rewrite-block-literal.mm +++ b/test/Rewriter/rewrite-block-literal.mm @@ -1,7 +1,9 @@ // RUN: %clang_cc1 -E %s -o %t.mm // RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %t.mm -o - | FileCheck %s // RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp -// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-modern-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp // rdar: // 11006566 diff --git a/test/Rewriter/rewrite-block-pointer.mm b/test/Rewriter/rewrite-block-pointer.mm index 4838b74439ff..58407a7ac5cf 100644 --- a/test/Rewriter/rewrite-block-pointer.mm +++ b/test/Rewriter/rewrite-block-pointer.mm @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp // RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-modern-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp // radar 7638400 typedef void * id; diff --git a/test/Rewriter/rewrite-byref-in-nested-blocks.mm b/test/Rewriter/rewrite-byref-in-nested-blocks.mm index b1ff46b5ce4a..a65938345637 100644 --- a/test/Rewriter/rewrite-byref-in-nested-blocks.mm +++ b/test/Rewriter/rewrite-byref-in-nested-blocks.mm @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp // RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-modern-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp // radar 7692350 void f(void (^block)(void)); diff --git a/test/Rewriter/rewrite-elaborated-type.mm b/test/Rewriter/rewrite-elaborated-type.mm index bef56b93b9b4..a0c7e43b0429 100644 --- a/test/Rewriter/rewrite-elaborated-type.mm +++ b/test/Rewriter/rewrite-elaborated-type.mm @@ -1,5 +1,7 @@ -// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp // RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D_Bool=bool -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fms-extensions -rewrite-objc %s -o %t-modern-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D_Bool=bool -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp // radar 8143056 typedef struct objc_class *Class; @@ -29,6 +31,8 @@ struct NSSlice { } @end +@interface I1 @end + @implementation I1 + (struct s1 *) f0 { return 0; diff --git a/test/Rewriter/rewrite-foreach-in-block.mm b/test/Rewriter/rewrite-foreach-in-block.mm index d0a8728310e9..fd34212d672e 100644 --- a/test/Rewriter/rewrite-foreach-in-block.mm +++ b/test/Rewriter/rewrite-foreach-in-block.mm @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp // RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-modern-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp // rdar:// 9878420 void objc_enumerationMutation(id); diff --git a/test/Rewriter/rewrite-modern-container-literal.mm b/test/Rewriter/rewrite-modern-container-literal.mm index 87b9b892813d..2c2f61df1d49 100644 --- a/test/Rewriter/rewrite-modern-container-literal.mm +++ b/test/Rewriter/rewrite-modern-container-literal.mm @@ -5,7 +5,7 @@ void *sel_registerName(const char *); typedef unsigned long NSUInteger; typedef long NSInteger; -typedef signed char BOOL; +typedef bool BOOL; @interface NSNumber + (NSNumber *)numberWithChar:(char)value; diff --git a/test/Rewriter/rewrite-modern-extern-c-func-decl.mm b/test/Rewriter/rewrite-modern-extern-c-func-decl.mm new file mode 100644 index 000000000000..10023bbc9f9f --- /dev/null +++ b/test/Rewriter/rewrite-modern-extern-c-func-decl.mm @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -fms-extensions -rewrite-objc -x objective-c++ -fblocks -o %t-rw.cpp %s +// RUN: %clang_cc1 -fsyntax-only -Werror -Wno-address-of-temporary -Wno-attributes -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// rdar://11131490 + +// XFAIL: mingw +// FIXME: __declspec(X) is predefined on mingw. + +extern "C" __declspec(dllexport) void BreakTheRewriter(void) { + __block int aBlockVariable = 0; + void (^aBlock)(void) = ^ { + aBlockVariable = 42; + }; + aBlockVariable++; + void (^bBlocks)(void) = ^ { + aBlockVariable = 43; + }; + void (^c)(void) = ^ { + aBlockVariable = 44; + }; + +} +__declspec(dllexport) extern "C" void AnotherBreakTheRewriter(int *p1, double d) { + + __block int bBlockVariable = 0; + void (^aBlock)(void) = ^ { + bBlockVariable = 42; + }; + bBlockVariable++; + void (^bBlocks)(void) = ^ { + bBlockVariable = 43; + }; + void (^c)(void) = ^ { + bBlockVariable = 44; + }; + +} + +int + +__declspec (dllexport) + +main (int argc, char *argv[]) +{ + __block int bBlockVariable = 0; + void (^aBlock)(void) = ^ { + bBlockVariable = 42; + }; +} diff --git a/test/Rewriter/rewrite-modern-protocol-1.mm b/test/Rewriter/rewrite-modern-protocol-1.mm new file mode 100644 index 000000000000..7b737fe61d66 --- /dev/null +++ b/test/Rewriter/rewrite-modern-protocol-1.mm @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -E %s -o %t.mm +// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %t.mm -o - | FileCheck %s +// rdar://11248048 + +@protocol NSCopying @end + +@interface INTF +@end + +@implementation INTF @end + +// CHECK: static struct _protocol_t _OBJC_PROTOCOL_NSCopying +// CHECK: static struct _protocol_t *_OBJC_LABEL_PROTOCOL_$_NSCopying = &_OBJC_PROTOCOL_NSCopying; + diff --git a/test/Rewriter/rewrite-modern-super.mm b/test/Rewriter/rewrite-modern-super.mm new file mode 100644 index 000000000000..ee397b332570 --- /dev/null +++ b/test/Rewriter/rewrite-modern-super.mm @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"id=struct objc_object *" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// rdar://11239894 + +extern "C" void *sel_registerName(const char *); + +typedef struct objc_class * Class; + +@interface Sub +- (void)dealloc; +@end + +@interface I : Sub +- (void)dealloc; +@end + +@implementation I +- (void)dealloc { + return; + [super dealloc]; +} +@end + diff --git a/test/Rewriter/rewrite-modern-typeof.mm b/test/Rewriter/rewrite-modern-typeof.mm new file mode 100644 index 000000000000..4650ab7b7f30 --- /dev/null +++ b/test/Rewriter/rewrite-modern-typeof.mm @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -Wno-attributes -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp + +extern "C" { +extern "C" void *_Block_copy(const void *aBlock); +extern "C" void _Block_release(const void *aBlock); +} + +int main() { + __attribute__((__blocks__(byref))) int a = 42; + int save_a = a; + + void (^b)(void) = ^{ + ((__typeof(^{ a = 2; }))_Block_copy((const void *)(^{ a = 2; }))); + }; + + ((__typeof(b))_Block_copy((const void *)(b))); + + return 0; +} + +// CHECK-LP: ((void (^)(void))_Block_copy((const void *)(b))) + +// radar 7628153 +void f() { + int a; + __typeof__(a) aVal = a; + char *a1t = (char *)@encode(__typeof__(a)); + __typeof__(aVal) bVal; + char *a2t = (char *)@encode(__typeof__(bVal)); + __typeof__(bVal) cVal = bVal; + char *a3t = (char *)@encode(__typeof__(cVal)); + +} + +// rdar://11239324 +void x() { + id y; + void (^z)() = ^{ }; + y = (id)((__typeof(z))_Block_copy((const void *)(z))); +} + +// CHECK-LP: int aVal = a; + +// CHECK-LP: int bVal; diff --git a/test/Rewriter/rewrite-nested-blocks-1.mm b/test/Rewriter/rewrite-nested-blocks-1.mm index 672486b1f9e2..25b17cfce179 100644 --- a/test/Rewriter/rewrite-nested-blocks-1.mm +++ b/test/Rewriter/rewrite-nested-blocks-1.mm @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp // RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-modern-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp // radar 7696893 void *sel_registerName(const char *); diff --git a/test/Rewriter/rewrite-nested-blocks-2.mm b/test/Rewriter/rewrite-nested-blocks-2.mm index 155576708669..d1513f3a5fa0 100644 --- a/test/Rewriter/rewrite-nested-blocks-2.mm +++ b/test/Rewriter/rewrite-nested-blocks-2.mm @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp // RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp // grep "static void __FUNC_block_copy_" %t-rw.cpp | count 2 +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-modern-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp +// grep "static void __FUNC_block_copy_" %t-modern-rw.cpp | count 2 // rdar://8499592 void Outer(void (^bk)()); diff --git a/test/Rewriter/rewrite-nested-blocks.mm b/test/Rewriter/rewrite-nested-blocks.mm index 6c860ef7e720..d492afa18d49 100644 --- a/test/Rewriter/rewrite-nested-blocks.mm +++ b/test/Rewriter/rewrite-nested-blocks.mm @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp // RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-modern-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp // radar 7682149 diff --git a/test/Rewriter/rewrite-nested-property-in-blocks.mm b/test/Rewriter/rewrite-nested-property-in-blocks.mm index 6a03d7319d68..7f9361ed0788 100755 --- a/test/Rewriter/rewrite-nested-property-in-blocks.mm +++ b/test/Rewriter/rewrite-nested-property-in-blocks.mm @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp // RUN: %clang_cc1 -fsyntax-only -fms-extensions -Wno-address-of-temporary -Did="void *" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-modern-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -fms-extensions -Wno-address-of-temporary -Did="void *" -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp // radar 8608293 void *sel_registerName(const char *); diff --git a/test/Rewriter/rewrite-unique-block-api.mm b/test/Rewriter/rewrite-unique-block-api.mm index 2c0c4a9094db..1dcc1b67fe7b 100644 --- a/test/Rewriter/rewrite-unique-block-api.mm +++ b/test/Rewriter/rewrite-unique-block-api.mm @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp // RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-modern-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp // radar 7630551 void f(void (^b)(char c)); diff --git a/test/Sema/const-eval-64.c b/test/Sema/const-eval-64.c new file mode 100644 index 000000000000..5727a93e51fa --- /dev/null +++ b/test/Sema/const-eval-64.c @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux %s + +#define EVAL_EXPR(testno, expr) int test##testno = sizeof(struct{char qq[expr];}); + +// +EVAL_EXPR(1, ((char*)-1LL) + 1 == 0 ? 1 : -1) +EVAL_EXPR(2, ((char*)-1LL) + 1 < (char*) -1 ? 1 : -1) diff --git a/test/Sema/const-eval.c b/test/Sema/const-eval.c index f1c0485bc1d4..bc8b227ac8b9 100644 --- a/test/Sema/const-eval.c +++ b/test/Sema/const-eval.c @@ -121,3 +121,13 @@ EVAL_EXPR(43, varfloat && constfloat) // expected-error {{must have a constant s // // (Make sure we continue to reject this.) EVAL_EXPR(44, "x"[0]); // expected-error {{variable length array}} + +// +EVAL_EXPR(45, ((char*)-1) + 1 == 0 ? 1 : -1) +EVAL_EXPR(46, ((char*)-1) + 1 < (char*) -1 ? 1 : -1) +EVAL_EXPR(47, &x < &x + 1 ? 1 : -1) +EVAL_EXPR(48, &x != &x - 1 ? 1 : -1) +EVAL_EXPR(49, &x < &x - 100 ? 1 : -1) // expected-error {{must have a constant size}} + +extern struct Test50S Test50; +EVAL_EXPR(50, &Test50 < (struct Test50S*)((unsigned)&Test50 + 10)) // expected-error {{must have a constant size}} diff --git a/test/Sema/surpress-deprecated.c b/test/Sema/surpress-deprecated.c index 78faf22328a4..dd673b9646ea 100644 --- a/test/Sema/surpress-deprecated.c +++ b/test/Sema/surpress-deprecated.c @@ -1,4 +1,4 @@ -// RUN: %clang -fsyntax-only -Wno-deprecated-declarations -verify %s +// RUN: %clang_cc1 -fsyntax-only -Wno-deprecated-declarations -verify %s extern void OldFunction() __attribute__((deprecated)); int main (int argc, const char * argv[]) { diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 41d214a6364b..9f80e7169bb1 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -615,6 +615,10 @@ static_assert(agg1.arr[4] == 0, ""); static_assert(agg1.arr[5] == 0, ""); // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end}} static_assert(agg1.p == nullptr, ""); +static constexpr const unsigned char uc[] = { "foo" }; +static_assert(uc[0] == 'f', ""); +static_assert(uc[3] == 0, ""); + namespace SimpleDerivedClass { struct B { diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp index 47589135c9d5..82a9dc8042c4 100644 --- a/test/SemaCXX/cxx98-compat.cpp +++ b/test/SemaCXX/cxx98-compat.cpp @@ -114,12 +114,16 @@ bool no_except_expr = noexcept(1 + 1); // expected-warning {{noexcept expression void *null = nullptr; // expected-warning {{'nullptr' is incompatible with C++98}} static_assert(true, "!"); // expected-warning {{static_assert declarations are incompatible with C++98}} +// FIXME: Reintroduce this test if support for inheriting constructors is +// implemented. +#if 0 struct InhCtorBase { InhCtorBase(int); }; struct InhCtorDerived : InhCtorBase { - using InhCtorBase::InhCtorBase; // expected-warning {{inherited constructors are incompatible with C++98}} + using InhCtorBase::InhCtorBase; // xpected-warning {{inheriting constructors are incompatible with C++98}} }; +#endif struct FriendMember { static void MemberFn(); diff --git a/test/SemaCXX/dependent-noexcept-unevaluated.cpp b/test/SemaCXX/dependent-noexcept-unevaluated.cpp index 8066b859f189..fad8d0918d53 100644 --- a/test/SemaCXX/dependent-noexcept-unevaluated.cpp +++ b/test/SemaCXX/dependent-noexcept-unevaluated.cpp @@ -23,7 +23,7 @@ struct array { T data[N]; - void swap(array& a) noexcept(noexcept(swap(declval(), declval()))); + void swap(array& a) noexcept(noexcept(::swap(declval(), declval()))); }; struct DefaultOnly diff --git a/test/SemaCXX/implicit-exception-spec.cpp b/test/SemaCXX/implicit-exception-spec.cpp index 786e8f4a148e..143d9f7cc877 100644 --- a/test/SemaCXX/implicit-exception-spec.cpp +++ b/test/SemaCXX/implicit-exception-spec.cpp @@ -39,20 +39,14 @@ namespace InClassInitializers { bool z = noexcept(Nested::Inner()); } -// FIXME: -// The same problem arises in delayed parsing of exception specifications, -// which clang does not yet support. namespace ExceptionSpecification { - struct Nested { // expected-note {{not complete}} + struct Nested { struct T { - T() noexcept(!noexcept(Nested())); // expected-error {{incomplete type}} + T() noexcept(!noexcept(Nested())); // expected-error{{exception specification is not available until end of class definition}} } t; }; } -// FIXME: -// The same problem arises in delayed parsing of default arguments, -// which clang does not yet support. namespace DefaultArgument { struct Default { struct T { diff --git a/test/SemaCXX/warn-everthing.cpp b/test/SemaCXX/warn-everthing.cpp index 144a8f90df22..ad3dd8a24d88 100644 --- a/test/SemaCXX/warn-everthing.cpp +++ b/test/SemaCXX/warn-everthing.cpp @@ -1,4 +1,4 @@ -// RUN: %clang -Weverything -fsyntax-only %s -verify +// RUN: %clang_cc1 -Weverything -fsyntax-only %s -verify // This previously crashed due to a bug in the CFG. Exercising all // warnings helps check CFG construction. @@ -8,6 +8,6 @@ class PR12271 { ~PR12271(); }; -void testPR12271() { - PR12271 a[1][1]; -} \ No newline at end of file +void testPR12271() { // expected-warning {{no previous prototype for function 'testPR12271'}} + PR12271 a[1][1]; // expected-warning {{unused variable 'a'}} +} diff --git a/test/SemaCXX/warn-thread-safety-parsing.cpp b/test/SemaCXX/warn-thread-safety-parsing.cpp index 587cb8a4c729..c2fa1d77a01a 100644 --- a/test/SemaCXX/warn-thread-safety-parsing.cpp +++ b/test/SemaCXX/warn-thread-safety-parsing.cpp @@ -1255,7 +1255,7 @@ class FooLate { void foo4(FooLate *f) __attribute__((exclusive_locks_required(f->mu))); static void foo5() __attribute__((exclusive_locks_required(mu))); // \ - // expected-error {{invalid use of member 'mu' in static member function}} + // expected-error {{'this' cannot be implicitly used in a static member function declaration}} template void foo6() __attribute__((exclusive_locks_required(T::statmu))) { } diff --git a/test/SemaObjC/error-implicit-property.m b/test/SemaObjC/error-implicit-property.m new file mode 100644 index 000000000000..ea0587a7449a --- /dev/null +++ b/test/SemaObjC/error-implicit-property.m @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -verify %s +// rdar://11273060 + +@interface I +- (void) setP : (int)arg; +@end + +@interface J + - (int) P; +@end + +@interface K @end + +@interface II @end + +@implementation II +- (void) Meth : (I*) arg { + arg.P++; // expected-error {{no getter method 'P' for increment of property}} + --arg.P; // expected-error {{no getter method 'P' for decrement of property}} +} +- (void) Meth1 : (J*) arg { + arg.P++; // expected-error {{no setter method 'setP:' for increment of property}} + arg.P--; // expected-error {{no setter method 'setP:' for decrement of property}} +} + +- (void) Meth2 : (K*) arg { + arg.P++; // expected-error {{property 'P' not found on object of type 'K *'}} + arg.P--; // expected-error {{property 'P' not found on object of type 'K *'}} +} +@end diff --git a/test/SemaObjC/objc-literal-nsnumber.m b/test/SemaObjC/objc-literal-nsnumber.m index 449bfff4d964..6635bea72e7f 100644 --- a/test/SemaObjC/objc-literal-nsnumber.m +++ b/test/SemaObjC/objc-literal-nsnumber.m @@ -78,8 +78,8 @@ NSDictionary * warn() { } // rdar:// 11231426 -typedef float BOOL; // expected-note {{previous declaration is here}} +typedef float BOOL; BOOL radar11231426() { - return __objc_yes; // expected-warning {{BOOL of type 'float' is non-intergal and unsuitable for a boolean literal - ignored}} + return __objc_yes; } diff --git a/test/SemaObjCXX/literals.mm b/test/SemaObjCXX/literals.mm index eed67652d2ab..6cdd207d57d1 100644 --- a/test/SemaObjCXX/literals.mm +++ b/test/SemaObjCXX/literals.mm @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x -fblocks %s // rdar://11231426 -typedef bool BOOL; +typedef signed char BOOL; void y(BOOL (^foo)()); diff --git a/test/SemaObjCXX/property-reference.mm b/test/SemaObjCXX/property-reference.mm index 18f06045a340..b86ae5e9f51d 100644 --- a/test/SemaObjCXX/property-reference.mm +++ b/test/SemaObjCXX/property-reference.mm @@ -42,3 +42,18 @@ typedef const TCPPObject& CREF_TCPPObject; cppObjectNonAtomic = cppObject; } @end + + +// +@interface NSObject ++ alloc; +- init; +- class; +@end + +template void f() { + NSObject *o = [NSObject.alloc init]; + [o class]; +} + +template void f(); diff --git a/test/SemaTemplate/default-expr-arguments.cpp b/test/SemaTemplate/default-expr-arguments.cpp index 5d301be2fb13..1eefa9f8956b 100644 --- a/test/SemaTemplate/default-expr-arguments.cpp +++ b/test/SemaTemplate/default-expr-arguments.cpp @@ -292,3 +292,14 @@ namespace PR8401 { f(); } } + +namespace PR12581 { + const int a = 0; + template < typename > struct A; + template < typename MatrixType, int = + A < MatrixType >::Flags ? : A < MatrixType >::Flags & a > class B; + void + fn1 () + { + } +} diff --git a/test/SemaTemplate/dependent-names.cpp b/test/SemaTemplate/dependent-names.cpp index 36e1ad8f17f0..924bad9257b9 100644 --- a/test/SemaTemplate/dependent-names.cpp +++ b/test/SemaTemplate/dependent-names.cpp @@ -292,3 +292,35 @@ namespace PR10187 { template void f(); // expected-note {{here}} } } + +namespace rdar11242625 { + +template +struct Main { + struct default_names { + typedef int id; + }; + + template + struct TS { + T2 q; + }; +}; + +struct Sub : public Main { + TS<> ff; +}; + +int arr[sizeof(Sub)]; + +} + +namespace PR11421 { +template < unsigned > struct X { + static const unsigned dimension = 3; + template + struct Y: Y { }; // expected-error {{incomplete type}} expected-note {{is not complete until the closing}} +}; +typedef X<3> X3; +X3::Y<>::iterator it; // expected-note {{requested here}} +} diff --git a/test/SemaTemplate/instantiate-declref.cpp b/test/SemaTemplate/instantiate-declref.cpp index ced56dfc6abc..7d4a2ff6a3ff 100644 --- a/test/SemaTemplate/instantiate-declref.cpp +++ b/test/SemaTemplate/instantiate-declref.cpp @@ -105,3 +105,13 @@ namespace test1 { } template void f(int const &); // expected-note {{requested here}} } + +namespace test2 { + template void f() { + T::error; // expected-error {{no member}} + } + void g() { + // This counts as an odr-use, so should trigger the instantiation of f. + (void)&f; // expected-note {{here}} + } +} diff --git a/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp b/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp new file mode 100644 index 000000000000..8a6f9efa68ec --- /dev/null +++ b/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp @@ -0,0 +1,133 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -ftemplate-depth 16 -fcxx-exceptions -fexceptions %s + +// DR1330: an exception specification for a function template is only +// instantiated when it is needed. + +template void f1(T*) throw(T); // expected-error{{incomplete type 'Incomplete' is not allowed in exception specification}} +struct Incomplete; // expected-note{{forward}} + +void test_f1(Incomplete *incomplete_p, int *int_p) { + f1(int_p); + f1(incomplete_p); // expected-note{{instantiation of exception spec}} +} + +template struct A { + template struct B { + static void f() noexcept(A().n); + }; + + constexpr A() : n(true) {} + bool n; +}; + +static_assert(noexcept(A::B::f()), ""); + +template struct S { + static void recurse() noexcept(noexcept(S::recurse())); // \ + // expected-error {{no member named 'recurse'}} \ + // expected-note 9{{instantiation of exception spec}} +}; +decltype(S<0>::recurse()) *pVoid1 = 0; // ok, exception spec not needed +decltype(&S<0>::recurse) pFn = 0; // ok, exception spec not needed + +template<> struct S<10> {}; +void (*pFn2)() noexcept = &S<0>::recurse; // expected-note {{instantiation of exception spec}} expected-error {{not superset}} + + +template T go(T a) noexcept(noexcept(go(a))); // \ +// expected-error 16{{call to function 'go' that is neither visible}} \ +// expected-note 16{{'go' should be declared prior to the call site}} \ +// expected-error {{recursive template instantiation exceeded maximum depth of 16}} \ +// expected-error {{use of undeclared identifier 'go'}} \ + +void f() { + int k = go(0); // \ + // expected-note {{in instantiation of exception specification for 'go' requested here}} +} + + +namespace dr1330_example { + template struct A { + void f(...) throw (typename T::X); // expected-error {{'int'}} + void f(int); + }; + + int main() { + A().f(42); + } + + int test2() { + struct S { + template + static int f() noexcept(noexcept(A().f("boo!"))) { return 0; } // \ + // expected-note {{instantiation of exception spec}} + typedef decltype(f()) X; + }; + S().f(); // ok + S().f(); // expected-note {{instantiation of exception spec}} + } +} + +namespace core_19754_example { + template T declval() noexcept; + + template()))> + struct is_movable { static const bool value = true; }; + + template + struct wrap { + T val; + void irrelevant(wrap &p) noexcept(is_movable::value); + }; + + template + struct base { + base() {} + base(const typename T::type1 &); + base(const typename T::type2 &); + }; + + template + struct type1 { + wrap base; + }; + + template + struct type2 { + wrap base; + }; + + struct types { + typedef base base; + typedef type1 type1; + typedef type2 type2; + }; + + base val = base(); +} + +namespace pr9485 { + template void f1(T) throw(typename T::exception); // expected-note {{candidate}} + template void f1(T, int = 0) throw(typename T::noitpecxe); // expected-note {{candidate}} + + template void f2(T) noexcept(T::throws); // expected-note {{candidate}} + template void f2(T, int = 0) noexcept(T::sworht); // expected-note {{candidate}} + + void test() { + f1(0); // expected-error {{ambiguous}} + f2(0); // expected-error {{ambiguous}} + } +} + +struct Exc1 { char c[4]; }; +struct Exc2 { double x, y, z; }; +struct Base { + virtual void f() noexcept; // expected-note {{overridden}} +}; +template struct Derived : Base { + void f() noexcept (sizeof(T) == 4); // expected-error {{is more lax}} + void g() noexcept (T::error); +}; + +Derived d1; // ok +Derived d2; // expected-note {{in instantiation of}} diff --git a/test/Tooling/clang-check-args.cpp b/test/Tooling/clang-check-args.cpp new file mode 100644 index 000000000000..a14fc7bcd647 --- /dev/null +++ b/test/Tooling/clang-check-args.cpp @@ -0,0 +1,8 @@ +// RUN: clang-check . "%s" -- -c 2>&1 | FileCheck %s + +// CHECK: C++ requires +invalid; + +// FIXME: JSON doesn't like path separator '\', on Win32 hosts. +// FIXME: clang-check doesn't like gcc driver on cygming. +// XFAIL: cygwin,mingw32,win32 diff --git a/tools/arcmt-test/Makefile b/tools/arcmt-test/Makefile index f5ca81a6d117..57cd57482bf7 100644 --- a/tools/arcmt-test/Makefile +++ b/tools/arcmt-test/Makefile @@ -17,7 +17,7 @@ TOOL_NO_EXPORTS = 1 NO_INSTALL = 1 LINK_COMPONENTS := support mc -USEDLIBS = clangIndex.a clangARCMigrate.a clangRewrite.a \ +USEDLIBS = clangARCMigrate.a clangRewrite.a \ clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \ clangSema.a clangEdit.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a diff --git a/tools/c-arcmt-test/Makefile b/tools/c-arcmt-test/Makefile index 878eb6f4ce2d..818f648872d1 100644 --- a/tools/c-arcmt-test/Makefile +++ b/tools/c-arcmt-test/Makefile @@ -17,7 +17,7 @@ TOOL_NO_EXPORTS = 1 NO_INSTALL = 1 LINK_COMPONENTS := support mc -USEDLIBS = clang.a clangIndex.a clangARCMigrate.a clangRewrite.a \ +USEDLIBS = clang.a clangARCMigrate.a clangRewrite.a \ clangFrontend.a clangDriver.a \ clangSerialization.a clangParse.a clangSema.a \ clangAnalysis.a clangEdit.a clangAST.a clangLex.a clangBasic.a diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile index 95a961f6611e..03519b3823c0 100644 --- a/tools/c-index-test/Makefile +++ b/tools/c-index-test/Makefile @@ -18,7 +18,7 @@ INTERNAL_TOOL = 1 TOOL_NO_EXPORTS = 1 LINK_COMPONENTS := support mc -USEDLIBS = clang.a clangIndex.a clangFrontend.a clangDriver.a \ +USEDLIBS = clang.a clangFrontend.a clangDriver.a \ clangSerialization.a clangParse.a clangSema.a \ clangAnalysis.a clangEdit.a clangAST.a clangLex.a clangBasic.a diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 573e6dc3141f..eb2a4063e760 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -2243,6 +2243,7 @@ int perform_token_annotation(int argc, const char **argv) { clang_getSpellingLocation(clang_getRangeEnd(extent), 0, &end_line, &end_column, 0); printf("%s: \"%s\" ", kind, clang_getCString(spelling)); + clang_disposeString(spelling); PrintExtent(stdout, start_line, start_column, end_line, end_column); if (!clang_isInvalid(cursors[i].kind)) { printf(" "); diff --git a/tools/clang-check/ClangCheck.cpp b/tools/clang-check/ClangCheck.cpp index b5b6bd5a14ae..d68e282949c8 100644 --- a/tools/clang-check/ClangCheck.cpp +++ b/tools/clang-check/ClangCheck.cpp @@ -50,13 +50,17 @@ cl::list SourcePaths( cl::desc(" [... ]"), cl::OneOrMore); -int main(int argc, char **argv) { - cl::ParseCommandLineOptions(argc, argv); - std::string ErrorMessage; +int main(int argc, const char **argv) { llvm::OwningPtr Compilations( - CompilationDatabase::loadFromDirectory(BuildPath, ErrorMessage)); - if (!Compilations) - llvm::report_fatal_error(ErrorMessage); + FixedCompilationDatabase::loadFromCommandLine(argc, argv)); + cl::ParseCommandLineOptions(argc, argv); + if (!Compilations) { + std::string ErrorMessage; + Compilations.reset(CompilationDatabase::loadFromDirectory(BuildPath, + ErrorMessage)); + if (!Compilations) + llvm::report_fatal_error(ErrorMessage); + } ClangTool Tool(*Compilations, SourcePaths); return Tool.run(newFrontendActionFactory()); } diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index c4c864bdbf5b..ae49ac1eeb68 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -7,7 +7,6 @@ set( LLVM_USED_LIBS clangDriver clangEdit clangFrontend - clangIndex clangLex clangParse clangEdit diff --git a/tools/driver/Makefile b/tools/driver/Makefile index d828f6786830..270d4fdda863 100644 --- a/tools/driver/Makefile +++ b/tools/driver/Makefile @@ -35,7 +35,7 @@ USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \ clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \ clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \ clangStaticAnalyzerCore.a \ - clangAnalysis.a clangIndex.a clangARCMigrate.a clangRewrite.a \ + clangAnalysis.a clangARCMigrate.a clangRewrite.a \ clangEdit.a clangAST.a clangLex.a clangBasic.a include $(CLANG_LEVEL)/Makefile diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index ece91ce20e83..605cc8bdee26 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -3196,6 +3196,18 @@ CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C, } } + if (C.kind == CXCursor_ObjCCategoryDecl || + C.kind == CXCursor_ObjCCategoryImplDecl) { + if (pieceIndex > 0) + return clang_getNullRange(); + if (ObjCCategoryDecl * + CD = dyn_cast_or_null(getCursorDecl(C))) + return cxloc::translateSourceRange(Ctx, CD->getCategoryNameLoc()); + if (ObjCCategoryImplDecl * + CID = dyn_cast_or_null(getCursorDecl(C))) + return cxloc::translateSourceRange(Ctx, CID->getCategoryNameLoc()); + } + // FIXME: A CXCursor_InclusionDirective should give the location of the // filename, but we don't keep track of this. @@ -3620,9 +3632,29 @@ static enum CXChildVisitResult GetCursorVisitor(CXCursor cursor, if (clang_isDeclaration(cursor.kind)) { // Avoid having the implicit methods override the property decls. - if (ObjCMethodDecl *MD = dyn_cast_or_null(getCursorDecl(cursor))) + if (ObjCMethodDecl *MD + = dyn_cast_or_null(getCursorDecl(cursor))) { if (MD->isImplicit()) return CXChildVisit_Break; + + } else if (ObjCInterfaceDecl *ID + = dyn_cast_or_null(getCursorDecl(cursor))) { + // Check that when we have multiple @class references in the same line, + // that later ones do not override the previous ones. + // If we have: + // @class Foo, Bar; + // source ranges for both start at '@', so 'Bar' will end up overriding + // 'Foo' even though the cursor location was at 'Foo'. + if (BestCursor->kind == CXCursor_ObjCInterfaceDecl || + BestCursor->kind == CXCursor_ObjCClassRef) + if (ObjCInterfaceDecl *PrevID + = dyn_cast_or_null(getCursorDecl(*BestCursor))){ + if (PrevID != ID && + !PrevID->isThisDeclarationADefinition() && + !ID->isThisDeclarationADefinition()) + return CXChildVisit_Break; + } + } } if (clang_isExpression(cursor.kind) && diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt index 66a1710bac14..fb0b91f00d75 100644 --- a/tools/libclang/CMakeLists.txt +++ b/tools/libclang/CMakeLists.txt @@ -4,7 +4,6 @@ set(LLVM_USED_LIBS clangFrontend clangDriver clangSerialization - clangIndex clangSema clangEdit clangAST diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index d84cf29098fe..a29875956243 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -247,19 +247,23 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU, case Stmt::CompoundStmtClass: K = CXCursor_CompoundStmt; break; - + case Stmt::NullStmtClass: K = CXCursor_NullStmt; break; - + case Stmt::LabelStmtClass: K = CXCursor_LabelStmt; break; - + + case Stmt::AttributedStmtClass: + K = CXCursor_UnexposedStmt; + break; + case Stmt::DeclStmtClass: K = CXCursor_DeclStmt; break; - + case Stmt::IntegerLiteralClass: K = CXCursor_IntegerLiteral; break; @@ -287,7 +291,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU, case Stmt::UnaryOperatorClass: K = CXCursor_UnaryOperator; break; - + case Stmt::CXXNoexceptExprClass: K = CXCursor_UnaryExpr; break; diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile index 1fff166bbf8f..08bf3c62e6b4 100644 --- a/tools/libclang/Makefile +++ b/tools/libclang/Makefile @@ -23,6 +23,11 @@ USEDLIBS = clangARCMigrate.a clangRewrite.a clangFrontend.a clangDriver.a \ include $(CLANG_LEVEL)/Makefile +# Add soname to the library. +ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU)) + LDFLAGS += -Wl,-soname,lib$(LIBRARYNAME)$(SHLIBEXT) +endif + ##===----------------------------------------------------------------------===## # FIXME: This is copied from the 'lto' makefile. Should we share this? ##===----------------------------------------------------------------------===## diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer index 32a7301362f6..d01bd0fa45aa 100755 --- a/tools/scan-build/ccc-analyzer +++ b/tools/scan-build/ccc-analyzer @@ -387,6 +387,8 @@ my %LangMap = ( 'c' => 'c', 'cp' => 'c++', 'cpp' => 'c++', + 'cxx' => 'c++', + 'txx' => 'c++', 'cc' => 'c++', 'ii' => 'c++', 'i' => 'c-cpp-output', diff --git a/unittests/Frontend/Makefile b/unittests/Frontend/Makefile index 7c282d6b47f1..f3e639665849 100644 --- a/unittests/Frontend/Makefile +++ b/unittests/Frontend/Makefile @@ -13,7 +13,7 @@ LINK_COMPONENTS := support mc USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \ clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \ clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \ - clangIndex.a clangARCMigrate.a clangRewrite.a clangEdit.a \ + clangARCMigrate.a clangRewrite.a clangEdit.a \ clangAnalysis.a clangAST.a clangLex.a clangBasic.a include $(CLANG_LEVEL)/unittests/Makefile diff --git a/unittests/Tooling/CompilationDatabaseTest.cpp b/unittests/Tooling/CompilationDatabaseTest.cpp index 9747de25548c..68d2896f1212 100644 --- a/unittests/Tooling/CompilationDatabaseTest.cpp +++ b/unittests/Tooling/CompilationDatabaseTest.cpp @@ -219,5 +219,74 @@ TEST(unescapeJsonCommandLine, ParsesQuotedStringWithoutClosingQuote) { EXPECT_EQ("", Empty[0]); } +TEST(FixedCompilationDatabase, ReturnsFixedCommandLine) { + std::vector CommandLine; + CommandLine.push_back("one"); + CommandLine.push_back("two"); + FixedCompilationDatabase Database(".", CommandLine); + std::vector Result = + Database.getCompileCommands("source"); + ASSERT_EQ(1ul, Result.size()); + std::vector ExpectedCommandLine(1, "clang-tool"); + ExpectedCommandLine.insert(ExpectedCommandLine.end(), + CommandLine.begin(), CommandLine.end()); + ExpectedCommandLine.push_back("source"); + EXPECT_EQ(".", Result[0].Directory); + EXPECT_EQ(ExpectedCommandLine, Result[0].CommandLine); +} + +TEST(ParseFixedCompilationDatabase, ReturnsNullOnEmptyArgumentList) { + int Argc = 0; + llvm::OwningPtr Database( + FixedCompilationDatabase::loadFromCommandLine(Argc, NULL)); + EXPECT_FALSE(Database); + EXPECT_EQ(0, Argc); +} + +TEST(ParseFixedCompilationDatabase, ReturnsNullWithoutDoubleDash) { + int Argc = 2; + const char *Argv[] = { "1", "2" }; + llvm::OwningPtr Database( + FixedCompilationDatabase::loadFromCommandLine(Argc, Argv)); + EXPECT_FALSE(Database); + EXPECT_EQ(2, Argc); +} + +TEST(ParseFixedCompilationDatabase, ReturnsArgumentsAfterDoubleDash) { + int Argc = 5; + const char *Argv[] = { "1", "2", "--\0no-constant-folding", "3", "4" }; + llvm::OwningPtr Database( + FixedCompilationDatabase::loadFromCommandLine(Argc, Argv)); + ASSERT_TRUE(Database); + std::vector Result = + Database->getCompileCommands("source"); + ASSERT_EQ(1ul, Result.size()); + ASSERT_EQ(".", Result[0].Directory); + std::vector CommandLine; + CommandLine.push_back("clang-tool"); + CommandLine.push_back("3"); + CommandLine.push_back("4"); + CommandLine.push_back("source"); + ASSERT_EQ(CommandLine, Result[0].CommandLine); + EXPECT_EQ(2, Argc); +} + +TEST(ParseFixedCompilationDatabase, ReturnsEmptyCommandLine) { + int Argc = 3; + const char *Argv[] = { "1", "2", "--\0no-constant-folding" }; + llvm::OwningPtr Database( + FixedCompilationDatabase::loadFromCommandLine(Argc, Argv)); + ASSERT_TRUE(Database); + std::vector Result = + Database->getCompileCommands("source"); + ASSERT_EQ(1ul, Result.size()); + ASSERT_EQ(".", Result[0].Directory); + std::vector CommandLine; + CommandLine.push_back("clang-tool"); + CommandLine.push_back("source"); + ASSERT_EQ(CommandLine, Result[0].CommandLine); + EXPECT_EQ(2, Argc); +} + } // end namespace tooling } // end namespace clang diff --git a/www/cxx_status.html b/www/cxx_status.html index 1b7d8140a252..3ee6b7231751 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -23,7 +23,7 @@

C++98 and C++11 Support in Clang

-

Last updated: $Date: 2012-04-13 03:02:19 +0200 (Fri, 13 Apr 2012) $

+

Last updated: $Date: 2012-04-17 03:04:22 +0200 (Tue, 17 Apr 2012) $

C++98 implementation status

@@ -40,8 +40,9 @@

You can use Clang in C++11 mode either with libc++ or with gcc's libstdc++. -libstdc++-4.4 requires a patch to work -with clang; other versions have not been tested.

+Patches are needed to make libstdc++-4.4 +and libstdc++-4.7 work with Clang in +C++11 mode.

diff --git a/www/hacking.html b/www/hacking.html index 2c11ce1896d2..aa13b8d0eb89 100644 --- a/www/hacking.html +++ b/www/hacking.html @@ -211,8 +211,16 @@

Testing on the Command Line

-

To run all the tests from the command line, execute a command like - the following:

+

If you want more control over how the tests are run, it may + be convenient to run the test harness on the command-line directly. Before + running tests from the command line, you will need to ensure that + lit.site.cfg files have been created for your build. You can do + this by running the tests as described in the previous sections. Once the + tests have started running, you can stop them with control+C, as the + files are generated before running any tests.

+ +

Once that is done, to run all the tests from the command line, + execute a command like the following:

   python (path to llvm)\llvm\utils\lit\lit.py -sv
diff --git a/www/libstdc++4.7-clang11.patch b/www/libstdc++4.7-clang11.patch
new file mode 100644
index 000000000000..3f0300725df3
--- /dev/null
+++ b/www/libstdc++4.7-clang11.patch
@@ -0,0 +1,13 @@
+Index: include/std/type_traits
+===================================================================
+--- include/std/type_traits	(revision 185724)
++++ include/std/type_traits	(working copy)
+@@ -1746,7 +1746,7 @@
+ 
+   template
+     struct common_type<_Tp, _Up>
+-    { typedef decltype(true ? declval<_Tp>() : declval<_Up>()) type; };
++    { typedef typename decay() : declval<_Up>())>::type type; };
+ 
+   template
+     struct common_type<_Tp, _Up, _Vp...>